自定义view系列(5)--99.99%实现QQ侧滑删除效果

本文介绍了如何实现类似QQ的侧滑删除效果,基于GitHub上的SwipeMenuListView项目进行修改。文章指出原项目依赖问题及滑动恢复bug,并提供了解决方案。通过分析QQ的交互逻辑,实现了在手指离开时保持滑出状态或关闭菜单的功能,同时修复了滑动方向可能导致误关闭的问题。文章附带了修改后的代码示例和下载链接。
摘要由CSDN通过智能技术生成

首先声明本文是基于GitHub上"baoyongzhang"的SwipeMenuListView修改而来,

该项目地址:https://github.com/baoyongzhang/SwipeMenuListView

可以说这个侧滑删除效果是我见过效果最好且比较灵活的项目,没有之一!!!

但是在使用它之前需要给大家提两点注意事项:

1,该项目支持Gradle dependence,但是目前作者提供的依赖地址对应的项目不是最新的项目,依赖过后的代码与demo中使用的不一致,会提示没有BaseSwipeListAdapter这个类,因为这个类是其他的开发者后来提交上去的,所以如果想使用最新的代码,目前还是得把代码下载下来,然后把library文件拷贝到自己项目中使用.

下图是目前作者提供的依赖地址,不是最新的,所以想用最新代码的朋友还是直接下载代码到本地吧.


2,第二点注意事项应该算是一个bug吧,如果你测试过作者给的demo,你会发现如果某一项item已经被拉出来了,这个时候你再把ListView向上或向下滑动,让这个被拉出来的item移出屏幕,然后再移回来,这个已经被拉出来的item会直接恢复到未拉出的状态.这会让用户感觉很困惑,我明明已经拉出了这个菜单,怎么又不见了,然后可能就会产生这个软件做的真垃圾的想法,进而可能把你的软件卸载掉.如下图:



对于上面两个注意事项,第一个倒是没什么好说的,第二个问题怎么办呢?别急,这正是我们今天要说的内容.

首先我们可以先研究一下QQ的侧滑删除效果,说到这你可以打开你的qq看看它的具体效果.

你会发现,如果一个item被拉出来了,当你的手指放到其他的item上时,它会直接先把被拉出的那个item关闭掉,并且当前动作的后续的事件也都不再响应,除非你再次把手指放到屏幕上,他才会响应相关事件,而如果你的手指放到当前被拉出的item上,他不会隐藏这个item,并且可以正常响应左右滑动事件.

ok,QQ的效果我们分析完毕,我们探讨一下它的实现原理:

1,如果一个item已经被拉了出来,当你的手指放到其他的item上时,它会直接先把被拉出的那个item关闭掉, 怎么实现呢?

首先我们需要判断我们当前所按下的这个item是不是被拉出来的那个item,不是的话,我们才需要关闭,是的话,则不用管.代码如下:

 if (view instanceof SwipeMenuLayout) {
                        SwipeMenuLayout touchView = (SwipeMenuLayout) view;
                        if (!touchView.isOpen()) {
                            mTouchView.smoothCloseMenu();
                        }
                    }

2,并且当前动作的后续的事件也都不再响应, 怎么实现呢?

这就很简单了,根据view的事件分发原理,如果在某一个触摸事件中返回了false,那么该事件后续的事件都不会再交给他处理,也就是说,如果我们在ACTION_DOWN的时候返回了false,那么后续的ACTION_MOVE,ACTION_UP等事件都不会响应,所以要实现这个效果,我们只需要在关闭菜单的后面,返回false就行了,完整的代码如下:

 /********新添加的内容,当按下的item不是当前已经打开的item,则关闭已经打开的item,并返回false.不再响应down以后的事件,仿qq效果********/
                    if (view instanceof SwipeMenuLayout) {
                        SwipeMenuLayout touchView = (SwipeMenuLayout) view;
                        if (!touchView.isOpen()) {
                            mTouchView.smoothCloseMenu();
                            return false;
                        }
                    }

这样的几行代码就实现了刚才分析的qq效果中的前半部分效果,即如果一个item被拉出来了,当你的手指放到其他的item上时,它会直接先把被拉出的那个item关闭掉,并且当前动作的后续的事件也都不再响应,除非你再次把手指放到屏幕上,他才会响应相关事件.

上面的那几行代码是基于SwipeMenuListView类修改而来,完整的修改之后的SwipeMenuListView代码如下所示:

package com.lanma.swipemenulistviewdemo.swipemenulistview;

import android.content.Context;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Interpolator;
import android.widget.ListAdapter;
import android.widget.ListView;

/**
 * @author baoyz
 * @date 2014-8-18
 * qiang_xi修改于2016-09-07(新增qq的效果)
 */
public class SwipeMenuListView extends ListView {

    private static final int TOUCH_STATE_NONE = 0;
    private static final int TOUCH_STATE_X = 1;
    private static final int TOUCH_STATE_Y = 2;

    public static final int DIRECTION_LEFT = 1;
    public static final int DIRECTION_RIGHT = -1;
    private int mDirection = 1;//swipe from right to left by default

    private int MAX_Y = 5;
    private int MAX_X = 3;
    private float mDownX;
    private float mDownY;
    private int mTouchState;
    private int mTouchPosition;
    private SwipeMenuLayout mTouchView;
    private OnSwipeListener mOnSwipeListener;

    private SwipeMenuCreator mMenuCreator;
    private OnMenuItemClickListener mOnMenuItemClickListener;
    private OnMenuStateChangeListener mOnMenuStateChangeListener;
    private Interpolator mCloseInterpolator;
    private Interpolator mOpenInterpolator;

    public SwipeMenuListView(Context context) {
        super(context);
        init();
    }

    public SwipeMenuListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

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

    private void init() {
        MAX_X = dp2px(MAX_X);
        MAX_Y = dp2px(MAX_Y);
        mTouchState = TOUCH_STATE_NONE;
    }

    @Override
    public void setAdapter(ListAdapter adapter) {
        super.setAdapter(new SwipeMenuAdapter(getContext(), adapter) {
            @Override
            public void createMenu(SwipeMenu menu) {
                if (mMenuCreator != null) {
                    mMenuCreator.create(menu);
                }
            }

            @Override
            public void onItemClick(SwipeMenuView view, SwipeMenu menu,
                                    int index) {
                boolean flag = false;
                if (mOnMenuItemClickListener != null) {
                    flag = mOnMenuItemClickListener.onMenuItemClick(
                            view.getPosition(), menu, index);
                }
                if (mTouchView != null && !flag) {
                    mTouchView.smoothCloseMenu();
                }
            }
        });
    }

    public void setCloseInterpolator(Interpolator interpolator) {
        mCloseInterpolator = interpolator;
    }

    public void setOpenInterpolator(Interpolator interpolator) {
        mOpenInterpolator = interpolator;
    }

    public Interpolator getOpenInterpolator() {
        return mOpenInterpolator;
    }

    public Interpolator getCloseInterpolator() {
        return mCloseInterpolator;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        //在拦截处处理,在滑动设置了点击事件的地方也能swip,点击时又不能影响原来的点击事件
        int action = ev.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值