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

前言

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

运行效果

实现步骤

这里分解为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(); } } } }

项目源码:ScrollCheckBox_jb51.rar

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

时间: 2024-10-25 16:21:06

Android实现滑动选择控件实例代码的相关文章

Android 自定义弹性ListView控件实例代码(三种方法)

关于在Android中实现ListView的弹性效果,有很多不同的方法,网上一搜,也有很多,下面贴出在项目中经常用到的两种实现ListView弹性效果的方法(基本上拿来就可以用),供大家参考: 弹性ListView 第一种方法: import android.content.Context; import android.content.res.Configuration; import android.util.AttributeSet; import android.util.Display

Android 底部导航控件实例代码_Android

一.先给大家展示下最终效果 通过以上可以看到,图一是简单的使用,图二.图三中为结合ViewPager共同使用,而且都可以随ViewPager的滑动渐变色,不同点是图二为选中非选中两张图片,图三的选中非选中是一张图片只是做了颜色变化. 二. 需求 我们希望做可以做成这样的,可以在xml布局中引入控件并绑定数据,在代码中设置监听回调,并且配置使用要非常简单! 三.需求分析 根据我们多年做不明确需求项目的经验,以上需求还算明确.那么我们可以采用在LinearLayout添加子View控件,这个子Vie

Android 底部导航控件实例代码

一.先给大家展示下最终效果 通过以上可以看到,图一是简单的使用,图二.图三中为结合ViewPager共同使用,而且都可以随ViewPager的滑动渐变色,不同点是图二为选中非选中两张图片,图三的选中非选中是一张图片只是做了颜色变化. 二. 需求 我们希望做可以做成这样的,可以在xml布局中引入控件并绑定数据,在代码中设置监听回调,并且配置使用要非常简单! 三.需求分析 根据我们多年做不明确需求项目的经验,以上需求还算明确.那么我们可以采用在LinearLayout添加子View控件,这个子Vie

jQuery 颜色选择控件实例教程

插件效果 特点 平面模式 - 元素在页面中 功能强大的颜色选择控件 容易改变一些图片来定制外观 视图适中 使用方法 平面模式: $('#colorpickerHolder').ColorPicker({flat: true});自定义皮肤,在自定义窗口中使用平面模式显示颜色选择器小部件. 附加到一个文本字段,并使用回调函数来更新字段的值为所选颜色和也可以设置颜色的值后确定即可.  代码如下 复制代码 $('#colorpickerField1, #colorpickerField2, #colo

Android开发中DatePicker日期与时间控件实例代码

一.简介 二.方法 最日常的使用方法了 日期控件DatePicker 时间控件TimePicker 月份从0开始 三.代码实例 效果图: 代码: fry.Activity01 package fry; import com.example.DatePicherDemo1.R; import android.app.Activity; import android.os.Bundle; import android.widget.DatePicker; import android.widget.

安卓自定义流程进度图控件实例代码

先上效果图: 如图,可实现设置:总流程数.已完进度程数.已完成颜色,各个标题 github地址戳这里 使用方法 1.导入compile 'com.github.pavlospt:circleview:1.3'依赖包(因为用到了CircleView) 2.直接把下面两个文件一个java一个xml,复制粘贴进项目(代码放在了文章最后,暂时还没弄成开源库,有时间直接做成依赖包倒进去) 在xml中写入ProcessImg控件 在java文件中实例化ProcessImg对象 根据需要调用几个方法 1.对象

jquery动态增加删除控件实例代码

可以添加在增减过程中需要的自定义参数和变量,如: $("table").dynamicaddremover({param1:"param1", param2:"param2"}); 使用时,如:options.param1等等. .根容器必须有唯一id且指定时必须唯一.如果有多个模块(多个根容器)需要使用可以这样:$("#table1").dynamicaddremover(),$("#table2").d

简约JS日历控件 实例代码_javascript技巧

运行结果如下: 复制代码 代码如下: <script type="text/javascript" language="javascript">function choose_date_czw(date_id,objtd){if(date_id=="choose_date_czw_close"){    document.getElementByIdx_x_x("choose_date_czw_id").style

js 模拟select控件实例代码

请选择游戏名称 搜索 地下城与勇士 魔兽世界(国服) 魔兽世界(台服) 热血江湖 神鬼传奇 大话西游II QQ幻想世界