Android仿微信对话列表滑动删除效果
程序员文章站
2024-03-06 17:43:14
微信对话列表滑动删除效果很不错的,借鉴了github上swipelistview(项目地址:https://github.com/likebamboo/swipelistv...
微信对话列表滑动删除效果很不错的,借鉴了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代码:
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微信开发教程汇总》,欢迎大家学习阅读。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。