Android RecyclerView实现滑动选中

1,516 阅读2分钟

需求:

实现将一段文字转化为char列表(有能力可以使用智能分词),然后用户选择自己想要的字或者词,生成新的String

思路:

  1. 创建列表
  2. 创建适配器
  3. 设置滑动监听
  4. 收集用户选择的文字
  5. 完毕

实施:

创建布局文件

<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/list"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_weight="1"
    android:clipChildren="false"
    android:clipToPadding="false"
    android:paddingStart="5dp"
    android:paddingEnd="5dp"
    android:paddingBottom="52dp" />

创建item布局文件

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="30dp"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/text"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@drawable/string_adapter"
            android:gravity="center"
            android:text="1"
            android:textColor="@color/word"
            android:textSize="@dimen/word" />

    </LinearLayout>
</layout>

适配器只做一件事

数据绑定

holder.binding.text.text = value

RecyclerView处理

这里是关键

 // 初始化列表
list.adapter = adapter
list.setHasFixedSize(true)
list.addItemDecoration(object : RecyclerView.ItemDecoration() {
		override fun getItemOffsets(
		outRect: Rect,
		view: View,
		parent: RecyclerView,
		state: RecyclerView.State
		) {
				super.getItemOffsets(outRect, view, parent, state)
						outRect.set(0, 0, 0, 20)
        }
		})
list.layoutManager = GridLayoutManager(this@QRCodeScanActivity, 15)

GridLayoutManager不在赘述,类似table布局

这里初始化了一些基本参数之后,我们就需要对整个list做触摸监听了

// 1. 申明一个map 用来保存用户选择的数据
val selectValue = hashMapOf<Int, Char>()

list.addOnItemTouchListener(object : RecyclerView.OnItemTouchListener {
    // 用于保存最后一个被划到的界面,防止view在一次滑动时被多次处理
    private var lastView: View? = null
  	
    /**
     * 处理触摸事件
     * @return Boolean  返回该触摸是否被拦截
     */
    override fun onInterceptTouchEvent(rv: RecyclerView, event: MotionEvent): Boolean {
      	// 开始分发触摸事件
        when (event.action) {
        // 用户抬起手指后 置空lastView 防止内存泄漏以及回收拦截(防止第二次点击该view时无法响应事件)
        MotionEvent.ACTION_UP -> {
            lastView = null
        }
						
        // 用户手指滑动的时候 处理事务
        MotionEvent.ACTION_MOVE -> {
            // 先获取当前手机所在的view
            val view = rv.findChildViewUnder(event.x, event.y) ?: return false
            // 防止手机在一个view上来回摩擦时抖动
            if (view == lastView) {
                return false
            } else {
                lastView = view
            }
            // 获取当前view的下标
            val endIndex = rv.getChildAdapterPosition(view)
            // 切换状态
            view.isSelected = !view.isSelected
            // 开始判断该view是否被选中,未被选中则 选中 并增加颜色
            if (view.isSelected) {
                // 保存数据	
                selectValue.put(endIndex, resData[endIndex])
                view.findViewById<TextView>(R.id.text).setTextColor(ResUtils.getColor(R.color.word))
            } else {
                // 移除数据
                selectValue.remove(endIndex)
                view.findViewById<TextView>(R.id.text).setTextColor(ResUtils.getColor(R.color.white))
            }
        }
    }
    return false
}
    override fun onTouchEvent(rv: RecyclerView, event: MotionEvent) {}
    override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {}
})

selectValue存的key就是对应的index,防止重复存入,value就是对应的字符串,最后selectValue.values.forEach { res += it } 将结果累加即可

ps: 如果要根据下标顺序展示 那么利用key去排序即可

技术总结:

  1. 要知道滑动监听要监听谁,不能在adapter中监听item

  2. 要防止单个view被反复摩擦~

  3. 使用map存放时用index当做key 防止重复放入

ps:功能很简单,挺有趣