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

作者:God_Of_Teen 时间:2022-04-13 14:17:31 

前言

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

运行效果

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

来源:http://www.jianshu.com/p/889355a87759#

标签:android,滑动,选择
0
投稿

猜你喜欢

  • spring基础概念AOP与动态代理理解

    2022-01-29 20:55:13
  • Java系统的高并发解决方法详解

    2021-08-23 08:39:50
  • C#使用Log4.net记录日志文件

    2022-12-05 04:01:47
  • Android实现通话自动录音

    2021-08-29 20:33:35
  • Java 获取当前系统时间的三种方法

    2023-11-21 12:51:51
  • Android开发中解析xml文件XmlUtils工具类与用法示例

    2023-03-26 01:05:45
  • springboot整合JSR303参数校验与全局异常处理的方法

    2023-10-06 01:31:40
  • Java如何获取对象属性及对应值

    2022-03-30 07:03:05
  • SpringBoot Java后端实现okhttp3超时设置的方法实例

    2022-11-06 04:56:03
  • 解决Mybatis-Plus操作分页后数据失效问题

    2023-11-25 11:31:55
  • C#实现飞行棋小游戏

    2022-10-28 22:00:02
  • 使用Spring Expression Language (SpEL)全面解析表达式

    2021-11-19 08:07:10
  • 详解利用SpringCloud搭建一个最简单的微服务框架

    2023-08-21 04:24:32
  • 详解Java弱引用(WeakReference)的理解与使用

    2022-07-13 12:37:32
  • C#自定义针对URL地址的处理类实例

    2022-09-12 16:54:02
  • Java 判断线程池所有任务是否执行完毕的操作

    2021-10-03 09:43:55
  • Java使用Socket简单通讯详解

    2023-11-03 02:54:43
  • 一文带你搞懂Java中的泛型和通配符

    2023-12-10 16:15:07
  • Kotlin开发Android应用实例详解

    2023-09-11 00:22:50
  • Android开发实现圆形图片功能示例

    2023-07-12 08:43:54
  • asp之家 软件编程 m.aspxhome.com