V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
lixyz
V2EX  ›  Android

RecyclerView 流式更新 item,当 item 高度高于屏幕时,如何保证一直保持滚动到底部并且不闪动?

  •  
  •   lixyz · 42 天前 · 1589 次点击
    这是一个创建于 42 天前的主题,其中的信息可能已经有所发展或是发生改变。

    rt 现在更新到底部时,会出现闪动的情况,想请问大佬们有没有什么解决方案?成功了请喝咖啡

    10 条回复    2025-02-14 10:40:45 +08:00
    murmurkerman
        1
    murmurkerman  
       42 天前
    简单讲一下 RecyclerView 和 ItemView 结构,是某个 Item 会动态更新么,类似于 Ai 聊天应用么。
    lixyz
        2
    lixyz  
    OP
       42 天前
    @murmurkerman 就是一个类似于 AI 聊天的应用,item 是 TextView ,然后 SSE 流式更新这个 TextView
    想要实现当 TextView 高于屏幕高度时,随着文本的增加,自行向下滚动
    现在通过 scrollToPositionWithOffset 可以实现滚动到底部,但是随着流式更新 TextView ,会导致上下一跳一跳的
    大佬有没有什么解决方案啊
    sankemao
        3
    sankemao  
       42 天前
    recyclerView 设置反向排列试过吗
    murmurkerman
        4
    murmurkerman  
       42 天前 via iPhone
    用正序的 recycler view 比较合适。消息高度超过限制和不再自动滚动到底部。逆序的话要计算 scroll range 的变化,然后滚动变化的部分。
    lixyz
        5
    lixyz  
    OP
       42 天前
    @sankemao @murmurkerman 因为还有其他类型的卡片以及交互,所以没有尝试改变 rv 的渲染方向,实在不行我试一下吧,多谢二位
    qwwuyu
        6
    qwwuyu  
       42 天前
    试了一下,可以一直保持在底部,不会上下跳动,我这里没有去计算 TextView 改变后的高度,有需要可以自己监听控件高度变化,再去 scrollToPositionWithOffset.
    代码图片 https://imgur.com/a/HU30yph
    ```
    new Thread(() -> {
    while (!isFinishing() && run) {
    try {
    Thread.sleep(200);
    } catch (InterruptedException ignored) {
    }
    runOnUiThread(() -> {
    if (textTv != null) {
    textTv.setText(textTv.getText() + "asdasdasdasdasdasdasd");
    int targetPosition = adapter.getItemCount() - 1;
    View targetView = linearLayoutManager.findViewByPosition(targetPosition);
    int offset = recyclerView.getHeight() - targetView.getHeight();
    linearLayoutManager.scrollToPositionWithOffset(targetPosition, offset);
    }
    });
    }
    }).start();
    ```
    murmurkerman
        7
    murmurkerman  
       42 天前   ❤️ 2
    好久没写 android view 哈哈哈,我写出来了,花掉了所有的摸鱼时间,https://github.com/Murmurl912/android_recycler_view_chat.git
    总结下:
    1. 去掉 RecyclerView 的 ItemAnimator
    2. 在更新 Item 的时候,判断是否在底部,已经是底部的时候滚动到底部。
    3. 我之前的方案是会加一个 FirstItem 和 LastItem 的占位 Item 到 RecyclerView 中,方便实现滚动到底部和顶部。
    Core Code:
    ```kotlin

    class MainActivity : ComponentActivity() {
    private val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }
    private val adapter by lazy {
    ItemAdapter()
    }
    private var id = 1L
    private val items = LinkedHashMap<Long, Item>()
    private var job: Job? = null
    private val layoutManager by lazy {
    binding.recyclerView.layoutManager as LinearLayoutManager
    }

    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    enableEdgeToEdge()
    setContentView(binding.root)
    binding.root.fitsSystemWindows = true
    binding.recyclerView.adapter = adapter
    binding.recyclerView.itemAnimator = null
    binding.generate.setOnClickListener {
    if (job?.isActive == true) {
    return@setOnClickListener
    }
    var item = Item.MessageItem(id++, "")
    items[item.id] = item
    updateItems()
    job = lifecycleScope.launch {
    MessageApi.generate()
    .collect { text ->
    item = item.copy(text = item.text + text, isGenerating = true).also {
    items[it.id] = it
    updateItems()
    }
    // scroll to bottom here
    val isAtBottom =
    layoutManager.findLastCompletelyVisibleItemPosition() == adapter.itemCount - 1
    if (isAtBottom) {
    layoutManager.scrollToPosition(adapter.itemCount - 1)
    }
    }
    item = item.copy(isGenerating = false).also {
    items[it.id] = it
    updateItems()
    }
    }
    }
    }


    private fun updateItems() {
    adapter.updateItems(items.values.toMutableList()
    .apply {
    add(0, Item.FirstItem)
    add(Item.LastItem)
    }
    )
    }


    }
    ```
    lixyz
        8
    lixyz  
    OP
       41 天前
    @qwwuyu 多谢大佬,昨天试了一下您的方案,闪动稍有缓解,但还存在
    @murmurkerman 多谢大佬,我今天抽空按照您的方案改造一下

    二位给我 V 还是啥?我给二位点奶茶喝!
    qwwuyu
        9
    qwwuyu  
       41 天前
    @lixyz 还是 7L 方案靠谱,试了加 LastItem,效果很好,也不用写那么多额外代码了,奶茶还是让给 7L 吧~
    murmurkerman
        10
    murmurkerman  
       41 天前 via iPhone
    @lixyz item 有没有加 id 和 type
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3004 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 13:55 · PVG 21:55 · LAX 06:55 · JFK 09:55
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.