Android 仿QQlistview侧滑删除

Posted BIGPiePieTree

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 仿QQlistview侧滑删除相关的知识,希望对你有一定的参考价值。

最近在项目中要实现listview的item能够侧滑显示按钮,然后点击删除对应的那一条数据。记得好像github上有一个开源的能实现这种效果,但是想想好像也不会太难,而且之前有很认真的了解过事件分发机制,大概整理整理思路 ,就动手自己写了一个。不过好像有些地方实现的效果不是太理想,以后还会有很大的改进余地。

我们来看看效果



在动手实现之前我们需要了解一下事件分发机制 以前在这里了解的Android事件分发机制完全解析,带你从源码的角度彻底理解(上)这里有个图一目了然

                                 

做个比喻,就像给公司老总提交涨工资,先给组长传达吧,组长看你工作努力,统一给你往上报,好嘛给部长了,部长觉得你能力不太行,然后就把申请书扣押下来自己处理,不传递给上级,然后通过组长告诉你,没戏!

既然对大概的情况了解我们就话不多说,我们来一步一步分解。


我们定义 一个DeleteListView 继承自ListView

并定义我们等下需要用到了一些变量

    private Scroller scroller;          //滑动类

    private int minDelta;          //最小滑动距离

    private int mDownX;             //手指按下时的坐标

    private int mDownY;


    private int itemPosition;          // 手指按下时所对应的item位置


    private boolean isSlide;              //是否item可以滑动


    private static int S_VELOCITY = 1200;


    private VelocityTracker velocityTracker;        //速度跟踪器


    private View itemview;            //得到滑动的item


    private String TAG = "XIONG";

    //监听滑动

    private SubViewClickListener subViewClickListener;

    //滑动方向
    int removeDirection;

    private final int TO_LEFT = 0;
    private final int TO_RITHG = 1;

    //删除按钮的  宽度

    int d_width = 0;

后面都有注释,我就不一一解释是什么意思了,等下我们用到的时候你就知道了。


重点是这两个方法我们需要重写

 一是 dispatchTouchEvent()   我们来看一下

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) 


        switch (event.getAction()) 
            case MotionEvent.ACTION_DOWN:

                isSlide = false;
                addVelocityTracker(event);

                //如果listview滑动还没有结束的时候    直接返回让listview处理滑动事件
                if (!scroller.isFinished()) 
                    return super.dispatchTouchEvent(event);
                

                mDownX = (int) event.getX();
                mDownY = (int) event.getY();

                //通过点击的坐标得到点击的子item的位置
                itemPosition = pointToPosition(mDownX, mDownY);
                Log.d(TAG, "touch  position" + itemPosition);


                if (itemPosition == AdapterView.INVALID_POSITION) 
                    return super.dispatchTouchEvent(event);
                

                itemview = getChildAt(itemPosition - getFirstVisiblePosition());
                itemview.findViewById(R.id.deledt_item).setOnClickListener(new OnClickListener() 
                    @Override
                    public void onClick(View v) 
                        itemview.scrollTo(0, 0);
                        subViewClickListener.subClick(itemPosition);
                    
                );
                break;
            case MotionEvent.ACTION_MOVE:
                float tX = Math.abs(event.getX() - mDownX);
                float tY = Math.abs(event.getY() - mDownY);  //   当x方向偏移量大于y方向并且都大于最小偏移时
                if (((tX > minDelta) && (tY < minDelta) && tX > tY) || getVelocity() > S_VELOCITY) 
                    isSlide = true;
                


                break;
            case MotionEvent.ACTION_UP:
                clearVelocityTracker();
                break;
        
        return super.dispatchTouchEvent(event);
    

在这里 我们在滑动listview的时候 先把event这个动作传给速度跟踪器,在这里我们要通过scroller来知道是不是listview还在滑动,如果还在滑动的话

return super.dispatchTouchEvent(event);
把它交给listview自己处理滑动事件,下面也是。然后我们通过按下的坐标获取对应的item并且给子view添加点击事件。


另外一个重写的方法是onTouchEvent()方法

    @Override
    public boolean onTouchEvent(MotionEvent ev) 

        if (isSlide && itemPosition != AdapterView.INVALID_POSITION) 

            // 拦截监听事件
            requestDisallowInterceptTouchEvent(true);

            addVelocityTracker(ev);

            int x = (int) ev.getX();
            switch (ev.getAction()) 
                case MotionEvent.ACTION_DOWN:
                    break;
                case MotionEvent.ACTION_MOVE:
                    MotionEvent cancelEvent = MotionEvent.obtain(ev);
                    cancelEvent.setAction(MotionEvent.ACTION_CANCEL |
                            (ev.getActionIndex() << MotionEvent.ACTION_POINTER_INDEX_SHIFT));
                    onTouchEvent(cancelEvent);
                    int deltaX = mDownX - x;
                    mDownX = x;


                    // 向左滑动的时候 , deltax>0  但是如果滑动的速度比较快,会造成删除部分太过向左
                    //   所以 当deltax超出范围时,控制到能达到的最大距离
                    if (deltaX > 0) 
                        if (Math.abs(itemview.getScrollX()) < d_width - 40) 
                            if (itemview.getScrollX() + deltaX > 400) 
                                deltaX = 400 - itemview.getScrollX();
                            
                            removeDirection = TO_LEFT;
                            itemview.scrollBy(deltaX, 0);
                        
                     else 

                        //向右滑动回复未滑动状态时
                        if (itemview.getScrollX() > 0) 

                            removeDirection = TO_RITHG;
                            itemview.scrollBy(deltaX, 0);
                        
                    


                    return true;
                case MotionEvent.ACTION_UP:

                    // 当手指滑动距离短但是速度比较快时   ,判断向左还是向右

                    int v = getVelocity();
                    if (v > S_VELOCITY) 
                        scrollToLeft();
                     else if (v < -S_VELOCITY) 
                        scrollToRight(itemview);
                     else 
                        scrollByDistanceX();
                    

            
        
        return super.onTouchEvent(ev);
    


这里是
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    

    <com.example.xiong.listviewdelete.DeleteListView
        android:id="@+id/delete_listview"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </com.example.xiong.listviewdelete.DeleteListView>
</RelativeLayout>


在Activity中的使用

        deleteListView = (DeleteListView) findViewById(R.id.delete_listview);
        for (int i = 0; i < 20; i++) 
            dataSourceList.add("第" + i + "个");
        
        baseAdapter = new ArrayAdapter<String>(this, R.layout.item, R.id.list_item, dataSourceList);
        deleteListView.setAdapter(baseAdapter);

        deleteListView.setSubViewClickListener(new DeleteListView.SubViewClickListener() 
            @Override
            public void subClick(int position) 
                
            
        );


github就不上了,直接把代码贴这吧


以上是关于Android 仿QQlistview侧滑删除的主要内容,如果未能解决你的问题,请参考以下文章

Android高仿网易新闻客户端之侧滑菜单

仿QQ侧滑删除(简陋版)

Android使用DrawerLayout仿qq6.6版本侧滑效果

Android使用DrawerLayout仿qq6.6版本侧滑效果

Android组件——使用DrawerLayout仿网易新闻v4.4侧滑菜单

仿QQ侧滑删除Item:Swipemenulistview的简单实现