RecyclerView 流式更新 item,当 item 高度高于屏幕时,如何保证一直保持滚动到底部并且不闪动? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
lixyz
V2EX    Android

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

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

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

    10 条回复    2025-02-14 10:40:45 +08:00
    murmurkerman
        1
    murmurkerman  
       240 天前
    简单讲一下 RecyclerView 和 ItemView 结构,是某个 Item 会动态更新么,类似于 Ai 聊天应用么。
    lixyz
        2
    lixyz  
    OP
       240 天前
    @murmurkerman 就是一个类似于 AI 聊天的应用,item 是 TextView ,然后 SSE 流式更新这个 TextView
    想要实现当 TextView 高于屏幕高度时,随着文本的增加,自行向下滚动
    现在通过 scrollToPositionWithOffset 可以实现滚动到底部,但是随着流式更新 TextView ,会导致上下一跳一跳的
    大佬有没有什么解决方案啊
    sankemao
        3
    sankemao  
       240 天前
    recyclerView 设置反向排列试过吗
    murmurkerman
        4
    murmurkerman  
       240 天前 via iPhone
    用正序的 recycler view 比较合适。消息高度超过限制和不再自动滚动到底部。逆序的话要计算 scroll range 的变化,然后滚动变化的部分。
    lixyz
        5
    lixyz  
    OP
       240 天前
    @sankemao @murmurkerman 因为还有其他类型的卡片以及交互,所以没有尝试改变 rv 的渲染方向,实在不行我试一下吧,多谢二位
    qwwuyu
        6
    qwwuyu  
       240 天前
    试了一下,可以一直保持在底部,不会上下跳动,我这里没有去计算 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  
       240 天前   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
       239 天前
    @qwwuyu 多谢大佬,昨天试了一下您的方案,闪动稍有缓解,但还存在
    @murmurkerman 多谢大佬,我今天抽空按照您的方案改造一下

    二位给我 V 还是啥?我给二位点奶茶喝!
    qwwuyu
        9
    qwwuyu  
       239 天前
    @lixyz 还是 7L 方案靠谱,试了加 LastItem,效果很好,也不用写那么多额外代码了,奶茶还是让给 7L 吧~
    murmurkerman
        10
    murmurkerman  
       239 天前 via iPhone
    @lixyz item 有没有加 id 和 type
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3647 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 22ms UTC 00:14 PVG 08:14 LAX 17:14 JFK 20:14
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86