IM会话界面列表滑动问题

1、IM类的会话列表类似微信,底部输入框,顶部标题等,中间这一块都是rv列表展示。
2、中间的rv是必须定位为wrap_content,无法设置match_parent。
3、数据必须是倒序摆放,下拉刷新时候加载更多。

我们知道类似布局管理器:

//第三个参数 true 数据跟布局倒序,从底部开始 你的position==0 是在最低部,跟平時相反
var linearLayoutManager = LinearLayoutManager(this,RecyclerView.VERTICAL, false)

我写了个简单demo测试了一下,发现下拉刷新去加载更多数据的时候总是会自动往下展示一点点。

在这里插入图片描述
设置了之后如果是下拉刷新去加载更多数据,就像上面的gif中所显示一样。下面还有测试数据0项可以滑动,最顶部还有测试数据19项可以滑动,这不坑爹吗?居然显示在中间。

换另外一种方式来实现:linearLayoutManager.stackFromEnd = true

测试结果还是不错的,符合预期。

目前我的IM类项目就是使用这种去实现的,但是出现了一个bug,类似上面GIF图片一样,加载更多之后不是停留在之前的位置,总是自动往上滑动了几项。

布局从下往上开始绘制,数据跟平时展示还是一样,最终数据集里面最后一个数据还是显示在最底部,当超过一屏的时候,默认一进来类似默认滑动到最底部的效果类似。
应用场景:IM聊天会话界面
当布局文件非常复杂的时候,下拉刷新去加载更多历史数据的时候,总是会不自觉往下滑动少许,也就是网上说的刷新rv时候自动滑动的情况。
网上提出一些解决方法,把rv的高度自适应改为match_parent,但是在当前IM项目的应用场景里面,rv的高度必须是wrap_content,这就无解了。

屏蔽linearLayoutManager.stackFromEnd = true,刷新之后自动滑动的bug就没了,但是当开始进来默认数据超过一屏的时候,必须默认滑动到底部,从底部开始展示数据

使用scrollToPosition 会有一个滑动的闪烁更新过程,所以需要改成无感知滑动到底部:scrollToPositionWithOffset

// linearLayoutManager.stackFromEnd = true

在这里插入图片描述

一进来默认已经滑动到底部,那么就跟从底部开始绘制一个道理。刷新之后不会自动滑动了一段距离。

linearLayoutManager.stackFromEnd = true ,使用了这个属性之后滑动了一段距离,估计是因为我的布局太复杂导致高度计算出现问题所导致,xml代码就有五百行,实在没办法,只能把它关了。
demo代码:

class TestAdapter(context: Context, data: ArrayList<String>): RecyclerView.Adapter<TestAdapter.TestHolder>() {
    private val  mDiffCallback = TestDiffCallBack()
    var oldData: ArrayList<String> = data
        set(value) {
            mDiffCallback.newData = value
            val diffResult = DiffUtil.calculateDiff(mDiffCallback, false)
            field.clear()
            field.addAll(value)
            diffResult.dispatchUpdatesTo(object : ListUpdateCallback {
                override fun onInserted(position: Int, count: Int) {
                    notifyItemRangeInserted(position, count)
                }

                override fun onRemoved(position: Int, count: Int) {
                    notifyItemRangeRemoved(position, count)
                }

                override fun onMoved(fromPosition: Int, toPosition: Int) {
                    notifyItemMoved(fromPosition, toPosition)
                }

                override fun onChanged(position: Int, count: Int, payload: Any?) {
                    notifyItemRangeChanged(position, count, null)
                }
            })
        }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TestHolder
            = TestHolder(LayoutInflater.from(parent.context).inflate(R.layout.test_activity_rv_item, parent,false))

    override fun getItemCount(): Int = oldData.size

    override fun onBindViewHolder(holder: TestHolder, position: Int) {
        holder.textView.text = oldData[position]
    }

    inner class TestHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        var textView: TextView = itemView.findViewById<TextView>(R.id.txt)
    }

    inner class TestDiffCallBack() : DiffUtil.Callback() {
        var newData: ArrayList<String> = arrayListOf()

        override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
            return oldData[oldItemPosition] == newData[newItemPosition]
        }

        override fun getOldListSize(): Int {
            return oldData.size
        }

        override fun getNewListSize(): Int {
            return newData.size
        }

        override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
            return true
        }
    }
}
class TestActivity : AppCompatActivity(), OnRefreshListener, OnLoadMoreListener {

    lateinit var refre: SmartRefreshLayout
    lateinit var rv: RecyclerView
    private var info: ArrayList<String> = arrayListOf()
    private var adapter : TestAdapter ? = null
    private var fresh: Int = 0

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_test)
        refre = findViewById(R.id.rc_refresh)
        refre.isNestedScrollingEnabled = false
        refre.setRefreshHeader(RongRefreshHeader(this))
//        refre.setRefreshFooter(RongRefreshHeader(this))
        refre.setEnableRefresh(true)
        refre.setOnRefreshListener(this)
//        refre.setOnLoadMoreListener(this)

        rv = findViewById(R.id.rv)
        //第三个参数 true 数据跟布局倒序,从底部开始 你的position==0 是在最低部,跟平時相反
        var linearLayoutManager = LinearLayoutManager(this,RecyclerView.VERTICAL, false)
        /**
         * 布局从下往上开始绘制,数据跟平时展示还是一样,最终数据集里面最后一个数据还是显示在最底部,当超过一屏的时候,默认一进来类似默认滑动到最底部的效果类似。
         * 应用场景:IM聊天会话界面
         * 当布局文件非常复杂的时候,下拉刷新去加载更多历史数据的时候,总是会不自觉往下滑动少许,也就是网上说的刷新rv时候自动滑动的情况。
         * 网上提出一些解决方法,把rv的高度自适应改为match_parent,但是在当前IM项目的应用场景里面,rv的高度必须是wrap_content,这就无解了。
         * 屏蔽linearLayoutManager.stackFromEnd = true,刷新之后自动滑动的bug就没了,但是当开始进来默认数据超过一屏的时候,必须默认滑动到底部,从底部开始展示数据
         * 使用scrollToPosition 会有一个滑动的闪烁更新过程,所以需要改成无感知滑动到底部:scrollToPositionWithOffset
         *
         */
//        linearLayoutManager.stackFromEnd = true
        rv.layoutManager = linearLayoutManager
        info = getData()
        adapter = TestAdapter(this,info)
        rv.adapter = adapter
        linearLayoutManager.scrollToPositionWithOffset(info.size-1, 0)
    }

    private fun getData() : ArrayList<String>{
        var data = arrayListOf<String>()
        var size = fresh * 20
        for (index in size + 19 downTo  size) {
            data.add("测试数据$index")
        }
        fresh += 1
        return data
    }

    override fun onRefresh(refreshLayout: RefreshLayout) {
        var data = getData()
        data.addAll(info)
        adapter?.oldData = data
        refre.finishRefresh()
    }

    override fun onLoadMore(refreshLayout: RefreshLayout) {

    }
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ui.activity.TestActivity">


    <io.rong.imkit.widget.refresh.SmartRefreshLayout
        android:id="@+id/rc_refresh"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/rv"
            android:background="@color/color_FFC900"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"></androidx.recyclerview.widget.RecyclerView>

    </io.rong.imkit.widget.refresh.SmartRefreshLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <TextView
        android:id="@+id/txt"
        android:layout_width="match_parent"
        android:layout_height="80dp"
        android:text="测试数据1"
        android:gravity="center"
        android:textSize="18sp"
        android:textColor="@color/color_E72D2D"
        ></TextView>

</LinearLayout>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值