ListView的item水平滑动(类QQ的左滑显示删除按钮)
2015-03-19 18:51
316 查看
QQ的一个聊天界面的listview每一行向左滑动的时候,会出现删除的按钮,特别炫酷,这个效果可以有,今天跟大家分享下。
先上demo的效果图
界面很丑,因为主要是介绍功能,界面什么的,搞那么复杂,下demo的时候还浪费资源,哈哈哈。
用到的几个类(4个)
SwipeItemLayout,SwipeListView,SwipeAdapter,FragmentTestActivity.
SwipeItemLayout就是listView的一个item,这个类集成了FrameLayout。SwipeListView是重写的一个ListView,其实主要在她的OnTouch事件的处理上。SwipeAdapter是一个adapter,这个不用解释了,FragmenTestActivity这个就是怎么用的了。
好,一个一个来
首先我们看一个item怎么写,先上代码,代码里面基本上有逐行的解释。
接下来就是另一个重要的类了,那就是ListView到底怎样,之后我还是把源码放上去,绝对不要积分,有需要的可以自己下了看看。这里看下核心的代码(主要原因是加班时间快要到了,再不回去的话就出不去了,哈哈哈)
这是变量,额,写代码的时候没写注释,我怕你们看不懂额,就在这里写算了
说完了变量之后,核心的就两个方法
唉,实在是很麻烦,其实代码不难,就是很繁琐,各种控制,各种判断,大家把这段代码中的核心的几个方法搞明白了,也就没问题了。我就不多说了哈。。。
好了,剩下的两个类,一个是adapter类,一个是用法,我就只说adapter中的一个getView方法了哈,用法的话跟一般的ListView的用法一样,对了,说adapter不就是再说用法么,哈哈哈。
是不是看完整个过程有点点晕,其实很简单的,你下了源码,自己去看就好了,真的简单,各位大神不要见怪.
demo下载链接(免费)
先上demo的效果图
界面很丑,因为主要是介绍功能,界面什么的,搞那么复杂,下demo的时候还浪费资源,哈哈哈。
用到的几个类(4个)
SwipeItemLayout,SwipeListView,SwipeAdapter,FragmentTestActivity.
SwipeItemLayout就是listView的一个item,这个类集成了FrameLayout。SwipeListView是重写的一个ListView,其实主要在她的OnTouch事件的处理上。SwipeAdapter是一个adapter,这个不用解释了,FragmenTestActivity这个就是怎么用的了。
好,一个一个来
首先我们看一个item怎么写,先上代码,代码里面基本上有逐行的解释。
public class SwipeItemLayout extends FrameLayout { //这个是内容的item,也就是不左滑的时候的布局 private View contentView = null; //这个是左滑之后显示的那个部分,即多出的部分 private View menuView = null; //这个是动画的速度控制器,其实没用到 private Interpolator closeInterpolator = null; private Interpolator openInterpolator = null; //控制控件滑动的,会平滑滑动,一个开一个关 private ScrollerCompat mOpenScroller; private ScrollerCompat mCloseScroller; //左滑之后,contentView左边距离屏幕左边的距离,基线,用于滑回 private int mBaseX; //手指点击的初始位置 private int mDownX; //当前item的状态,open和close两种 private int state = STATE_CLOSE; private static final int STATE_CLOSE = 0; private static final int STATE_OPEN = 1; //构造函数 public SwipeItemLayout(View contentView,View menuView,Interpolator closeInterpolator, Interpolator openInterpolator){ super(contentView.getContext()); this.contentView = contentView; this.menuView = menuView; this.closeInterpolator = closeInterpolator; this.openInterpolator = openInterpolator; init(); } private void init(){ //设置一个item的宽和高,其实就是设置宽充满而已 setLayoutParams(new AbsListView.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); //初始化mColoseScroller和mOpenScroller if (closeInterpolator != null) { mCloseScroller = ScrollerCompat.create(getContext(), closeInterpolator); } else { mCloseScroller = ScrollerCompat.create(getContext()); } if (openInterpolator != null) { mOpenScroller = ScrollerCompat.create(getContext(), openInterpolator); } else { mOpenScroller = ScrollerCompat.create(getContext()); } //这也是设置宽和高 LayoutParams contentParams = new LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); contentView.setLayoutParams(contentParams); menuView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); //将这两个布局都add到这个view中 addView(contentView); addView(menuView); } //这个类就是当用户在界面上滑动的时候,通过ListView的onTouch方法,将MotionEvent的动作传到这里来,通过这个函数执行操作。 public boolean onSwipe(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: //记录当前手指点击的x的坐标 mDownX = (int) event.getX(); break; case MotionEvent.ACTION_MOVE: //当手指移动的时候,获取这个差值 int dis = (int) (mDownX - event.getX()); //这个地方,当状态是open的时候,为啥要执行 += 这个操作,我们在下面就会找到答案的 if (state == STATE_OPEN) { dis += menuView.getWidth(); } //这个函数在下面说 swipe(dis); break; case MotionEvent.ACTION_UP: //这里其实是一个判断,当用户滑了menuView的一半的时候,自动滑出来,否则滑进去。 if ((mDownX - event.getX()) > (menuView.getWidth() / 2)) { // 平滑的滑出 smoothOpenMenu(); } else { // 平滑的滑进 smoothCloseMenu(); return false; } break; } //这个地方一定要return true,才能保证这个动作不会继续往下传递 return true; } // 判断是否滑出的状态 public boolean isOpen() { return state == STATE_OPEN; } //这个方法就是滑动dis的距离,还记得那个 += 吗,如果dis > menuView.getWidth()的 话,dis = menuView.getWidth().这样,当滑到最大限度的时候,就不会滑动了 private void swipe(int dis) { if (dis > menuView.getWidth()) { dis = menuView.getWidth(); } if (dis < 0) { dis = 0; } // layout的四个参数分别是(l,t,r,b),这样实现contentView的移动,这个应该没问题的吧? contentView.layout(-dis, contentView.getTop(), contentView.getWidth() - dis, getMeasuredHeight()); // 这个跟上面方法一样 menuView.layout(contentView.getWidth() - dis, menuView.getTop(), contentView.getWidth() + menuView.getWidth() - dis, menuView.getBottom()); } //这个方法是系统的方法,就是执行一个刷新而已 @Override public void computeScroll() { if (state == STATE_OPEN) { if (mOpenScroller.computeScrollOffset()) { swipe(mOpenScroller.getCurrX()); postInvalidate(); } } else { if (mCloseScroller.computeScrollOffset()) { swipe(mBaseX - mCloseScroller.getCurrX()); postInvalidate(); } } } // 额,这个不用解释了 public void smoothCloseMenu() { state = STATE_CLOSE; mBaseX = -contentView.getLeft(); mCloseScroller.startScroll(0, 0, mBaseX, 0, 350); postInvalidate(); } // 额 这个也不用解释了 public void smoothOpenMenu() { state = STATE_OPEN; mOpenScroller.startScroll(-contentView.getLeft(), 0, menuView.getWidth(), 0, 350); postInvalidate(); } // 这个也懒得解释了 public void closeMenu() { if (mCloseScroller.computeScrollOffset()) { mCloseScroller.abortAnimation(); } if (state == STATE_OPEN) { state = STATE_CLOSE; swipe(0); } } // 各位码大大最棒了 public void openMenu() { if (state == STATE_CLOSE) { state = STATE_OPEN; swipe(menuView.getWidth()); } } public View getContentView() { return contentView; } public View getMenuView() { return menuView; } //这个方法 其实就是获取menuView的宽和高 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); menuView.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec( getMeasuredHeight(), MeasureSpec.EXACTLY)); } //这个方法就把两个控件的相对布局表现出来了 @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { contentView.layout(0, 0, getMeasuredWidth(), contentView.getMeasuredHeight()); menuView.layout(getMeasuredWidth(), 0, getMeasuredWidth() + menuView.getMeasuredWidth(), contentView.getMeasuredHeight()); } }
接下来就是另一个重要的类了,那就是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; //这是设置的两个方向的阀值 private int MAX_Y = 5; private int MAX_X = 3; // 记录初始时候的坐标 private float mDownX; //状态标志符 private int mTouchState; // 触摸的位置 private int mTouchPosition; private SwipeItemLayout mTouchView; //private OnSwipeListener mOnSwipeListener; private Interpolator mCloseInterpolator; private Interpolator mOpenInterpolator;
说完了变量之后,核心的就两个方法
@Override public boolean onTouchEvent(MotionEvent ev) { if (ev.getAction() != MotionEvent.ACTION_DOWN && mTouchView == null) return super.onTouchEvent(ev); int action = MotionEventCompat.getActionMasked(ev); action = ev.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: int oldPos = mTouchPosition; mDownX = ev.getX(); mDownY = ev.getY(); mTouchState = TOUCH_STATE_NONE; //这个方法就是获取当前的x,y坐标对应的是listView中的哪个position,是系统方法。 mTouchPosition = pointToPosition((int) ev.getX(), (int) ev.getY()); if (mTouchPosition == oldPos && mTouchView != null && mTouchView.isOpen()) { mTouchState = TOUCH_STATE_X; mTouchView.onSwipe(ev); return true; } //这个方法获取当前的item的View,也是系统的方法 View view = getChildAt(mTouchPosition - getFirstVisiblePosition()); if (mTouchView != null && mTouchView.isOpen()) { mTouchView.smoothCloseMenu(); mTouchView = null; return super.onTouchEvent(ev); } if (view instanceof SwipeItemLayout) { mTouchView = (SwipeItemLayout) view; } if (mTouchView != null) { mTouchView.onSwipe(ev); } break; case MotionEvent.ACTION_MOVE: float dy = Math.abs((ev.getY() - mDownY)); float dx = Math.abs((ev.getX() - mDownX)); if (mTouchState == TOUCH_STATE_X) { if (mTouchView != null) { mTouchView.onSwipe(ev); } getSelector().setState(new int[] { 0 }); ev.setAction(MotionEvent.ACTION_CANCEL); super.onTouchEvent(ev); return true; } else if (mTouchState == TOUCH_STATE_NONE) { if (Math.abs(dy) > MAX_Y) { mTouchState = TOUCH_STATE_Y; } else if (dx > MAX_X) { mTouchState = TOUCH_STATE_X; // if (mOnSwipeListener != null) { // mOnSwipeListener.onSwipeStart(mTouchPosition); // } } } break; case MotionEvent.ACTION_UP: if (mTouchState == TOUCH_STATE_X) { if (mTouchView != null) { mTouchView.onSwipe(ev); if (!mTouchView.isOpen()) { mTouchPosition = -1; mTouchView = null; } } // if (mOnSwipeListener != null) { // mOnSwipeListener.onSwipeEnd(mTouchPosition); // } ev.setAction(MotionEvent.ACTION_CANCEL); super.onTouchEvent(ev); return true; } break; } return super.onTouchEvent(ev); } public void smoothOpenMenu(int position) { if (position >= getFirstVisiblePosition() && position <= getLastVisiblePosition()) { View view = getChildAt(position - getFirstVisiblePosition()); if (view instanceof SwipeItemLayout) { mTouchPosition = position; if (mTouchView != null && mTouchView.isOpen()) { mTouchView.smoothCloseMenu(); } mTouchView = (SwipeItemLayout) view; mTouchView.smoothOpenMenu(); } } }
唉,实在是很麻烦,其实代码不难,就是很繁琐,各种控制,各种判断,大家把这段代码中的核心的几个方法搞明白了,也就没问题了。我就不多说了哈。。。
好了,剩下的两个类,一个是adapter类,一个是用法,我就只说adapter中的一个getView方法了哈,用法的话跟一般的ListView的用法一样,对了,说adapter不就是再说用法么,哈哈哈。
@Override public View getView(int position, View contentView, ViewGroup arg2) { ViewHolder holder = null; if(contentView==null){ holder = new ViewHolder(); View view01 = LayoutInflater.from(mContext).inflate(R.layout.test01, null); View view02 = LayoutInflater.from(mContext).inflate(R.layout.test2, null); //这个地方就用到了我们自己写的那个类了,后面两个参数我上面已经说了,没用到,用到的话也可以,自己改下代码就好了。其他的没什么区别吧 contentView = new SwipeItemLayout(view01, view02, null, null); contentView.setTag(holder); }else{ holder = (ViewHolder) contentView.getTag(); } //这个地方如果你的menu里面有button什么的,就可以在这个地方注册监听,或者,你直接将view02(上面声明的)自定义也行,在自定义的类中实现onClickListener 方法 // holder.btn.setOnClickListener(new OnClickListener() { // // @Override // public void onClick(View arg0) { // // TODO Auto-generated method stub // Toast.makeText(mContext, "click", Toast.LENGTH_LONG).show(); // } // }); return contentView; }
是不是看完整个过程有点点晕,其实很简单的,你下了源码,自己去看就好了,真的简单,各位大神不要见怪.
demo下载链接(免费)
相关文章推荐
- 自定义ListView实现仿QQ消息列表滑动item出现删除按钮
- Android View深入学习——实现QQ滑动显示隐藏按钮ListView
- Android学习自定义View(四)——继承控件(滑动时ListView的Item出现删除按钮)
- Android仿QQ、微信ListView滑动删除item
- 重写listview,横向滑动出现删除按钮,点击按钮删除item
- Android Listview item向左滑动 显示菜单(仿QQ滑动)
- android侧滑删除,模仿qq跟进item显示删除按钮
- 自定义listview,实现Item侧滑显示删除、置顶按钮
- ListView 仿QQ侧滑显示删除按钮
- Android学习自定义View(四)——继承控件(滑动时ListView的Item出现删除按钮)
- Android ListViewitem滑动出现删除按钮
- Android Listview item向左滑动 显示菜单(仿QQ滑动)
- Android 使用Scroller实现绚丽的ListView左右滑动删除Item效果
- Android 仿iPhone ListView拖动排序 按钮联动删除显示隐藏
- android 实现Listview左右滑动删除Item
- listview 实现微信删除功能向左移动item出现隐藏的删除按钮功能终于实现了,分享总结一下。(跟微信删除一样额)
- Android ListView实现单击item出现删除按钮以及滑动出现删除按钮
- Android 使用NineOldAndroids实现绚丽的ListView左右滑动删除Item效果
- Android 使用NineOldAndroids实现绚丽的ListView左右滑动删除Item效果
- android中listview的item滑动删除效果(已解决listview点击问题)