软件编程
位置:首页>> 软件编程>> Android编程>> Android实现滑动选择控件实例代码

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

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

标签:android,滑动,选择

前言

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

运行效果

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#

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com