软件编程
位置:首页>> 软件编程>> Android编程>> Android仿微信对话列表滑动删除效果

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

作者:FX_SKY  发布时间:2023-04-15 13:22:30 

标签:android,微信,滑动

微信对话列表滑动删除效果很不错的,借鉴了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即可。

运行效果如下

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

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

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

下面是最核心的部分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
*/
@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");
 /**
 * 情况一:
 * <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.
*/
@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");
 /**
 * 情况二:
 * <p>
 * 一个Item的右边布局已经显示,
 * <p>
 * 这时候左右滑动另外一个item,那个右边布局显示的item隐藏其右边布局
 * <p>
 * 向左滑动只触发该情况,向右滑动还会触 * 况五
 */
 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");
 /**
 * 情况三:
 * <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, 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;
}
}

Demo下载地址:http://xiazai.jb51.net/201608/yuanma/SwipeListView(jb51.net).rar

Demo中SwipeAdapter源码中有一处由于粗心写错了,会导致向下滑动时出现数组越界异常,现更正如下:


@Override
public int getCount() {
// return 100;
return data.size();
}

本文已被整理到了《Android微信开发教程汇总》,欢迎大家学习阅读。

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com