Android实现滑动选择控件实例代码
程序员文章站
2022-06-20 22:51:22
前言
最近做了个滑动选择的小控件,拿出来给大家分享一下,先上图
运行效果
实现步骤
这里分解为3个动作:down、move、up来进行分析,博主文采不好,大...
前言
最近做了个滑动选择的小控件,拿出来给大家分享一下,先上图
运行效果
实现步骤
这里分解为3个动作:down、move、up来进行分析,博主文采不好,大家直接看流程图吧!!
代码分析
前置知识
1、这个地方使用的是recyclerview的代码,使用recyclerview只能使用linearlayoutmanager,listview的运行效果稍微要比recyclerview差一些
//这里使用dispatchtouchevent,因为ontouchevent容易被ontouchlistener截取 @override public boolean dispatchtouchevent(motionevent ev) { layoutmanager manager = getlayoutmanager(); //获取第一个和最后一个显示的item对应的相对position if (manager instanceof linearlayoutmanager) { mfirstvisibleposition = ((linearlayoutmanager) manager).findfirstvisibleitemposition(); mlastvisibleposition = ((linearlayoutmanager) manager).findlastvisibleitemposition(); } switch (ev.getaction()) { case motionevent.action_down: //获取按下时的位置,x,y int startx = (int) ev.getx(); int starty = (int) ev.gety(); int prex = startx; mprey = starty; mprefirstvisibleposition = mfirstvisibleposition; mpreposition = mstartposition = pointtoposition(startx, starty); if (mstartposition > -1) { //获取当前item的view view child = getchildat(mstartposition); if (null != child) { //获取响应域,一般响应域里面就是一个checkbox view tmpcheckboxcontainer = child.findviewwithtag("checkbox_layout"); if (null != tmpcheckboxcontainer && tmpcheckboxcontainer.getvisibility() == visible) { mcheckboxwidth = tmpcheckboxcontainer.getwidth(); //获取响应域的范围,一定要用这种获取绝对位置的方式,不然会受到padding或者是margin的影响 int[] location = new int[2]; tmpcheckboxcontainer.getlocationonscreen(location); mcheckboxx = location[0]; //判断按下的位置是否是在响应域内 if (startx >= mcheckboxx && startx <= (mcheckboxx + mcheckboxwidth)) { log.d(log_tag, "dispatchtouchevent() down mstartposition: " + mstartposition); //设置截取事件的标志位 misneedscrollcheck = true; //设置为第一次滑动,这是用作判断折返的 misfirstmove = true; setstartcheckboxstate(); //截获checkbox的点击事件,防止两次选中 return true; } else { misneedscrollcheck = false; } } else { misneedscrollcheck = false; log.e(log_tag, "dispatchtouchevent() ", new throwable("cannot get checkboxcontainer!")); } } else { log.e(log_tag, "dispatchtouchevent() ", new throwable("cannot get item view!")); } } break; case motionevent.action_move: //获取当前位置 int currentx = (int) ev.getx(); int currenty = (int) ev.gety(); //获取当前的item int currentposition = pointtoposition(currentx, currenty); //判断是否允许滑动选中 if (misneedscrollcheck && -1 != mfirstvisibleposition && -1 != mlastvisibleposition && -1 != currentposition) { //判断是否在下一个item的像英语 if ((currentposition + mfirstvisibleposition) != (mpreposition + mprefirstvisibleposition) && currentx >= mcheckboxx && currentx <= (mcheckboxx + mcheckboxwidth)) { log.i(log_tag, "********************************** dispatchtouchevent() ********************************"); log.d(log_tag, "dispatchtouchevent() move mcurrentposition: " + currentposition); log.d(log_tag, "dispatchtouchevent() move mfirstvisibleposition: " + mfirstvisibleposition); log.d(log_tag, "dispatchtouchevent() move mpreposition: " + mpreposition); log.d(log_tag, "dispatchtouchevent() move mprefirstvisibleposition: " + mprefirstvisibleposition); log.i(log_tag, "********************************** dispatchtouchevent() ********************************"); //折返回来时要改变前一个的checkbox的状态 if (misfirstmove) { misfirstmove = false; if (currenty >= mprey) { mupordown = false; } else { mupordown = true; } } else { if ((currentposition + mfirstvisibleposition) > (mpreposition + mprefirstvisibleposition) && mupordown) { changecheckboxstate(mpreposition); mupordown = false; } else if ((currentposition + mfirstvisibleposition) < (mpreposition + mprefirstvisibleposition) && !mupordown) { changecheckboxstate(mpreposition); mupordown = true; } } changecheckboxstate(currentposition); } //判断是否是在最后一个item上滑动,如果是则进行自动向下滑动,如果是在第一个上下滑动,则自动向上滑动 //log.d(log_tag, "dispatchtouchevent() move: " + (mlastvisibleposition - mcurrentposition - mfirstvisibleposition)); if ((mlastvisibleposition - mfirstvisibleposition - currentposition) < 1 && currenty > mprey) { //自动向下滑 log.d(log_tag, "dispatchtouchevent() move mcount: " + mcount); view child = getchildat(currentposition); if (null != child && 0 == mcount % 5) { scrolltoposition(mlastvisibleposition + 1); } mcount++; } else if (currentposition < 2 && currenty < mprey) { //自动向上滑 view child = getchildat(currentposition); log.d(log_tag, "dispatchtouchevent() move mcount: " + mcount); //mcount用于降低滑动的频率,频率太快容易滑动的看不清楚 if (null != child && 0 == mcount % 5) { scrolltoposition(mfirstvisibleposition - 1); } mcount++; } mprey = currenty; mpreposition = currentposition; mprefirstvisibleposition = mfirstvisibleposition; return true; } break; case motionevent.action_up: if (misneedscrollcheck) { mcount = 0; return false; } break; } return super.dispatchtouchevent(ev); }
其他的代码片段
//改变开始的checkbox状态 private void setstartcheckboxstate() { view child = getchildat(mstartposition); if (null != child) { viewgroup checkboxcontainer = (viewgroup) child.findviewwithtag("checkbox_layout"); if (null != checkboxcontainer) { checkbox checkbox = (checkbox) checkboxcontainer.getchildat(0); if (null != checkbox && checkbox.getvisibility() == visible) { checkbox.toggle(); } } } }
//判断当前item的position,相对位置 private int pointtoposition(int x, int y) { rect frame = mtouchframe; if (frame == null) { mtouchframe = new rect(); frame = mtouchframe; } final int count = getchildcount(); for (int i = count - 1; i >= 0; i--) { final view child = getchildat(i); if (child.getvisibility() == view.visible) { child.gethitrect(frame); if (frame.contains(x, y)) { return i; } } } return -1; }
//改变position的选中状态 public void changecheckboxstate(int position) { if (position < 0 || position >= getchildcount()) { return; } view child = getchildat(position); if (null != child) { viewgroup checkboxlayout = (viewgroup) child.findviewwithtag("checkbox_layout"); if (null != checkboxlayout && checkboxlayout.getvisibility() == visible) { checkbox checkbox = (checkbox) checkboxlayout.getchildat(0); if (null != checkbox) { log.d(log_tag, "changecheckboxstate() selectcheckbox: " + position); //checkbox.performclick(); checkbox.toggle(); //checkbox.setclickable(false); //checkbox.callonclick(); } } } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。