`

2011.06.20——— android listview的拖拽

阅读更多
2011.06.20——— android listview的拖拽


参考:http://www.cnblogs.com/qianxudetianxia/archive/2011/06/12/2068761.html


主要看上面那个链接 作者写的非常详细 在此谢过了



可拖拽的listview:

package com.fengjian.test;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.Toast;

import com.fengjian.test.DragListActivity.DragListAdapter;

/**
 * http://www.cnblogs.com/qianxudetianxia/archive/2011/06/12/2068761.html
 * @author li
 *
 */
public class DragListView extends ListView {
    
    private ImageView dragImageView;//被拖拽的项,其实就是一个ImageView
    private int dragSrcPosition;//手指拖动项原始在列表中的位置
    private int dragPosition;//手指拖动的时候,当前拖动项在列表中的位置
    
    private int dragPoint;//在当前数据项中的位置
    private int dragOffset;//当前视图和屏幕的距离(这里只使用了y方向上)
    
    private WindowManager windowManager;//windows窗口控制类
    private WindowManager.LayoutParams windowParams;//用于控制拖拽项的显示的参数
    
    private int scaledTouchSlop;//判断滑动的一个距离
    private int upScrollBounce;//拖动的时候,开始向上滚动的边界
    private int downScrollBounce;//拖动的时候,开始向下滚动的边界
    
    public DragListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        scaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
    }
    
    //拦截touch事件,其实就是加一层控制
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if(ev.getAction()==MotionEvent.ACTION_DOWN){
            int x = (int)ev.getX();
            int y = (int)ev.getY();
            System.out.println("x: "+ x +" y: "+ y +" RawX: "+ev.getRawX()+" RawY: "+ev.getRawY());
            dragSrcPosition = dragPosition = pointToPosition(x, y);//判断当前xy值 是否在item上 如果在 返回改item的position 否则 返回 INVALID_POSITION(-1)
            System.out.println("super.onInterceptTouchEvent(ev): "+super.onInterceptTouchEvent(ev));
            if(dragPosition==AdapterView.INVALID_POSITION){
                return super.onInterceptTouchEvent(ev);
            }
            System.out.println("dragPosition: "+dragSrcPosition +" getFirstVisiblePosition(): "+getFirstVisiblePosition());
            
          //getChildAt(int position)参数 为当前屏幕里面显示的item 从0开始 并不是adapter里面的位置 如果当前屏幕显示的微list从 5--8 的数据 则
          //getChildAt(0) 为在list中position为5的那个item
          //getFirstVisiblePosition()返回第一个显示在界面的view在adapter的位置position,可能是0,也可能是4

            ViewGroup itemView = (ViewGroup) getChildAt(dragPosition-getFirstVisiblePosition());
            System.out.println("itemView.getTop(): " + itemView.getTop());
            dragPoint = y - itemView.getTop();
            // lipeng add 
            //dragPoint = itemView.getTop();
            dragOffset = (int) (ev.getRawY() - y);
            
            View dragger = itemView.findViewById(R.id.drag_list_item_image);
            if(dragger!=null&&x>dragger.getLeft()-20){
                //
                upScrollBounce = Math.min(y-scaledTouchSlop, getHeight()/3);
                downScrollBounce = Math.max(y+scaledTouchSlop, getHeight()*2/3);
                
                itemView.setDrawingCacheEnabled(true);
                Bitmap bm = Bitmap.createBitmap(itemView.getDrawingCache());
                startDrag(bm, y);
            }
            return false;
         }
         return super.onInterceptTouchEvent(ev);
    }

    /**
     * 触摸事件
     */
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        if(dragImageView!=null&&dragPosition!=INVALID_POSITION){
            int action = ev.getAction();
            switch(action){
                case MotionEvent.ACTION_UP:
                    int upY = (int)ev.getY();
                    stopDrag();
                    onDrop(upY);
                    break;
                case MotionEvent.ACTION_MOVE:
                    int moveY = (int)ev.getY();
                    //onDrag(moveY);
                    // lipeng add
                    onDrag(moveY,(int)ev.getRawY());
                    break;
                default:break;
            }
            return true;
        }
        //也决定了选中的效果
        return super.onTouchEvent(ev);
    }
    
    /**
     * 准备拖动,初始化拖动项的图像
     * @param bm
     * @param y
     */
    public void startDrag(Bitmap bm ,int y){
        stopDrag();
        
        windowParams = new WindowManager.LayoutParams();
        windowParams.gravity = Gravity.TOP;
        windowParams.x = 0;
        
        windowParams.y = y - dragPoint + dragOffset;
        
        //windowParams.y = dragPoint + 50;// lipeng add  
        windowParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
        windowParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
        windowParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                            | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
                            | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
                            | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
        windowParams.format = PixelFormat.TRANSLUCENT;
        windowParams.windowAnimations = 0;

        ImageView imageView = new ImageView(getContext());
        imageView.setImageBitmap(bm);
        windowManager = (WindowManager)getContext().getSystemService("window");
        windowManager.addView(imageView, windowParams);
        dragImageView = imageView;
    }
    
    /**
     * 停止拖动,去除拖动项的头像
     */
    public void stopDrag(){
        if(dragImageView!=null){
            windowManager.removeView(dragImageView);
            dragImageView = null;
        }
    }
    
    /**
     * 拖动执行,在Move方法中执行
     * @param y
     */
    public void onDrag(int y){
        if(dragImageView!=null){
            windowParams.alpha = 0.8f;
            windowParams.y = y - dragPoint + dragOffset;
            windowManager.updateViewLayout(dragImageView, windowParams);
        }
        //为了避免滑动到分割线的时候,返回-1的问题
        int tempPosition = pointToPosition(0, y);
        if(tempPosition!=INVALID_POSITION){
            dragPosition = tempPosition;
        }
        
        //滚动
        int scrollHeight = 0;
        if(y<upScrollBounce){
            scrollHeight = 8;//定义向上滚动8个像素,如果可以向上滚动的话
        }else if(y>downScrollBounce){
            scrollHeight = -8;//定义向下滚动8个像素,,如果可以向上滚动的话
        }
        
        if(scrollHeight!=0){
            //真正滚动的方法setSelectionFromTop()
            setSelectionFromTop(dragPosition, getChildAt(dragPosition-getFirstVisiblePosition()).getTop()+scrollHeight);
        }
    }
    
    // lipeng add {
    /**
     * 拖动执行,在Move方法中执行
     * @param y
     */
    public void onDrag(int y,int rawY){
        if(dragImageView!=null){
            windowParams.alpha = 0.8f;
            //windowParams.y = y - dragPoint + dragOffset;
            windowParams.y = rawY-dragPoint;
            windowManager.updateViewLayout(dragImageView, windowParams);
        }
        //为了避免滑动到分割线的时候,返回-1的问题
        int tempPosition = pointToPosition(0, y);
        if(tempPosition!=INVALID_POSITION){
            dragPosition = tempPosition;
        }
        
        //滚动
        int scrollHeight = 0;
        if(y<upScrollBounce){
            scrollHeight = 8;//定义向上滚动8个像素,如果可以向上滚动的话
        }else if(y>downScrollBounce){
            scrollHeight = -8;//定义向下滚动8个像素,,如果可以向上滚动的话
        }
        
        if(scrollHeight!=0){
            //真正滚动的方法setSelectionFromTop()
            setSelectionFromTop(dragPosition, getChildAt(dragPosition-getFirstVisiblePosition()).getTop()+scrollHeight);
        }
    }
    // lipeng add }
    
    /**
     * 拖动放下的时候
     * @param y
     */
    public void onDrop(int y){
        
        //为了避免滑动到分割线的时候,返回-1的问题
        int tempPosition = pointToPosition(0, y);
        if(tempPosition!=INVALID_POSITION){
            dragPosition = tempPosition;
        }
        
        //超出边界处理
        if(y<getChildAt(1).getTop()){
            //超出上边界
            dragPosition = 1;
        }else if(y>getChildAt(getChildCount()-1).getBottom()){
            //超出下边界
            dragPosition = getAdapter().getCount()-1;
        }
        
        //数据交换
        if(dragPosition>0&&dragPosition<getAdapter().getCount()){
            DragListAdapter adapter = (DragListAdapter)getAdapter();
            String dragItem = adapter.getItem(dragSrcPosition);
            adapter.remove(dragItem);
            adapter.insert(dragItem, dragPosition);
            Toast.makeText(getContext(), adapter.getList().toString(), Toast.LENGTH_SHORT).show();
        }
        
    }
}


main类:

package com.fengjian.test;

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

public class DragListActivity extends Activity {
    
    private static List<String> list = null;
    private DragListAdapter adapter = null;
    
    public static List<String> groupKey= new ArrayList<String>();
    private List<String> navList = new ArrayList<String>();
    private List<String> moreList = new ArrayList<String>();
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.drag_list_activity);
        
        initData();
        
        DragListView dragListView = (DragListView)findViewById(R.id.drag_list);
        adapter = new DragListAdapter(this, list);
        dragListView.setAdapter(adapter);
    }
    
    public void initData(){
        //数据结果
        list = new ArrayList<String>();
        
        //groupKey存放的是分组标签
        groupKey.add("A组");
        groupKey.add("B组");
        
        for(int i=0; i<5; i++){
            navList.add("A选项"+i);
        }
        list.add("A组");
        list.addAll(navList);
        
        for(int i=0; i<8; i++){
            moreList.add("B选项"+i);
        }
        list.add("B组");
        list.addAll(moreList);
    }
    
    public static class DragListAdapter extends ArrayAdapter<String>{

        public DragListAdapter(Context context, List<String> objects) {
            super(context, 0, objects);
        }
        
        public List<String> getList(){
            return list;
        }
        
        @Override
        public boolean isEnabled(int position) {
            if(groupKey.contains(getItem(position))){
                //如果是分组标签,返回false,不能选中,不能点击
                return false;
            }
            return super.isEnabled(position);
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            
            View view = convertView;
            if(groupKey.contains(getItem(position))){
                //如果是分组标签,就加载分组标签的布局文件,两个布局文件显示效果不同
                view = LayoutInflater.from(getContext()).inflate(R.layout.drag_list_item_tag, null);
            }else{
                //如果是正常数据项标签,就加在正常数据项的布局文件
                view = LayoutInflater.from(getContext()).inflate(R.layout.drag_list_item, null);
            }
            
            TextView textView = (TextView)view.findViewById(R.id.drag_list_item_text);
            textView.setText(getItem(position));
            
            return view;
        }
    }
}



drag_list_activity.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    <com.fengjian.test.DragListView 
       android:id="@+id/drag_list" 
       android:layout_width="fill_parent" 
       android:layout_height="fill_parent"
       android:cacheColorHint="#00000000"/>
</LinearLayout>


drag_list_item_tag.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:background="#555555"
    android:padding="5dip"
    android:paddingLeft="10dip">
    <TextView
       android:id="@+id/drag_list_item_text"
       android:layout_width="wrap_content"
       android:layout_height="20dip"
       android:textColor="#ffffff"
       android:gravity="center_vertical"/>
</LinearLayout>


drag_list_item.xml

<?xml version="1.0" encoding="utf-8"?>
<!-- 一定要使用相对布局 -->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content">
    <TextView
       android:id="@+id/drag_list_item_text" 
       android:layout_width="wrap_content" 
       android:layout_height="@dimen/drag_item_normal_height"
       android:paddingLeft="5dip"
       android:layout_alignParentLeft="true"
       android:layout_centerVertical="true"
       android:gravity="center_vertical"/>
    <ImageView android:id="@+id/drag_list_item_image"
       android:src="@drawable/list_icon"
       android:layout_alignParentRight="true"
       android:layout_centerVertical="true"
       android:layout_width="wrap_content"
       android:layout_height="@dimen/drag_item_normal_height"/>
</RelativeLayout>



全部代码 就是上面这些了 截张图吧。。


注意几个问题吧 :

1、pointToPosition(x, y);
判断当前xy值 是否在item上 如果在 返回改item的position 否则 返回 INVALID_POSITION(-1)

2、getChildAt(int position)
参数 为当前屏幕里面显示的item 从0开始 并不是adapter里面的位置 如果当前屏幕显示的微list从 5--8 的数据 则getChildAt(0) 为在list中position为5的那个item
3、getFirstVisiblePosition()
返回第一个显示在界面的view在adapter的位置position,可能是0,也可能是4
4、setSelectionFromTop(position,y)
第一个参数 是需要选中的item的位置,第二个是y轴上的坐标




分享到:
评论
3 楼 asialee900715 2014-04-23  
已经搞懂了!
2 楼 asialee900715 2014-04-23  
想请教楼主一个比较菜的问题,为什么要在onInterceptTouchEvent函数里去处理,直接放到onTouchEvent底下去处理action_down不可以吗
1 楼 noonnightstorm 2012-07-04  
  不错,不过感觉代码有点繁琐了,可以简化下

相关推荐

Global site tag (gtag.js) - Google Analytics