Android SwipeMenuListView框架详解分析
周末 特地把android swipemenulistview(滑动菜单)的知识资料整理一番,以下是整理内容:
swipemenulistview(滑动菜单)
a swipe menu for listview.--一个非常好的滑动菜单开源项目。
demo
一、简介
看了挺长时间的自定义view和事件分发,想找一个项目练习下。。正好印证自己所学。
在github上找到了这个项目:swipemenulistview这的真不错,对事件分发和自定义view都很有启发性,虽然还有点小瑕疵,后面说明。想了解滑动菜单怎么实现的同学,这篇文章绝对对你有帮助,从宏观微观角度详细分析了每个文件。
项目地址:https://github.com/baoyongzhang/swipemenulistview/tree/b00e0fe8c2b8d6f08607bfe2ab390c7cee8df274 版本:b00e0fe 它的使用很简单只需要三步,在github上就可以看懂就不占用篇幅啦,本文只分析原理。另外如果你看代码感觉和我不一样,看着困难的话,可以看我加了注释的:http://download.csdn.net/detail/jycboy/9667699
先看两个图:有一个大体的了解
这是框架中所有的类。
1.下面的图是视图层次:
上面的图中:swipemenulayout是listview中item的布局,分左右两部分,一部分是正常显示的contentview,一部分是滑出来的menuview;滑出来的swipemenuview继承自linearlayout,添加view时,就是横向添加,可以横向添加多个。
2.下面的图是类图结构:
上面是类之间的调用关系,类旁边注明了类的主要作用。
二、源码分析
swipemenu、swipemenuitem是实体类,定义了属性和setter、getter方法,看下就行。基本上源码的注释很清楚。
2.1 swipemenuview: 代码中注释的很清楚
/** * 横向的linearlayout,就是整个swipemenu的父布局 * 主要定义了添加item的方法及item的属性设置 * @author baoyz * @date 2014-8-23 * */ public class swipemenuview extends linearlayout implements onclicklistener { private swipemenulistview mlistview; private swipemenulayout mlayout; private swipemenu mmenu; private onswipeitemclicklistener onitemclicklistener; private int position; public int getposition() { return position; } public void setposition(int position) { this.position = position; } public swipemenuview(swipemenu menu, swipemenulistview listview) { super(menu.getcontext()); mlistview = listview; mmenu = menu; // // menuitem的list集合 list<swipemenuitem> items = menu.getmenuitems(); int id = 0; //通过item构造出view添加到swipemenuview中 for (swipemenuitem item : items) { additem(item, id++); } } /** * 将 menuitem 转换成 ui控件,一个item就相当于一个垂直的linearlayout, * swipemenuview就是横向的linearlayout, */ private void additem(swipemenuitem item, int id) { //布局参数 layoutparams params = new layoutparams(item.getwidth(), layoutparams.match_parent); linearlayout parent = new linearlayout(getcontext()); //设置menuitem的id,用于后边的点击事件区分item用的 parent.setid(id); parent.setgravity(gravity.center); parent.setorientation(linearlayout.vertical); parent.setlayoutparams(params); parent.setbackgrounddrawable(item.getbackground()); //设置监听器 parent.setonclicklistener(this); addview(parent); //加入到swipemenuview中,横向的 if (item.geticon() != null) { parent.addview(createicon(item)); } if (!textutils.isempty(item.gettitle())) { parent.addview(createtitle(item)); } } //创建img private imageview createicon(swipemenuitem item) { imageview iv = new imageview(getcontext()); iv.setimagedrawable(item.geticon()); return iv; } /*根据参数创建title */ private textview createtitle(swipemenuitem item) { textview tv = new textview(getcontext()); tv.settext(item.gettitle()); tv.setgravity(gravity.center); tv.settextsize(item.gettitlesize()); tv.settextcolor(item.gettitlecolor()); return tv; } @override /** * 用传来的mlayout判断是否打开 * 调用onitemclick点击事件 */ public void onclick(view v) { if (onitemclicklistener != null && mlayout.isopen()) { onitemclicklistener.onitemclick(this, mmenu, v.getid()); } } public onswipeitemclicklistener getonswipeitemclicklistener() { return onitemclicklistener; } /** * 设置item的点击事件 * @param onitemclicklistener */ public void setonswipeitemclicklistener(onswipeitemclicklistener onitemclicklistener) { this.onitemclicklistener = onitemclicklistener; } public void setlayout(swipemenulayout mlayout) { this.mlayout = mlayout; } /** * 点击事件的回调接口 */ public static interface onswipeitemclicklistener { /** * onclick点击事件中调用onitemclick * @param view 父布局 * @param menu menu实体类 * @param index menuitem的id */ void onitemclick(swipemenuview view, swipemenu menu, int index); } }
**swipemenuview就是滑动时显示的view,看他的构造函数swipemenuview(swipemenu menu, swipemenulistview listview);遍历items:menu.getmenuitems();调用additem方法向swipemenuview中添加item。
在additem方法中:每一个item都是一个linearlayout。
2.2 swipemenulayout:
这个类代码有点长,我们分成三部分看,只粘贴核心代码,剩下的看一下应该就懂啦。
public class swipemenulayout extends framelayout { private static final int content_view_id = 1; private static final int menu_view_id = 2; private static final int state_close = 0; private static final int state_open = 1; //方向 private int mswipedirection; private view mcontentview; private swipemenuview mmenuview; 。。。。。 public swipemenulayout(view contentview, swipemenuview menuview) { this(contentview, menuview, null, null); } public swipemenulayout(view contentview, swipemenuview menuview, interpolator closeinterpolator, interpolator openinterpolator) { super(contentview.getcontext()); mcloseinterpolator = closeinterpolator; mopeninterpolator = openinterpolator; mcontentview = contentview; mmenuview = menuview; //将swipemenulayout设置给swipemenuview,用于判断是否打开 mmenuview.setlayout(this); init(); } private void init() { setlayoutparams(new abslistview.layoutparams(layoutparams.match_parent, layoutparams.wrap_content)); mgesturelistener = new simpleongesturelistener() { @override public boolean ondown(motionevent e) { isfling = false; return true; } @override //velocityx这个参数是x轴方向的速率,向左是负的,向右是正的 public boolean onfling(motionevent e1, motionevent e2, float velocityx, float velocityy) { // todo if (math.abs(e1.getx() - e2.getx()) > min_fling && velocityx < max_velocityx) { isfling = true; } log.i("tag","isfling="+isfling+" e1.getx()="+e1.getx()+" e2.getx()="+e2.getx()+ " velocityx="+velocityx+" max_velocityx="+max_velocityx); // log.i("byz", max_velocityx + ", velocityx = " + velocityx); return super.onfling(e1, e2, velocityx, velocityy); } }; mgesturedetector = new gesturedetectorcompat(getcontext(), mgesturelistener); 。。。。 layoutparams contentparams = new layoutparams( layoutparams.match_parent, layoutparams.wrap_content); mcontentview.setlayoutparams(contentparams); if (mcontentview.getid() < 1) { //noinspection resourcetype mcontentview.setid(content_view_id); } //noinspection resourcetype mmenuview.setid(menu_view_id); mmenuview.setlayoutparams(new layoutparams(layoutparams.wrap_content, layoutparams.wrap_content)); addview(mcontentview); addview(mmenuview); }
从上边的init方法中可以看出swipemenulayout由两部分组成,分别是用户的 item view 和 menu view 。手指的时候滑动的操作是通过 simpleongesturelistener
来完成的。
/** * 滑动事件,用于外边调用的接口 * 这是一个对外暴露的api,而调用这个api的是swipemenulistview,那么motionevent是swipemenulistview的motionevent * @param event * @return */ public boolean onswipe(motionevent event) { mgesturedetector.ontouchevent(event); switch (event.getaction()) { case motionevent.action_down: mdownx = (int) event.getx();//记下点击的x坐标 isfling = false; break; case motionevent.action_move: // log.i("byz", "downx = " + mdownx + ", movex = " + event.getx()); int dis = (int) (mdownx - event.getx()); if (state == state_open) {//当状态是open时,dis就是0 log.i("tag", "dis = " + dis);//这个值一直是0 //direction_left = 1 || direction_right = -1 dis += mmenuview.getwidth()*mswipedirection;//mswipedirection=1 log.i("tag", "dis = " + dis + ", mswipedirection = " + mswipedirection); } log.i("tag", "action_move downx = " + mdownx + ", movex = " + event.getx()+", dis="+dis); swipe(dis); break; case motionevent.action_up: //判断滑动距离,是打开还是关闭 //在这里,如果已经有一个item打开了,此时滑动另外的一个item,还是执行这个方法,怎么改进? if ((isfling || math.abs(mdownx - event.getx()) > (mmenuview.getwidth() / 2)) && math.signum(mdownx - event.getx()) == mswipedirection) { log.i("tag", "action_up downx = " + mdownx + ", movex = " + event.getx()); // open smoothopenmenu(); } else { // close smoothclosemenu(); return false; } break; } return true; } public boolean isopen() { return state == state_open; } /** * 滑动dis的距离,把mcontentview和mmenuview都滑动dis距离 * @param dis */ private void swipe(int dis) { if(!mswipenable){ return ; } //left is positive;right is negative if (math.signum(dis) != mswipedirection) {//left=1;right =-1 dis = 0; //不滑动 } else if (math.abs(dis) > mmenuview.getwidth()) {//大于它的宽度,dis就是mmenuview.getwidth() dis = mmenuview.getwidth()*mswipedirection; } //重新设置布局,不断左移(或者右移), mcontentview.layout(-dis, mcontentview.gettop(), mcontentview.getwidth() -dis, getmeasuredheight()); if (mswipedirection == swipemenulistview.direction_left) {//1 //同上重新设置menuview的布局,画图很清晰 mmenuview.layout(mcontentview.getwidth() - dis, mmenuview.gettop(), mcontentview.getwidth() + mmenuview.getwidth() - dis, mmenuview.getbottom()); } else { mmenuview.layout(-mmenuview.getwidth() - dis, mmenuview.gettop(), - dis, mmenuview.getbottom()); } } /** * 更新状态state = state_close; * 关闭menu */ public void smoothclosemenu() { state = state_close; if (mswipedirection == swipemenulistview.direction_left) { mbasex = -mcontentview.getleft(); //滑动mmenuview.getwidth()的距离,正好隐藏掉 mclosescroller.startscroll(0, 0, mmenuview.getwidth(), 0, 350); } else { mbasex = mmenuview.getright(); mclosescroller.startscroll(0, 0, mmenuview.getwidth(), 0, 350); } postinvalidate(); } public void smoothopenmenu() { if(!mswipenable){ return ; } state = state_open; if (mswipedirection == swipemenulistview.direction_left) { mopenscroller.startscroll(-mcontentview.getleft(), 0, mmenuview.getwidth(), 0, 350); log.i("tag","mcontentview.getleft()="+mcontentview.getleft()+", mmenuview="+mmenuview.getwidth());//-451,就是移动的距离dis,-(downx-movex) //mcontentview.getleft()=-540, mmenuview=540 ,这俩的绝对值是相等的,完全正确!哈哈· } else { mopenscroller.startscroll(mcontentview.getleft(), 0, mmenuview.getwidth(), 0, 350); } //在非ui thread中调用这个方法,使视图重绘 postinvalidate(); } 。。。 }
上面主要的方法是onswipe和swipe这两个方法,主要逻辑是:onswipe是暴漏给外面调用的api,
在swipemenulistview的ontouchevent事件处理方法中调用了onswipe;而swipe就是把mcontentview和mmenuview都滑动dis距离。
protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { super.onmeasure(widthmeasurespec, heightmeasurespec); //宽度是无限扩展的,高度是指定的 mmenuview.measure(measurespec.makemeasurespec(0, measurespec.unspecified), measurespec.makemeasurespec( getmeasuredheight(), measurespec.exactly)); } protected void onlayout(boolean changed, int l, int t, int r, int b) { mcontentview.layout(0, 0, getmeasuredwidth(), mcontentview.getmeasuredheight()); if (mswipedirection == swipemenulistview.direction_left) {//左滑 //相对于父view,以左边和上边为基准,隐藏在右边 mmenuview.layout(getmeasuredwidth(), 0, getmeasuredwidth() + mmenuview.getmeasuredwidth(), mcontentview.getmeasuredheight()); } else { //右滑,隐藏在左边 mmenuview.layout(-mmenuview.getmeasuredwidth(), 0, 0, mcontentview.getmeasuredheight()); } }
上面的onmeasure、onlayout方法就是自定义view中经常重写的方法,在onmeasure是测量view的大小,这里把宽度类型设置为unspecified,可以无限扩展。 onlayout是在view的大小测量之后,把view放到父布局的什么位置,代码里可以看出根据滑动方向吧menuview隐藏在左边(或右边)。
2.3 swipemenuadapter
public class swipemenuadapter implements wrapperlistadapter, onswipeitemclicklistener { private listadapter madapter; private context mcontext; private swipemenulistview.onmenuitemclicklistener onmenuitemclicklistener; public swipemenuadapter(context context, listadapter adapter) { madapter = adapter; mcontext = context; } 。。。。 /** * 添加滑动时的显示的菜单 * 在这里可以看出每一个item都是一个swipemenulayout */ public view getview(int position, view convertview, viewgroup parent) { swipemenulayout layout = null; if (convertview == null) { view contentview = madapter.getview(position, convertview, parent);//item的view swipemenu menu = new swipemenu(mcontext); //创建swipemenu menu.setviewtype(getitemviewtype(position)); createmenu(menu); //测试的,可以先不管 swipemenuview menuview = new swipemenuview(menu, (swipemenulistview) parent); menuview.setonswipeitemclicklistener(this); swipemenulistview listview = (swipemenulistview) parent; layout = new swipemenulayout(contentview, menuview, listview.getcloseinterpolator(), listview.getopeninterpolator()); layout.setposition(position); } else { layout = (swipemenulayout) convertview; layout.closemenu(); layout.setposition(position); view view = madapter.getview(position, layout.getcontentview(), parent); } if (madapter instanceof baseswiplistadapter) { boolean swipenable = (((baseswiplistadapter) madapter).getswipenablebyposition(position)); layout.setswipenable(swipenable); } return layout; } //这个方法在创建时,重写啦,在这里是测试的,可以不管。 public void createmenu(swipemenu menu) { // test code 。。。。。。 } /** * onswipeitemclicklistener的回掉方法 * 这个方法在该类创建时,重写啦。 */ public void onitemclick(swipemenuview view, swipemenu menu, int index) { if (onmenuitemclicklistener != null) { onmenuitemclicklistener.onmenuitemclick(view.getposition(), menu, index); } } 。。。。//省略了不重要的 }
2.4 核心类:swipemenulistview,
这个代码很长,看的时候需要耐心。
public class swipemenulistview extends 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; public static final int direction_left = 1; //方向 public static final int direction_right = -1; private int mdirection = 1;//swipe from right to left by default private int max_y = 5; private int max_x = 3; private float mdownx; private float mdowny; private int mtouchstate; private int mtouchposition; private swipemenulayout mtouchview; private onswipelistener monswipelistener; //创建menuitem的 private swipemenucreator mmenucreator; //menuitem的item点击事件 private onmenuitemclicklistener monmenuitemclicklistener; private onmenustatechangelistener monmenustatechangelistener; private interpolator mcloseinterpolator; //动画变化率 private interpolator mopeninterpolator; //----added in myself--下面这两行是我自己加的, //你如果下下来代码demo运行下你会发现,当一个item已经滑开时,滑动另外的item,此时原来打开的item没有关闭,可以看下qq的侧滑,它是关闭的,我这里就稍微修改了下。 private int moldtouchposition = -1; private boolean shouldclosemenu; //-------- public swipemenulistview(context context) { super(context); init(); } public swipemenulistview(context context, attributeset attrs, int defstyle) { super(context, attrs, defstyle); init(); } public swipemenulistview(context context, attributeset attrs) { super(context, attrs); init(); } //初始化变量 private void init() { max_x = dp2px(max_x); max_y = dp2px(max_y); mtouchstate = touch_state_none; } @override /** * 对参数adapter进行了一次包装,包装成swipemenuadapter */ public void setadapter(listadapter adapter) { super.setadapter(new swipemenuadapter(getcontext(), adapter) { @override public void createmenu(swipemenu menu) { if (mmenucreator != null) { mmenucreator.create(menu); } } @override public void onitemclick(swipemenuview view, swipemenu menu, int index) { boolean flag = false; if (monmenuitemclicklistener != null) { flag = monmenuitemclicklistener.onmenuitemclick( view.getposition(), menu, index); } //再次点击list中的item关闭menu if (mtouchview != null && !flag) { mtouchview.smoothclosemenu(); } } }); } 。。。。。 @override //拦截事件,判断事件是点击事件还是滑动事件 public boolean onintercepttouchevent(motionevent ev) { //在拦截处处理,在滑动设置了点击事件的地方也能swip,点击时又不能影响原来的点击事件 int action = ev.getaction(); switch (action) { case motionevent.action_down: mdownx = ev.getx(); mdowny = ev.gety(); boolean handled = super.onintercepttouchevent(ev); mtouchstate = touch_state_none; //每次down都把状态变为无状态 //返回item的position mtouchposition = pointtoposition((int) ev.getx(), (int) ev.gety()); //得到那个点击的item对应的view,就是swipemenulayout view view = getchildat(mtouchposition - getfirstvisibleposition()); //只在空的时候赋值 以免每次触摸都赋值,会有多个open状态 if (view instanceof swipemenulayout) { //如果有打开了 就拦截.mtouchview是swipemenulayout //如果两次是一个mtouchview,更新mtouchview;如果不是一个view,就拦截返回true if (mtouchview != null && mtouchview.isopen() && !inrangeofview(mtouchview.getmenuview(), ev)) { log.i("tag","listview中的onintercepttouchevent action_down。"); return true; } mtouchview = (swipemenulayout) view; mtouchview.setswipedirection(mdirection);//默认是left=1 } //如果摸在另外一个view,拦截此事件 if (mtouchview != null && mtouchview.isopen() && view != mtouchview) { handled = true; } if (mtouchview != null) { mtouchview.onswipe(ev); } return handled; case motionevent.action_move: //move时拦截事件,在ontouch中进行处理 float dy = math.abs((ev.gety() - mdowny)); float dx = math.abs((ev.getx() - mdownx)); if (math.abs(dy) > max_y || math.abs(dx) > max_x) { //每次拦截的down都把触摸状态设置成了touch_state_none 只有返回true才会走ontouchevent 所以写在这里就够了 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); } } } return true; } } return super.onintercepttouchevent(ev); } @override public boolean ontouchevent(motionevent ev) { if (ev.getaction() != motionevent.action_down && mtouchview == null) return super.ontouchevent(ev); int action = ev.getaction(); switch (action) { case motionevent.action_down: //这个down事件的前提是已经拦截事件啦,所以可能的情况时:1.该menu已经滑出来,再点击左边的item区域 //2.menu已经滑出来,点击了其他的item //3.滑动item时,先down在move log.i("tag","listview中的ontouchevent action_down。是否点击了另一个item"); int oldpos = mtouchposition; //这里设计不合理,onintercepttouchevent之后直接调用的这个事件,mtouchposition是一样的 if(moldtouchposition == -1){//-1 is the original value moldtouchposition = mtouchposition; } mdownx = ev.getx(); mdowny = ev.gety(); mtouchstate = touch_state_none; mtouchposition = pointtoposition((int) ev.getx(), (int) ev.gety());//list中 //这里改了,pldpos没有用,改为moldtouchposition if (mtouchposition == moldtouchposition && mtouchview != null && mtouchview.isopen()) { mtouchstate = touch_state_x; //x方向(横着)滑开 //调用swipemenulayout的onswipe()事件接口 mtouchview.onswipe(ev); log.i("tag","listview中的ontouchevent action_down。滑动了或点击了另一个item"); return true; } if(moldtouchposition != mtouchposition){ //when the down position is different //shouldclosemenu = true; moldtouchposition = mtouchposition; } view view = getchildat(mtouchposition - getfirstvisibleposition()); //已经有一个menu滑开了,此时如果点击了另一个item //这个方法永远执行不到! if (mtouchview != null && mtouchview.isopen()) { //关闭swipemenu mtouchview.smoothclosemenu(); mtouchview = null; // return super.ontouchevent(ev); // try to cancel the touch event motionevent cancelevent = motionevent.obtain(ev); cancelevent.setaction(motionevent.action_cancel); ontouchevent(cancelevent); //取消事件,时间结束 //进行menu close的回掉 if (monmenustatechangelistener != null) { monmenustatechangelistener.onmenuclose(oldpos); } return true; } if (view instanceof swipemenulayout) { mtouchview = (swipemenulayout) view; mtouchview.setswipedirection(mdirection); } if (mtouchview != null) { mtouchview.onswipe(ev); } break; case motionevent.action_move: //有些可能有header,要减去header再判断 mtouchposition = pointtoposition((int) ev.getx(), (int) ev.gety()) - getheaderviewscount(); //如果滑动了一下没完全展现,就收回去,这时候mtouchview已经赋值,再滑动另外一个不可以swip的view //会导致mtouchview swip 。 所以要用位置判断是否滑动的是一个view if (!mtouchview.getswipenable() || mtouchposition != mtouchview.getposition()) { break; } float dy = math.abs((ev.gety() - mdowny)); float dx = math.abs((ev.getx() - mdownx)); if (mtouchstate == touch_state_x) { //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) {//down事件后的move 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: //关闭了menu log.i("tag","ontouchevent事件的action_up"); if (mtouchstate == touch_state_x) { if (mtouchview != null) { log.i("tag","ontouchevent事件的action_up 为什么没有关闭"); boolean isbeforeopen = mtouchview.isopen(); //调用滑动事件 mtouchview.onswipe(ev); boolean isafteropen = mtouchview.isopen(); if (isbeforeopen != isafteropen && monmenustatechangelistener != null) { if (isafteropen) { monmenustatechangelistener.onmenuopen(mtouchposition); } else { monmenustatechangelistener.onmenuclose(mtouchposition); } } if (!isafteropen) { 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 swipemenulayout) { mtouchposition = position; if (mtouchview != null && mtouchview.isopen()) { mtouchview.smoothclosemenu(); } mtouchview = (swipemenulayout) view; mtouchview.setswipedirection(mdirection); mtouchview.smoothopenmenu(); } } } /** * 可以进去看源代码,就是将不同的单位统一转换成像素px,这里是dp->px * @param dp * @return */ private int dp2px(int dp) { return (int) typedvalue.applydimension(typedvalue.complex_unit_dip, dp, getcontext().getresources().getdisplaymetrics()); } public static interface onmenuitemclicklistener { boolean onmenuitemclick(int position, swipemenu menu, int index); } public static interface onswipelistener { void onswipestart(int position); void onswipeend(int position); } public static interface onmenustatechangelistener { void onmenuopen(int position); void onmenuclose(int position); } 。。。。 }
这个类中最重要的逻辑就是关于事件的判断和分发,什么时候拦截事件,不同的事件对应什么操作。如果对事件分发不清楚的同学,可以在网上找找相关的博客,也可以看我的后续博客,应该这两天的事。
在这里分析swipemenulistview的事件分发逻辑:核心就是swipemenulistview中item的点击事件和滑动事件的处理。当滑动时swipemenulistview拦截事件,自己处理,记住这个逻辑看代码就一目了然了。下面是我画的一个事件分发流程图:
触摸事件是一个事件序列:action_down->action_move->....action_move->action_up. 以action_down开始,以action_up结束。
下边是我的一个打印的流程:(自己在代码中加log)
i/tag: listview中的onintercepttouchevent action_down。view=class com.baoyz.swipemenulistview.swipemenulayout i/tag: onintercepttouchevent action_down handled=false i/tag: swipemenulayout ontouchevent i/tag: listview中的ontouchevent action_down。是否点击了另一个item i/tag: oldpos=1 mtouchposition=1 i/tag: action_move downx = 987, movex = 906.69666, dis=80 i/tag: action_move downx = 987, movex = 855.5785, dis=131 i/tag: action_move downx = 987, movex = 797.6258, dis=189 i/tag: action_move downx = 987, movex = 735.9639, dis=251 i/tag: action_move downx = 987, movex = 666.5104, dis=320 i/tag: action_move downx = 987, movex = 589.0626, dis=397 i/tag: action_move downx = 987, movex = 509.15567, dis=477 i/tag: action_move downx = 987, movex = 431.7224, dis=555 i/tag: action_move downx = 987, movex = 361.2613, dis=625 i/tag: action_move downx = 987, movex = 319.70398, dis=667 i/tag: ontouchevent事件的action_up i/tag: ontouchevent事件的action_up 为什么没有关闭 i/tag: isfling=true e1.getx()=987.08606 e2.getx()=319.70398 velocityx=-4122.911 max_velocityx=-1500 i/tag: action_up downx = 987, movex = 319.70398 i/tag: mcontentview.getleft()=-540, mmenuview=540
三、存在的问题
1.如果你下下来框架运行了,你会发现一个问题:
当listview的一个item已经滑开,假设为item1;此时滑动另外一个的item,叫它item2;
这种情况下item1不会关闭,item2当然也不会打开。
这种效果并不好,我在代码中已经修改了这个问题。具体代码,我已经标明。
2.就是下面的这段代码:在swipemenulistview的ontouchevent(motionevent ev)的action_down中,这段代码永远不会执行到,因为ontouchevent和onintercepttouchevent对应的一个motionevent。
mtouchposition ==oldpos永远相等。
//这个方法永远执行不到!作者的愿意是当mtouchposition != oldpos时closemenu,但是按照这个代码这两个值是永远相等的, //因为对应的是一个motionevent当然就相等啦 if (mtouchview != null && mtouchview.isopen()) { //关闭swipemenu mtouchview.smoothclosemenu(); //mtouchview = null; // return super.ontouchevent(ev); // try to cancel the touch event motionevent cancelevent = motionevent.obtain(ev); cancelevent.setaction(motionevent.action_cancel); ontouchevent(cancelevent); //取消事件,时间结束 //进行menu close的回掉 if (monmenustatechangelistener != null) { monmenustatechangelistener.onmenuclose(oldpos); } return true; }
在代码中我已经修改了这个问题。目前已经在github上提交给原作者啦。
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!