Android仿微信列表滑动删除 如何实现滑动列表SwipeListView

接上一篇,本篇主要讲如何实现滑动列表SwipeListView。

上篇完成了滑动控件SwipeItemView,这个控件是一个自定义的ViewGroup,作为列表的一个item,为列表提供一些方法让这个SwipeItemView能滑动其视图内容,同时滑动过程中会有顺滑的动画效果。而本篇讲的SwipeListView则是这个列表的具体实现了。当然啦,这个SwipeListView继承自ListView,为了实现我们需要的功能,重点就是重写ListView的onTouchEvent()以及onInterceptTouchEvent()这个方法了。先说onTouchEvent():

@Override public boolean onTouchEvent(MotionEvent ev) { //if user had not set mSwipeItemViewID, not handle any touch event if(mSwipeItemViewID == -1) return super.onTouchEvent(ev); if(mCancelMotionEvent && ev.getAction() == MotionEvent.ACTION_DOWN) { //ev.setAction(MotionEvent.ACTION_CANCEL); LogUtil.Log("SwipeListView.onTouchEvent(), cancel ACTION_DOWN"); hideShowingItem(); return true; } else if(mCancelMotionEvent && ev.getAction() == MotionEvent.ACTION_MOVE) { if(mSwipeItemView.getCurrentScrollX() > 0) { mSwipeItemView.computeScroll(); //mSwipeItemView.scrollBy(-1, 0); } return true; } else if(mCancelMotionEvent && ev.getAction() == MotionEvent.ACTION_UP) { mCancelMotionEvent = false; return true; } switch(ev.getAction()) { case MotionEvent.ACTION_DOWN: { LogUtil.Log("ACTION_DOWN"); if(mTracker == null) { mTracker = VelocityTracker.obtain(); } else { mTracker.clear(); } mActionDownX = ev.getX(); mActionDownY = ev.getY(); mLastMotionX = ev.getX(); mLastMotionY = ev.getY(); }break; case MotionEvent.ACTION_MOVE: { //if the scroll distance at X-axis or Y-axis less than the //TOUCH_SLOP, do not handle the event MotionEvent.ACTION_MOVE if(Math.abs(ev.getX() - mActionDownX) < TOUCH_SLOP || Math.abs(ev.getY() - mActionDownY) < TOUCH_SLOP) break; float curX = ev.getX(); float curY = ev.getY(); int distanceX = (int)(mLastMotionX - curX); int distanceY = (int)(mLastMotionY - curY); if(mScrollDirection == DIRECTION_UNKNOW && Math.abs(distanceY) <= Math.abs(distanceX)) mScrollDirection = DIRECTION_HORIZONTAL; else if(mScrollDirection == DIRECTION_UNKNOW && Math.abs(distanceY) > Math.abs(distanceX)) mScrollDirection = DIRECTION_VERTICAL; //if ListView is scrolling vertical, do not handle the touch event if(mScrollDirection == DIRECTION_VERTICAL) break; int lastPos = pointToPosition((int)mActionDownX, (int)mActionDownY); int firstVisibleItemPos = getFirstVisiblePosition() - getHeaderViewsCount(); int factPos = lastPos - firstVisibleItemPos; mItemView = getChildAt(factPos); if(mItemView != null) { mSwipeItemView = (SwipeItemView)mItemView.findViewById(mSwipeItemViewID); if(mSwipeItemView.getSlidingView() != null && mSwipeItemView.getScrollX() <= mSwipeItemView.getSlidingView().getWidth() && mSwipeItemView.getScrollX() >= 0) { if(mSwipeItemView.getScrollX() + distanceX > mSwipeItemView.getSlidingView().getWidth()) distanceX = mSwipeItemView.getSlidingView().getWidth() - mSwipeItemView.getScrollX(); else if(mSwipeItemView.getScrollX() + distanceX < 0) distanceX = -mSwipeItemView.getScrollX(); mSwipeItemView.scrollBy(distanceX, 0); } mLastShowingPos = lastPos; ev.setAction(MotionEvent.ACTION_CANCEL); } mLastMotionX = curX; mLastMotionY = curY; }break; case MotionEvent.ACTION_UP: { LogUtil.Log("ACTION_UP"); if(mTracker != null) { mTracker.clear(); mTracker.recycle(); mTracker = null; } //reset the mScrollDirection to DIRECTION_UNKNOW mScrollDirection = DIRECTION_UNKNOW; //reset the mCancelMotionEvent to false mCancelMotionEvent = false; //ensure if the showing item need open or hide if(mLastShowingPos != -1) ensureIfItemOpenOrHide(); }break; case MotionEvent.ACTION_CANCEL: { hideShowingItem(); }break; } return super.onTouchEvent(ev); }

上面代码,首先分析用户滑开一个item的操作,这个操作以ACTION_DOWN起始,一系列的ACTION_MOVE,以ACTION_UP作为结束,所以,在ACTION_DOWN事件里面,我们先记录下最开始的事件位置mActionDownX和mActionDownY;然后再ACTION_MOVE事件里面,我们先要进行判断,这个判断分两步,第一步,判断这个ACTION_MOVE事件下,当前事件的位置curX和curY在x轴上以及y轴上和ACTION_DOWN里面记录的位置的距离是否已经超过TOUCH_SLOP的值,这个值是android用来判断是否应该进行一次滑动的阈值,第二步,我们要进一步判断用户是纵向滑动这整个列表还是左右滑动某个item,这里的逻辑判断就简单点处理,若是超过TOUCH_SLOP阈值的情况下,x轴方向上距离大于y轴的,我们就认为用户是左右滑动单个item,反之则是纵向滑动整个列表,这里我们用三种状态区分,DIRECTION_UNKNOW表示当前的滑动操作还没有进行判断左右滑动还是纵向滑动,DIRECTION_HORIZONTAL表示当前滑动操作判定为左右滑动,DIRECTION_VERTICAL表示判定为纵向滑动,一旦滑动操作被判定了,则在ACTION_UP处理前,我们都认为用户是做同一方向的滑动;ACTION_UP事件里面,重置滑动操作状态为DIRECTION_UNKNOW以便下一次的判定,以及这次ACTION_UP事件处理的时候,如果当前滑开的item的位置mLastShowingPos不为-1,则表示当前是一次滑开的操作,这次仔细想想,用户可能在并没有完全滑开这个item的状态下手就离开屏幕了,这时候我们就应该要判断此时这个被滑动的item是应该完全打开又或者是关闭,这里的逻辑判断是item已经滑开的距离超过它本身宽度的一半的话,就完全打开它,否则就关闭它,ensureIfItemOpenOrHide()的具体代码如下:

private void ensureIfItemOpenOrHide() { if(mLastShowingPos != -1) { int firstVisibleItemPos = getFirstVisiblePosition() - getHeaderViewsCount(); int factPos = mLastShowingPos - firstVisibleItemPos; mItemView = getChildAt(factPos); if(mItemView != null) { mSwipeItemView = (SwipeItemView)mItemView.findViewById(mSwipeItemViewID); if(mSwipeItemView.getSlidingView() != null && mSwipeItemView.getScrollX() >= mSwipeItemView.getSlidingView().getWidth() / 2) { openShowingItem(); } else if(mSwipeItemView.getSlidingView() != null) { hideShowingItem(); } } } }

那第一次的用户滑动操作的逻辑判定我们就算处理完了。接下来是第二次的,为什么说第二次呢,第一次用户滑开了某单个的item,使其处于打开的状态下,再一次触摸屏幕,这次我们则要再一次进行判定,其一,如果ACTION_DOWN发生的位置在item滑开显示出来的button的范围内,表示当前用户是点击这个button,这样我们就不做额外处理,直接交由列表默认的逻辑处理;其二,如果ACTION_DOWN发生的位置不在item滑开后显示出来的button范围内,怎表示当前用户只是操作列表的其他范围,这里我们就关闭当前打开了的item,并取消后续的touch事件,这里的话,我们就要截获这个ACTIOIN_DOWN事件了,需要重写ListView的onInterceptTouchEvent()方法,代码如下:

public boolean onInterceptTouchEvent(MotionEvent ev) { //if user had not set mSwipeItemViewID, not handle any touch event if(mSwipeItemViewID == -1) return super.onInterceptTouchEvent(ev); if(mLastShowingPos != -1 && ev.getAction() == MotionEvent.ACTION_DOWN && !isClickChildView(ev)) { LogUtil.Log("SwipeListView.onInterceptTouchEvent(), intercept ACTION_DOWN"); mCancelMotionEvent = true; return true; } else if(mLastShowingPos == -1 && ev.getAction() == MotionEvent.ACTION_DOWN) { return true; } return super.onInterceptTouchEvent(ev); }

上面的mCancelMotionEvent是用来在onTouchEvent()里面判断是否需要取消后续touch事件的标志,那期间,如何判断当前的ACTION_DOWN事件是否发生在button的范围内呢,使用如下代码:

private boolean isClickChildView(MotionEvent event) { if(mLastShowingPos != -1) { int firstVisibleItemPos = getFirstVisiblePosition() - getHeaderViewsCount(); int factPos = mLastShowingPos - firstVisibleItemPos; mItemView = getChildAt(factPos); if(mItemView != null) { mSwipeItemView = (SwipeItemView)mItemView.findViewById(mSwipeItemViewID); View slidingView = mSwipeItemView.getSlidingView(); if(slidingView != null) { int[] slidingViewLocation = new int[2]; slidingView.getLocationOnScreen(slidingViewLocation); int left = slidingViewLocation[0]; int right = slidingViewLocation[0] + slidingView.getWidth(); int top = slidingViewLocation[1]; int bottom = slidingViewLocation[1] + slidingView.getHeight(); return (event.getRawX() > left && event.getRawX() < right && event.getRawY() > top && event.getRawY() < bottom); } } } return false; }

剩下的,就是如何打开或者关闭一个item了,代码如下:

private void openShowingItem() { if(mLastShowingPos != -1) { int firstVisibleItemPos = getFirstVisiblePosition() - getHeaderViewsCount(); int factPos = mLastShowingPos - firstVisibleItemPos; mItemView = getChildAt(factPos); if(mItemView != null) { mSwipeItemView = (SwipeItemView)mItemView.findViewById(mSwipeItemViewID); if(mSwipeItemView.getSlidingView() != null) mSwipeItemView.scrollToWithAnimation( mSwipeItemView.getSlidingView().getWidth(), 0); } } } private void hideShowingItem() { if(mLastShowingPos != -1) { int firstVisibleItemPos = getFirstVisiblePosition() - getHeaderViewsCount(); int factPos = mLastShowingPos - firstVisibleItemPos; mItemView = getChildAt(factPos); if(mItemView != null) { mSwipeItemView = (SwipeItemView)mItemView.findViewById(mSwipeItemViewID); mSwipeItemView.scrollToWithAnimation(0, 0); } mLastShowingPos = -1; } }

上面的scrollToWithAnimation()方法就是上一篇博客里面我们实现了的移动item并使其带有动画效果的方法了。

这样,整个仿微信滑动删除操作的总体实现方案就解释完毕了,具体一些细节的话可以查看这个工程的源码,源码我已经上传到了我的Github主页上:https://github.com/YoungLeeForeverBoy/SlidingListViewPlus。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

时间: 2024-10-24 04:20:13

Android仿微信列表滑动删除 如何实现滑动列表SwipeListView的相关文章

Android仿微信滑动弹出编辑、删除菜单效果、增加下拉刷新功能_Android

如何为不同的list item呈现不同的菜单,本文实例就为大家介绍了Android仿微信或QQ滑动弹出编辑.删除菜单效果.增加下拉刷新等功能的实现,分享给大家供大家参考,具体内容如下 效果图: 1. 下载开源项目,并将其中的liberary导入到自己的项目中: 2. 使用SwipeMenuListView代替ListView,在页面中布局: <android.support.v4.widget.SwipeRefreshLayout android:id="@+id/swipeRefresh

Android仿微信通讯录列表侧边栏效果

先看Android仿微信通讯录列表侧边栏效果图 这是比较常见的效果了吧 列表根据首字符的拼音字母来排序,且可以通过侧边栏的字母索引来进行定位. 实现这样一个效果并不难,只要自定义一个索引View,然后引入一个可以对汉字进行拼音解析的jar包--pinyin4j-2.5.0即可 首先,先来定义侧边栏控件View,只要直接画出来即可. 字母选中项会变为红色,且滑动时背景会变色,此时SideBar并不包含居中的提示文本 public class SideBar extends View { priva

Android仿微信滑动退出Activity

效果图: 原理: 原理一句话就能描述清楚.重写Activity的dispatchTouchEvent,滑动的时候拿到Activity栈中栈顶Activity的上一个Acticity的ContentView添加到栈顶Activity的DecorView中,滑动的过程中做视图平移,滑动结束之后把前面拿过来用的ContentView归还给上一个Activity,然后finish当前Activity. ActivityStack: 实现 Application.ActivityLifecycleCall

Android仿微信@好友功能 输入@跳转、删除整块

最近在做聊天功能的时候,有一个需求是仿照微信做@好友的功能,本来以为挺简单,但是做到这块的时候,发现和想象的有点不一样,什么整块删除,块可编辑,总之,加个@的功能很简单,但是要做和微信的一样还是费了一些功夫,下面是一个demo仅供参考,防止遗忘 先上个效果图 就是这么个功能 1. 分析需求 输入@跳转到联系人界面,选中一个或者多个好友返回到当前界面 按退格键删除整块内容 块内的内容可编辑,编辑完了之后将不附带@功能,只是单纯的文字 2. 开始编码 既然是文本输入首先继承EditText自定义一个

Android仿微信5实现滑动导航条_Android

本文实例为大家分享了Android 仿微信5滑动导航效果,供大家参考,具体内容如下 ViewPageAdapter.java package com.rong; import java.util.ArrayList; import java.util.List; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import android.view.View; publi

Android仿微信5实现滑动导航条

本文实例为大家分享了Android 仿微信5滑动导航效果,供大家参考,具体内容如下 ViewPageAdapter.java package com.rong; import java.util.ArrayList; import java.util.List; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import android.view.View; publi

Android仿微信底部按钮滑动变色

Android仿微信底部按钮滑动变色,这里只针对使用Fragment为Tab页的滑动操作,进行简单的变色讲解. 首先说下OnPageChangeListener这个监听 //这个监听有三个方法 public abstract void onPageScrollStateChanged (int state) public abstract void onPageScrolled (int position, float positionOffset, int positionOffsetPixe

Android仿微信通讯录滑动快速定位功能

先给大家展示下效果图: 实现代码如下: 下面简单说下实现原理. public class IndexBar extends LinearLayout implements View.OnTouchListener { private static final String[] INDEXES = new String[]{"#", "A", "B", "C", "D", "E", &qu

Android仿微信发朋友圈浏览图片效果_Android

先看一下效果吧: 下面就来说一下具体怎么实现的: 实现思路 1.首先我们要获取数据源,数据源就是我们的每条说说(包括姓名.标题.图片数组) 2.自定义适配器(ListView嵌套着GridView) 3.图片点击浏览图片(Fragment+ViewPager) 具体实现 1.初始化数据源,设置适配器,看一下代码: public class MyActivity extends Activity { /*图片显示列表*/ private ListView listView; /*图片URL数组*/

Android仿微信发朋友圈浏览图片效果

先看一下效果吧: 下面就来说一下具体怎么实现的: 实现思路 1.首先我们要获取数据源,数据源就是我们的每条说说(包括姓名.标题.图片数组) 2.自定义适配器(ListView嵌套着GridView) 3.图片点击浏览图片(Fragment+ViewPager) 具体实现 1.初始化数据源,设置适配器,看一下代码: public class MyActivity extends Activity { /*图片显示列表*/ private ListView listView; /*图片URL数组*/