Android 仿微信对话列表滑动删除效果

微信对话列表滑动删除效果很不错的,借鉴了github上SwipeListView(项目地址:https://github.com/likebamboo/SwipeListView),在其上进行了一些重构,最终实现了微信对话列表滑动删除效果。

实现原理1.通过ListView的pointToPosition(int x, int y)来获取按下的position,然后通过android.view.ViewGroup.getChildAt(position)来得到滑动对象swipeView2.在onTouchEvent中计算要滑动的距离,调用swipeView.scrollTo即可。

运行效果如下

下面是最核心的部分SwipeListView代码:

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*/@Overridepublic 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");/*** 情况一:* <p>* 一个Item的右边布局已经显示,* <p>* 这时候点击任意一个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.*/@Overridepublic 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 directionif (mIsHorizontal == null) {if (!judgeScrollDirection(dx, dy)) {break;}}if (mIsHorizontal) {if (mIsShown && mPreItemView != mCurrentItemView) {System.out.println("2—> hiddenRight");/*** 情况二:* <p>* 一个Item的右边布局已经显示,* <p>* 这时候左右滑动另外一个item,那个右边布局显示的item隐藏其右边布局* <p>* 向左滑动只触发该情况,向右滑动还会触发情况五*/hiddenRight(mPreItemView);}if (mIsShown && mPreItemView == mCurrentItemView) {dx = dx – mRightViewWidth;System.out.println("======dx " + dx);}// can’t move beyond boundaryif (dx < 0 && dx > -mRightViewWidth) {mCurrentItemView.scrollTo((int)(-dx), 0);}return true;} else {if (mIsShown) {System.out.println("3—> hiddenRight");/*** 情况三:* <p>* 一个Item的右边布局已经显示,* <p>* 这时候上下滚动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");/*** 情况四:* <p>* 一个Item的右边布局已经显示,* <p>* 这时候左右滑动当前一个item,那个右边布局显示的item隐藏其右边布局*/hiddenRight(mPreItemView);}if (mIsHorizontal != null && mIsHorizontal) {if (mFirstX – lastX > mRightViewWidth / 2) {showRight(mCurrentItemView);} else {System.out.println("5—> hiddenRight");/*** 情况五:* <p>* 向右滑动一个item,且滑动的距离超过了右边View的宽度的一半,,隐藏之。*/hiddenRight(mCurrentItemView);}return true;}break;}return super.onTouchEvent(ev);}private void clearPressedState() {// TODO current item is still has background, issuemCurrentItemView.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;}@Overridepublic 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,效果如下:

一个人,一条路,人在途中,心随景动,

Android 仿微信对话列表滑动删除效果

相关文章:

你感兴趣的文章:

标签云: