`

Android实现可拖拽的ListView

 
阅读更多

通过继承 ListView 实现可拖拽的 ListView ,先说说实现拖拽的原理吧,实现拖拽需要考虑三个问题:第一怎么确定你在拖拽 listview 里面的 item 的时候就是你手指当前选中的 item ;第二实现拖拽的效果,就是有一个浮动的层跟随你的手指在移动;第三你放开手指时怎么把你拖拽的这个 item 放到当前 listView 的位置(也就是说改变 item 的位置)。 明白了这三个问题就比较好实现了。

里面会涉及到一些比较重要的方法调用,首先是 pointToPosition(int x, int y) 这方方法 Android 官方的解释是 ” Maps a point to a position in the list” 我把它理解为通过 x y 的位置来确定这个 listView 里面这个 item 的位置。 有了这个方法就解决了第一和第三个问题了。接下来我们可以通过 WindowManager 来解决第二个问题,然后通过 pointToPosition 方法就可以获取你手指按下时的 item 这个 item 其实就是你 listview 里面的 item ,这样的就可以把这个 item 设置为是 WindowManager view ,这样的话拖动的层的效果就模拟出来了,接下来是怎么让这个 WindowManager 跟随你的手指在移动。这个时候会涉及到 WindowManager 里面的 updateViewLayout(view, layoutparams) 来刷新 WindowManager 的位置,这样就实现了 WindowManager 会跟随你的手指在移动。最后就剩下你放下手指的时候怎么让你拖拽的 item 插入到 listview 里面,这个插入的动作其实包含了移除和插 入这两个动作。这个时候你可能会问在某个位置插入这个 item 需要 ”position” ”item” 两个参数, position 我们可以通过 pointToPosition 方法来获取,然后要插入的“ item ”其实是你 adapter 里面数据。因为我们上面的一系列动作都是在 listview 里面完成的,但是在我们重写 listview 的时候是还没有给 listview 设置 adapter 是吧,这个问题的我们通过在重写 listview 的类中自定义一个接口,然后你在 activity 里面初始化 listview 数据的时候实现这个接口。接口里面只有一个方法,方法里面的两个参数一个是你开始拖拽的的 item 的位置,另一个是你拖拽移动之后之后的 item 的位置。下面我们看看效果吧:

 

 

        private final float mAlpha = 0.9f;
	//拖动的view
	private ImageView mDragView;
	private Context mContext;
	private WindowManager mWindowManager;
	private WindowManager.LayoutParams mLayoutParams;
	//开始拖动时的位置
	private int mDragStartPosition;
	//当前的位置
	private int mDragCurrentPostion;
	//在滑动的时候,手的移动要大于这个返回的距离值才开始移动控件
	private int mScaledTouchSlop;
	//当前位置距离边界的位置
	private int mDragOffsetX;
	private int mDragOffSetY;
	//移动的位置
	private int mDragPointX;
	private int mDragPointY;
	//边界
	private int mUpperBound;
        private int mLowerBound;
	private DropViewListener mDropViewListener;
	
	public DragListView(Context context) {
		super(context);
		mContext = context;
		mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
		mScaledTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
	}

	public DragListView(Context context, AttributeSet attr) {
		super(context, attr);
		mContext = context;
		mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
		mScaledTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
	}
 

 我们在onInterceptTouchEvent方法里面作初始化动作:

 

 

@Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        //ev.getX()相对于控件本身左上角,ev.getRawX()相对于容器圆点位置
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                final int x = (int) ev.getX();//相对于空间本身
                final int y = (int) ev.getY();
                final int itemNum = pointToPosition(x, y);
                if(itemNum == AdapterView.INVALID_POSITION){
                    break;
                }
                final ViewGroup item = (ViewGroup) getChildAt(itemNum - getFirstVisiblePosition());
                mDragPointX = x - item.getLeft();
                mDragPointY = y - item.getTop();
                mDragOffsetX = ((int) ev.getRawX()) - x;
                mDragOffSetY = ((int) ev.getRawY()) - y;
               
                //长按
                item.setOnLongClickListener(new OnLongClickListener() {
                    @Override
                    public boolean onLongClick(View v) {
                        //计算边界
                        final int height = getHeight();
                        mUpperBound = Math.min(y - mScaledTouchSlop, height / 3);
                        mLowerBound = Math.max(y + mScaledTouchSlop, height * 2 / 3);
                        mDragCurrentPostion = mDragStartPosition = itemNum;
                       
                        item.setDrawingCacheEnabled(true);
                        Bitmap bitmap = Bitmap.createBitmap(item.getDrawingCache());
                        startDragging(bitmap, x, y);
                        return true;
                    }
                });
                break;
        }
        return super.onInterceptTouchEvent(ev);
    }

这里面我们就记录了拖拽的当前和开始时位置mDragCurrentPostion和 mDragStartPosition,并通过startDragging来初始化mWindowManager,在startDragging方法里面调用的stopDragging方法其实是一个内存释放的过程,这个方法做的事情就是释放内存空间。

 

private void startDragging(Bitmap bitm, int x, int y){
        stopDragging();
       
        mLayoutParams = new WindowManager.LayoutParams();
        mLayoutParams.gravity = Gravity.TOP | Gravity.LEFT;
        mLayoutParams.x = x - mDragPointX + mDragOffsetX;
        mLayoutParams.y = y - mDragPointY + mDragOffSetY;
        mLayoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
        mLayoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
        mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
                | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
                | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
                | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
        mLayoutParams.format = PixelFormat.TRANSLUCENT;
        mLayoutParams.windowAnimations = 0;
       
        ImageView imageView = new ImageView(mContext);
        imageView.setImageBitmap(bitm);
        imageView.setBackgroundResource(R.drawable.tab_item_bg);
        imageView.setPadding(0, 0, 0, 0);
        mWindowManager.addView(imageView, mLayoutParams);
        mDragView = imageView;
    }

private void stopDragging(){
        if(mDragView != null){
            mWindowManager.removeView(mDragView);
            mDragView.setImageDrawable(null);
            mDragView = null;
        }
    }

我们在onInterceptTouchEvent方法记录了拖拽的开始位置和当前位置,并且初始化了windowmanager,接下来我们通过onTouchEvent方法来实现让windowmanager跟随你的手指移动

@Override
    public boolean onTouchEvent(MotionEvent ev) {
        if(mDragView != null && mDragCurrentPostion != INVALID_POSITION && mDropViewListener != null){
            switch (ev.getAction()) {
                case MotionEvent.ACTION_UP:
                    //int y = (int) ev.getY();
                    stopDragging();
                    //数据交换
                    if(mDragCurrentPostion >= 0 && mDragCurrentPostion < getCount()){
                        mDropViewListener.drop(mDragStartPosition, mDragCurrentPostion);
                    }
                    break;
                case MotionEvent.ACTION_MOVE:
                    int x = (int) ev.getX();
                    int y = (int) ev.getY();
                    dragView(x, y);
                    if (y >= getHeight() / 3) {
                        mUpperBound = getHeight() / 3;
                    }
                    if (y <= getHeight() * 2 / 3) {
                        mLowerBound = getHeight() * 2 / 3;
                    }
                     int speed = 0;
                    if (y > mLowerBound) {
                        if (getLastVisiblePosition() < getCount() - 1) {
                            speed = y > (getHeight() + mLowerBound) / 2 ? 16 : 4;
                        } else {
                            speed = 1;
                        }
                    } else if (y < mUpperBound) {
                        speed = y < mUpperBound / 2 ? -16 : -4;
                        if (getFirstVisiblePosition() == 0
                                && getChildAt(0).getTop() >= getPaddingTop()) {
                            speed = 0;
                        }
                    }
                    if (speed != 0) {
                        smoothScrollBy(speed, 30);
                    }
                    break;
            }
            return true;
        }
        return super.onTouchEvent(ev);
    }

其中dragView方法就是根据你手指移动来改变windowmanager的位置,在移动的时候我们需要考虑的另外一个问题是你的listview滚动条的时候,这个时候我们需要考虑边界,不然会抛出空指针异常。

private void dragView(int x, int y){
        if(mDragView != null){
            mLayoutParams.alpha = mAlpha;
            mLayoutParams.y = y - mDragPointY + mDragOffSetY;
            mLayoutParams.x = x - mDragPointX + mDragOffsetX;
            mWindowManager.updateViewLayout(mDragView, mLayoutParams);
        }
        int tempPosition = pointToPosition(0, y);
        if(tempPosition != INVALID_POSITION){
            mDragCurrentPostion = tempPosition;
        }
       
        //滚动
        int scrollY = 0;
        if(y < mUpperBound){
            scrollY = 8;
        }else if(y > mLowerBound){
            scrollY = -8;
        }
       
        if(scrollY != 0){
            int top = getChildAt(mDragCurrentPostion - getFirstVisiblePosition()).getTop();
            setSelectionFromTop(mDragCurrentPostion, top + scrollY);
        }
    }

 这样的话就完成了拖拽的效果,剩下的是你放开手指,然后把你拖拽的item插入到listview的列表里面,我们定义了一个接口

1 public void setDropViewListener(DropViewListener listener){
2          this .mDropViewListener = listener;
3      }
4       
5      public interface DropViewListener {
6          void drop( int from, int to);
7      }

这样的话,你在初始化listview给listView设置adapter的时候需要实现DropViewListener接口,from和to两个参数分别是你拖拽时的最初位置和你移动后的位置,这样的话你在activity里面就可以实现数据插入了。 注意:
但是如果你的这listview的item包含了复选框的话,这个时候 listview的onitemclicklistener事件就会失效,也就是说你不能通过你平时处理listview的 onitemclicklistener的方法一样处理,你也可以通过自定义接口来模拟onitemclicklistener事件

 

 

   return true;http://blog.csdn.net/chenjie19891104/article/details/7031713

 

分享到:
评论

相关推荐

    android 可拖动listview

    要实现“android可拖动listview”,我们需要关注以下几个关键知识点: 1. **Drag and Drop API**:Android系统提供了一套Drag and Drop API,用于处理拖放操作。我们需要在ListView的Item视图上添加OnTouchListener...

    android listview item 拖动排序

    这个库允许用户通过手势拖动ListView中的item,以改变它们的顺序,从而提供了一种直观且用户友好的交互体验。 首先,我们需要在项目中引入`DragSortListView`库。如果你使用的是Gradle构建系统,可以在`build....

    Android ListView 可拖拽Item 1 - 创建浮动Item

    总结来说,实现Android ListView中可拖拽Item的功能需要对触摸事件、DragEvent和Adapter有深入理解。通过自定义布局、监听器和适配器更新,我们可以创建出具有高度交互性的ListView。同时,别忘了在设计和实现过程中...

    android listview 拖拽效果

    "android listview 拖拽效果"是指在ListView上实现的一项高级功能,允许用户通过手势拖动ListView中的每个条目(item)来改变它们的位置,提供了一种直观且交互性强的用户体验。在本篇文章中,我们将深入探讨如何...

    实现android listview可拖动item

    要实现ListView的item可拖动效果,可以增强用户体验,让应用更具交互性。本文将详细介绍如何在Android中实现ListView的拖动功能。 首先,我们需要了解ListView的工作原理。ListView通过Adapter来绑定数据,并通过...

    android 可拖拽 ListView

    android的一个可拖拽ListView,是继承ListView实现的 我是在一个开源项目的基础上修改得来,原开源项目地址: https://github.com/fjtianxia/qianxudetianxia

    Android_可拖拽(拖动)换位置的ListView

    那么就自己import并add那个appcompat_v7(如果你的项目目录下有这个工程的话就添加你自己的)就正常了,其实Demo报错并不影响,关键是demo里的jar包才是可拖拽控件,你可以自己新建项目仿照demo的代码实现效果。...

    android 拖拽列表listview

    在本案例中,我们将深入探讨如何在Android中实现ListView的行拖拽功能,以及如何实现在多级列表间的行拖拽。 首先,要实现ListView的行拖拽,我们需要使用适配器(Adapter)来管理和更新ListView的数据。适配器将...

    Android ListVIew 拖动Item 删除

    拖动ListView的子项(Item)并实现删除功能是一项常见的需求,特别是在构建具有交互性较强的界面时。本篇将详细介绍如何在Android中实现在ListView中拖动并删除Item。 首先,我们需要创建一个自定义的ListView,这...

    实现可以拖动listview

    在Android开发中,ListView是一种常用的组件,用于展示可滚动的列表数据。在许多应用中,如QQ消息列表,用户可以通过拖动列表项来实现排序或删除功能,这大大提升了用户体验。"实现可以拖动的listview"就是这样一个...

    android 拖拽和删除的listview

    本篇文章将深入探讨如何在Android中实现ListView的拖拽排序和删除功能。 首先,我们要创建一个可拖动的ListView。这需要我们自定义一个Adapter,例如继承自BaseAdapter,用于填充ListView的数据。在Adapter中,我们...

    android可以横向拖动listView

    综上所述,创建一个可横向拖动的ListView需要对Android的基础知识有深入理解,包括自定义视图、事件处理、布局管理以及性能优化等。通过自定义控件或使用第三方库,我们可以实现更加丰富的交互效果,提升应用的用户...

    Android listview 拖拽实现源码

    本篇文章将深入探讨如何在Android ListView中实现拖拽功能,并基于提供的"Android listview 拖拽实现源码"进行解析。 首先,要实现ListView的拖拽功能,我们需要自定义一个适配器(Adapter),这个适配器需要继承自...

    可拖拽 listview

    总的来说,实现一个可拖拽的listview涉及了Android UI组件的编程、触摸事件处理、数据结构操作以及动画效果的添加。熟练掌握这些知识点,不仅能够提升应用的用户体验,也为开发者提供了更多创新设计的可能性。

    android ListView和GridView拖拽移位实现代码

    本文将深入探讨如何在Android中实现ListView和GridView的拖拽移位功能,这在构建可交互的应用界面时非常有用,比如在音乐播放器、文件管理器等场景。 首先,我们需要了解ListView和GridView的基本用法。ListView...

    Android 可拖拽排序的ListView

    Android 可拖拽排序的ListView

    Android应用源码ListView 中的item随意拖动.zip

    在“Android应用源码ListView 中的item随意拖动.zip”这个压缩包中,包含的源码示例是关于如何实现ListView的item(列表项)的自由拖动功能。这种功能常用于创建具有高度交互性的应用,如待办事项列表、音乐播放器或...

    可拖动listview

    本篇将详细介绍如何在Android中实现一个可拖动的ListView,以及如何实现拖动分组管理。 首先,我们要了解Android中的Drag and Drop API,这是实现拖动功能的基础。Android SDK提供了一套完整的Drag and Drop API,...

    Android luncher拖动效果+listview下拉加载

    在Android开发中,"Android launcher拖动效果"和"listview下拉加载"是两个重要的功能模块,它们分别涉及到用户界面交互和数据加载优化。让我们深入探讨这些知识点。 首先,Android launcher是用户启动应用程序的主...

    可拖拽listview,可改变item位置

    为了实现这一功能,我们需要自定义一个可拖拽的ListView,使用户可以直观地通过手势调整列表中各个条目的顺序。这个"可拖拽listview,可改变item位置"的功能,正是我们要讨论的知识点。 首先,我们需要创建一个...

Global site tag (gtag.js) - Google Analytics