仿QQ左滑删除

1.先看下效果图(本来是想上传视屏的,但不知道怎么上传哈,哪位知道怎么上传留个言),我讲下实际操作情况。当手指选择了其中一个ItemView,会随着手指滑动(此时ListView不能进行滑动),当手指离开界面,如果向左滑动超过了删除按钮的一半宽度,则显示删除按钮,否则隐藏删除按钮。当手指重新点击界面时,如果之前的点击的ItemView删除按钮处于打开状态,则隐藏删除按钮。


 


2.左右滑动的实现是ItemView继承了LinearLayout。再次点击屏幕,上个itemView删除按钮的隐藏,是通过继承ListView实现。先贴下ItemView的完整代码:

package com.deleteview;

import android.content.Context;
import android.support.v4.view.MotionEventCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.ViewConfiguration;
import android.widget.LinearLayout;
import android.widget.Scroller;


/**
 * Created by 54420 on 2016/10/29.
 */
public class SlideView extends LinearLayout {
    private int downX,firstX;
    private Scroller scroller;
    private VelocityTracker mVelocityTracker;   //手速监听
    private int mTouchSLop;           //最小移动距离

    private int mDeleteWidth;     //删除按钮宽度

    private int minVelocity = 600;
    private State state = State.CLOSE;
    private int xVelocity,yVelocity;          //横向和纵向的手速

    public enum State{
        CLOSE,OPEN
    }

    public SlideView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    private void init(Context context){
        mTouchSLop = ViewConfiguration.get(context).getScaledTouchSlop();
        scroller = new Scroller(context);
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        addVelocityTracker(event);
        switch (MotionEventCompat.getActionMasked(event)){
            case MotionEvent.ACTION_DOWN:
                xVelocity = 0;
                yVelocity = 0;
                firstX = downX = (int) event.getX();
                if(getChildCount() < 2){
                    try {
                        throw new Exception("必需包含两个子View");
                    } catch (Exception e) {
                        Log.e("DeleteView","必需包含两个子View");
                        e.printStackTrace();
                    }
                }else
                mDeleteWidth = getChildAt(1).getWidth();
                break;
            case MotionEvent.ACTION_MOVE:
                moveAction(event);
                break;
            case MotionEvent.ACTION_CANCEL:
                scrollerRight();             //失去事件时,删除按钮隐藏
                removeVelocityTracker(event);         //移除手速监听
                break;
            case MotionEvent.ACTION_UP:
                if(Math.abs(xVelocity) > Math.abs(yVelocity) && Math.abs(yVelocity) < minVelocity){        //抬手时的手速判断
                    if(xVelocity > minVelocity ){
                        scrollerRight();
                    }else if(xVelocity < -minVelocity){
                        scrollerLeft();
                    }else{
                        scrollerByDisX();              //根据滑动的距离判断滑动方向
                    }
                }else {
                    scrollerByDisX();
                }
                removeVelocityTracker(event);            //移除手速监听
                break;
        }
        return true;
    }

    //滑动事件
    private void moveAction(MotionEvent event){
        int x = (int) event.getX();
        xVelocity = getXvelocity();
        yVelocity = getYvelocity();
        if(Math.abs(x - firstX) > mTouchSLop){
            getParent().requestDisallowInterceptTouchEvent(true);        //告诉父层已经处理了滑动事件,不要去拦截
            if(getScrollX() <= 0){         //如果删除按钮完全隐藏,则只能向左滑
                if(x < downX){
                    scrollerItem(x);
                }
            }else if(getScrollX() >= mDeleteWidth){      //如果完全显示删除按钮则只能向右滑
                if(x > downX){
                    scrollerItem(x);
                }
            }else {
                scrollerItem(x);
            }
            rectifyScroller();                //纠正因滑速过快造成的偏差
        }

        downX = x;
    }



    //移动
    private void scrollerItem(int x){
        int offsetX = downX - x;
        scrollBy(offsetX,0);
    }

    //移动到最左边
    private void  scrollerLeft(){
        int offsetX = mDeleteWidth - getScrollX();
        scroller.startScroll(getScrollX(),0,offsetX,0,Math.abs(offsetX));
        postInvalidate();
        state = State.OPEN;
    }

    //移动到最右边
    private void scrollerRight(){
        int offsetX = getScrollX();
        scroller.startScroll(getScrollX(),0,-offsetX,0,Math.abs(offsetX));
        postInvalidate();
        state =  State.CLOSE;
    }

    //纠正因移动过快产生的偏移差
    private void rectifyScroller(){
        if(getScrollX() < 0){
            scrollTo(0,0);
        }else if(getScrollX() > mDeleteWidth){
            scrollTo(mDeleteWidth,0);
        }
    }

    //抬手时根据移动距离判断是否显示删除按钮
    private void  scrollerByDisX(){
        if(getScrollX() > mDeleteWidth/2){
            scrollerLeft();
        }else {
            scrollerRight();
        }
    }

    @Override
    public void computeScroll() {
         if(scroller.computeScrollOffset()){
             scrollTo(scroller.getCurrX(),scroller.getCurrY());
             postInvalidate();
         }
    }

    //获取X轴的移动速度
    private int getXvelocity(){
       if(mVelocityTracker != null){
           mVelocityTracker.computeCurrentVelocity(1000);
           return (int) mVelocityTracker.getXVelocity();
       }
        return 0;
    }

    //获取Y轴的移动速度
    private int getYvelocity(){
        if(mVelocityTracker != null){
            mVelocityTracker.computeCurrentVelocity(1000);
            return (int) mVelocityTracker.getYVelocity();
        }
        return 0;
    }

    //添加手速监听
    private void addVelocityTracker(MotionEvent event){
        if(mVelocityTracker == null){
            mVelocityTracker = VelocityTracker.obtain();
        }
        mVelocityTracker.addMovement(event);
    }

    //移除速度监听器
    private void removeVelocityTracker(MotionEvent event){
        if(mVelocityTracker != null){
            mVelocityTracker.recycle();
        }
        mVelocityTracker = null;
    }

    //关闭删除按钮显示
    public void close(){
        if(state == State.OPEN){
            scrollerRight();
        }
    }
}

(1)ACTION_DOWN事件

  获取点击时X的坐标点,以及删除按钮的宽度

  xVelocity = 0;
                yVelocity = 0;
                firstX = downX = (int) event.getX();
                if(getChildCount() < 2){
                    try {
                        throw new Exception("必需包含两个子View");
                    } catch (Exception e) {
                        Log.e("DeleteView","必需包含两个子View");
                        e.printStackTrace();
                    }
                }else
                mDeleteWidth = getChildAt(1).getWidth();

 (2)ACTION_MOVE事件

   当X轴的滑动距离超过系统识别的最小滑动距离时获取MOVE事件,并通过getParent().requestDisallowInterceptTouchEvent(true);告诉父层已经获取了事件,不要进行拦截。再通过scrollBy(offsetX,0)进行ItemVIew的滑动。

private void moveAction(MotionEvent event){
        int x = (int) event.getX();
        xVelocity = getXvelocity();
        yVelocity = getYvelocity();
        if(Math.abs(x - firstX) > mTouchSLop){
            getParent().requestDisallowInterceptTouchEvent(true);        //告诉父层已经处理了滑动事件,不要去拦截
            if(getScrollX() <= 0){         //如果删除按钮完全隐藏,则只能向左滑
                if(x < downX){
                    scrollerItem(x);
                }
            }else if(getScrollX() >= mDeleteWidth){      //如果完全显示删除按钮则只能向右滑
                if(x > downX){
                    scrollerItem(x);
                }
            }else {
                scrollerItem(x);
            }
            rectifyScroller();                //纠正因滑速过快造成的偏差
        }

        downX = x;
    }

(3)ACTION_CANCEL事件

   当ListView拦截了事件则会触发ItemView的cancel事件。这时让当前的itemView隐藏删除按钮

    scrollerRight();             //失去事件时,删除按钮隐藏
     removeVelocityTracker(event);         //移除手速监听

(4)ACTION_UP事件

 当手指离开屏幕时,先根据手势判断是显示还是隐藏删除按钮,再根据滑动距离判断。

 

if(Math.abs(xVelocity) > Math.abs(yVelocity) && Math.abs(yVelocity) < minVelocity){        //抬手时的手速判断
                    if(xVelocity > minVelocity ){
                        scrollerRight();
                    }else if(xVelocity < -minVelocity){
                        scrollerLeft();
                    }else{
                        scrollerByDisX();              //根据滑动的距离判断滑动方向
                    }
                }else {
                    scrollerByDisX();
                }
                removeVelocityTracker(event);            //移除手速监听

3.MyListView继承自ListView,当点击屏幕时,先把上个点击的ItemView的删除按钮隐藏,通过SlideView的close()方法。再根据点击的位置获取到当前ItemView。

public class MyListView extends ListView {
    private SlideView itemView;
    public MyListView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }


    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (MotionEventCompat.getActionMasked(ev)){
            case MotionEvent.ACTION_DOWN:
                if(itemView != null){                                          //关闭之前的ItemView删除按钮的显示状态
                    itemView.close();
                }
                int dowX = (int) ev.getX();
                int dowY = (int) ev.getY();
                int itemPosition = pointToPosition(dowX,dowY);
                if(itemPosition == AbsListView.INVALID_POSITION){
                    return  super.dispatchTouchEvent(ev);
                }
                itemView = (SlideView) getChildAt(itemPosition - getFirstVisiblePosition());                  //记录当前ItemVIew
                break;
        }
        return super.dispatchTouchEvent(ev);
    }


SlideView的close()方法

//关闭删除按钮显示
    public void close(){
        if(state == State.OPEN){
            scrollerRight();
        }
    }

4.最后是下载地址(http://download.csdn.net/detail/huangma11/9672108)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值