欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android实现滑动选择控件实例代码

程序员文章站 2022-06-20 22:51:22
前言 最近做了个滑动选择的小控件,拿出来给大家分享一下,先上图 运行效果 实现步骤 这里分解为3个动作:down、move、up来进行分析,博主文采不好,大...

前言

最近做了个滑动选择的小控件,拿出来给大家分享一下,先上图

运行效果

Android实现滑动选择控件实例代码

实现步骤

这里分解为3个动作:down、move、up来进行分析,博主文采不好,大家直接看流程图吧!!

Android实现滑动选择控件实例代码

Android实现滑动选择控件实例代码

Android实现滑动选择控件实例代码

代码分析

前置知识

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();
        }
      }

    }
  }

项目源码:scrollcheckbox_jb51.rar

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。