Recyclerview实现长按并显示滑动位置

本文展示了如何使用RecyclerView实现长按并滑动显示当前item内容的demo,类似于通讯录索引或微信表情展示。通过监听触摸事件,判断长按和滑动,结合PopupWindow展示内容。关键代码在于addOnItemTouchListener中的手势判断和PopupWindow的使用。

最近用recyclerview实现了一个长按并滑动显示当前item内容的demo,类似通讯录索引或者微信滑动查看表情,废话不多说,先看图再看代码

 

 

/**
 *
 * @ProjectName: HiltDemo
 * @Package: com.example.hiltdemo.ui.main
 * @ClassName: RecyclerviewHelper
 * @Description: java类作用描述
 * @Author: wanghaiyang
 * @CreateDate: 2021/11/12 11:10
 * @UpdateUser: 更新者
 * @UpdateDate: 2021/11/12 11:10
 * @UpdateRemark: 更新说明
 * @Version: 1.0
 */
class RecyclerviewHelperFragment : Fragment() {

    companion object{
        val instance = RecyclerviewHelperFragment()
    }
    private val binding: RecyclerviewHelperFragmentBinding by lazy { RecyclerviewHelperFragmentBinding.inflate(layoutInflater) }
    private val recyAdapter: RecyclerviewHelperAdapter by lazy { RecyclerviewHelperAdapter() }
    private val popLayoutManager by lazy{GridLayoutManager(requireContext(), 5)}
    private val popWidow by lazy { TestPopupWindow(requireContext()) }
    private val dats = mutableListOf<String>()
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding.recycler.adapter = recyAdapter
        binding.recycler.layoutManager = popLayoutManager
        for(i in 65..90){
            dats.add(i.toChar().toString())
        }

        recyAdapter.refreshDatas(dats)
        initListener()


    }

    private fun initListener() {
        var startTime = 0L
        var initFlag = true
        var startX = 0f
        var startY = 0f
        var currPosition = -1
        binding.recycler.addOnItemTouchListener(object : RecyclerView.OnItemTouchListener{
            override fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent): Boolean {
                return when(e.action){
                    MotionEvent.ACTION_DOWN->{
                        startTime = System.currentTimeMillis()
                        startX = e.x
                        startY = e.y
                        Log.e("swipe", "按下")
                        false
                    }
                    MotionEvent.ACTION_MOVE->{
                        if(startTime != 0L && System.currentTimeMillis() - startTime > 500){
                            Log.e("swipe", "滑动$startTime x=${e.x} y=${e.y}")
                            true
                        }else{
                            if(abs(e.x - startX) > 10 || abs(e.y - startY) > 10){
                                initFlag = false
                                startTime = 0
                                Log.e("swipe", "提前滑动了 x=${e.x} y=${e.y}")
                            }
                            false
                        }
                    }
                    MotionEvent.ACTION_UP->{
                        Log.e("swipe", "已经抬起")
                        initFlag = true
                        startTime = 0
                        false
                    }
                    else-> false
                }

            }

            override fun onTouchEvent(rv: RecyclerView, e: MotionEvent) {
                when(e.action){
                    MotionEvent.ACTION_MOVE->{
                        val view = binding.recycler.findChildViewUnder(e.x, e.y)
                        view?.let {
                            val position = binding.recycler.getChildAdapterPosition(it)
                            val layoutPosition = binding.recycler.getChildLayoutPosition(it)
                            Log.e("position", "position=$position")
                            if(currPosition != position){
                                popWidow.updateData(dats[position])
                                popWidow.dismiss()
                                PopupWindowCompat.showAsDropDown(popWidow, view, -view.width - 10, - view.height / 2, Gravity.START)
                                currPosition = position
                            }

                        }

                    }
                }
            }

            override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {

            }

        })
    }



}

class TestPopupWindow constructor(val context: Context) : PopupWindow() {
    private val binding by lazy { PopupTestBinding.inflate(LayoutInflater.from(context)) }
    init {
        height = ViewGroup.LayoutParams.WRAP_CONTENT
        width = ViewGroup.LayoutParams.WRAP_CONTENT
        isOutsideTouchable = true
        isFocusable = true
        setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))

        contentView = binding.root
    }

    fun updateData(str: String){
        binding.text.text = str
    }
}

其中最重要的代码就是addOnItemTouchListener里面的代码,在onInterceptTouchEvent中进行判定是否为长按,我判定的时间为500,大家可以提取出来弄一个变量进行控制。

还有就是要做一些滑动距离的误判,例如点击很快但还是会走到move,这个时候就要增加一点儿小的滑动距离防止进入长按逻辑。

最后就是UP那里进行一个popup销毁就可以了,这个只是一个demo,可能会有一定问题,大家注意优化

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值