http://blog.csdn.net/top_code/article/details/17965743
微信对话列表滑动删除效果很不错的,借鉴了github上SwipeListView(项目地址:https://github.com/likebamboo/SwipeListView),在其上进行了一些重构,最终实现了微信对话列表滑动删除效果。
实现原理
1.通过ListView的pointToPosition(int x, int y)来获取按下的position,然后通过android.view.ViewGroup.getChildAt(position)来得到滑动对象swipeView
2.在onTouchEvent中计算要滑动的距离,调用swipeView.scrollTo即可。
运行效果如下
文章图片
文章图片
文章图片
下面是最核心的部分SwipeListView代码:
[java] view plain copy
- package com.fxsky.swipelist.widget;
- import android.annotation.SuppressLint;
- import android.content.Context;
- import android.content.res.TypedArray;
- import android.os.Handler;
- import android.os.Message;
- import android.util.AttributeSet;
- import android.view.MotionEvent;
- import android.view.View;
- import android.widget.ListView;
- import com.fxsky.swipelist.R;
- public class SwipeListView extends ListView {
- private Boolean mIsHorizontal;
- private View mPreItemView;
- private View mCurrentItemView;
- private float mFirstX;
- private float mFirstY;
- private int mRightViewWidth;
- // private boolean mIsInAnimation = false;
- private final int mDuration = 100;
- private final int mDurationStep = 10;
- private boolean mIsShown;
- public SwipeListView(Context context) {
- this(context,null);
- }
- public SwipeListView(Context context, AttributeSet attrs) {
- this(context, attrs,0);
- }
- public SwipeListView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- TypedArray mTypedArray = context.obtainStyledAttributes(attrs,
- R.styleable.swipelistviewstyle);
- //获取自定义属性和默认值
- mRightViewWidth = (int) mTypedArray.getDimension(R.styleable.swipelistviewstyle_right_width, 200);
- mTypedArray.recycle();
- }
- /**
- * return true, deliver to listView. return false, deliver to child. if
- * move, return true
- */
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- float lastX = ev.getX();
- float lastY = ev.getY();
- switch (ev.getAction()) {
- case MotionEvent.ACTION_DOWN:
- mIsHorizontal = null;
- System.out.println("onInterceptTouchEvent----->ACTION_DOWN");
- mFirstX = lastX;
- mFirstY = lastY;
- int motionPosition = pointToPosition((int)mFirstX, (int)mFirstY);
- if (motionPosition >= 0) {
- View currentItemView = getChildAt(motionPosition - getFirstVisiblePosition());
- mPreItemView = mCurrentItemView;
- mCurrentItemView = currentItemView;
- }
- break;
- case MotionEvent.ACTION_MOVE:
- float dx = lastX - mFirstX;
- float dy = lastY - mFirstY;
- if (Math.abs(dx) >= 5 && Math.abs(dy) >= 5) {
- return true;
- }
- break;
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
- System.out.println("onInterceptTouchEvent----->ACTION_UP");
- if (mIsShown && (mPreItemView != mCurrentItemView || isHitCurItemLeft(lastX))) {
- System.out.println("1---> hiddenRight");
- /**
- * 情况一:
- *
- * 一个Item的右边布局已经显示,
- *
- * 这时候点击任意一个item, 那么那个右边布局显示的item隐藏其右边布局
- */
- hiddenRight(mPreItemView);
- }
- break;
- }
- return super.onInterceptTouchEvent(ev);
- }
- private boolean isHitCurItemLeft(float x) {
- return x < getWidth() - mRightViewWidth;
- }
- /**
- * @param dx
- * @param dy
- * @return judge if can judge scroll direction
- */
- private boolean judgeScrollDirection(float dx, float dy) {
- boolean canJudge = true;
- if (Math.abs(dx) > 30 && Math.abs(dx) > 2 * Math.abs(dy)) {
- mIsHorizontal = true;
- System.out.println("mIsHorizontal---->" + mIsHorizontal);
- } else if (Math.abs(dy) > 30 && Math.abs(dy) > 2 * Math.abs(dx)) {
- mIsHorizontal = false;
- System.out.println("mIsHorizontal---->" + mIsHorizontal);
- } else {
- canJudge = false;
- }
- return canJudge;
- }
- /**
- * return false, can't move any direction. return true, cant't move
- * vertical, can move horizontal. return super.onTouchEvent(ev), can move
- * both.
- */
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- float lastX = ev.getX();
- float lastY = ev.getY();
- switch (ev.getAction()) {
- case MotionEvent.ACTION_DOWN:
- System.out.println("---->ACTION_DOWN");
- break;
- case MotionEvent.ACTION_MOVE:
- float dx = lastX - mFirstX;
- float dy = lastY - mFirstY;
- // confirm is scroll direction
- if (mIsHorizontal == null) {
- if (!judgeScrollDirection(dx, dy)) {
- break;
- }
- }
- if (mIsHorizontal) {
- if (mIsShown && mPreItemView != mCurrentItemView) {
- System.out.println("2---> hiddenRight");
- /**
- * 情况二:
- * 【Android 仿微信对话列表滑动删除效果】
- * 一个Item的右边布局已经显示,
- *
- * 这时候左右滑动另外一个item,那个右边布局显示的item隐藏其右边布局
- *
- * 向左滑动只触发该情况,向右滑动还会触发情况五
- */
- hiddenRight(mPreItemView);
- }
- if (mIsShown && mPreItemView == mCurrentItemView) {
- dx = dx - mRightViewWidth;
- System.out.println("======dx " + dx);
- }
- // can't move beyond boundary
- if (dx < 0 && dx > -mRightViewWidth) {
- mCurrentItemView.scrollTo((int)(-dx), 0);
- }
- return true;
- } else {
- if (mIsShown) {
- System.out.println("3---> hiddenRight");
- /**
- * 情况三:
- *
- * 一个Item的右边布局已经显示,
- *
- * 这时候上下滚动ListView,那么那个右边布局显示的item隐藏其右边布局
- */
- hiddenRight(mPreItemView);
- }
- }
- break;
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
- System.out.println("============ACTION_UP");
- clearPressedState();
- if (mIsShown) {
- System.out.println("4---> hiddenRight");
- /**
- * 情况四:
- *
- * 一个Item的右边布局已经显示,
- *
- * 这时候左右滑动当前一个item,那个右边布局显示的item隐藏其右边布局
- */
- hiddenRight(mPreItemView);
- }
- if (mIsHorizontal != null && mIsHorizontal) {
- if (mFirstX - lastX > mRightViewWidth / 2) {
- showRight(mCurrentItemView);
- } else {
- System.out.println("5---> hiddenRight");
- /**
- * 情况五:
- *
- * 向右滑动一个item,且滑动的距离超过了右边View的宽度的一半,隐藏之。
- */
- hiddenRight(mCurrentItemView);
- }
- return true;
- }
- break;
- }
- return super.onTouchEvent(ev);
- }
- private void clearPressedState() {
- // TODO current item is still has background, issue
- mCurrentItemView.setPressed(false);
- setPressed(false);
- refreshDrawableState();
- // invalidate();
- }
- private void showRight(View view) {
- System.out.println("=========showRight");
- Message msg = new MoveHandler().obtainMessage();
- msg.obj = view;
- msg.arg1 = view.getScrollX();
- msg.arg2 = mRightViewWidth;
- msg.sendToTarget();
- mIsShown = true;
- }
- private void hiddenRight(View view) {
- System.out.println("=========hiddenRight");
- if (mCurrentItemView == null) {
- return;
- }
- Message msg = new MoveHandler().obtainMessage(); //
- msg.obj = view;
- msg.arg1 = view.getScrollX();
- msg.arg2 = 0;
- msg.sendToTarget();
- mIsShown = false;
- }
- /**
- * show or hide right layout animation
- */
- @SuppressLint("HandlerLeak")
- class MoveHandler extends Handler {
- int stepX = 0;
- int fromX;
- int toX;
- View view;
- private boolean mIsInAnimation = false;
- private void animatioOver() {
- mIsInAnimation = false;
- stepX = 0;
- }
- @Override
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
- if (stepX == 0) {
- if (mIsInAnimation) {
- return;
- }
- mIsInAnimation = true;
- view = (View)msg.obj;
- fromX = msg.arg1;
- toX = msg.arg2;
- stepX = (int)((toX - fromX) * mDurationStep * 1.0 / mDuration);
- if (stepX < 0 && stepX > -1) {
- stepX = -1;
- } else if (stepX > 0 && stepX < 1) {
- stepX = 1;
- }
- if (Math.abs(toX - fromX) < 10) {
- view.scrollTo(toX, 0);
- animatioOver();
- return;
- }
- }
- fromX += stepX;
- boolean isLastStep = (stepX > 0 && fromX > toX) || (stepX < 0 && fromX < toX);
- if (isLastStep) {
- fromX = toX;
- }
- view.scrollTo(fromX, 0);
- invalidate();
- if (!isLastStep) {
- this.sendEmptyMessageDelayed(0, mDurationStep);
- } else {
- animatioOver();
- }
- }
- }
- public int getRightViewWidth() {
- return mRightViewWidth;
- }
- public void setRightViewWidth(int mRightViewWidth) {
- this.mRightViewWidth = mRightViewWidth;
- }
- }
github上有另一个项目47deg / android-swipelistview,项目地址:https://github.com/47deg/android-swipelistview,效果如下:
Demo下载地址:http://download.csdn.net/detail/fx_sky/6820665
------------------------------------------------------------
Demo中SwipeAdapter源码中有一处由于粗心写错了,会导致向下滑动时出现数组越界异常,现更正如下:
[java] view plain copy
- @Override
- public int getCount() {
- //return 100;
- return data.size();
- }