gpt4 book ai didi

android - 向 ListView 添加项目,保持滚动位置并且看不到滚动跳转

转载 作者:IT老高 更新时间:2023-10-28 22:10:01 25 4
gpt4 key购买 nike

我正在构建一个类似于 Google Hangouts 聊天界面的界面。新消息将添加到列表底部。向上滚动到列表顶部将触发加载以前的消息历史记录。当历史从网络进入时,这些消息将被添加到列表的顶部,并且不应从触发加载时用户停止的位置触发任何类型的滚动。换句话说,列表顶部会显示一个“加载指示器”:

enter image description here

然后将其替换为任何加载的历史记录。

enter image description here

我已经完成了所有这些工作......除了我不得不诉诸反射(reflection)来完成的一件事。在将项目添加到附加到 ListView 的适配器时,有很多问题和答案仅涉及保存和恢复滚动位置。我的问题是,当我执行以下操作时(简化但应该不言自明):

public void addNewItems(List<Item> items) {
final int positionToSave = listView.getFirstVisiblePosition();
adapter.addAll(items);
listView.post(new Runnable() {

@Override
public void run() {
listView.setSelection(positionToSave);
}
});
}

然后用户会看到快速闪到 ListView 顶部,然后快速闪回到正确的位置。问题比较明显,发现了by many people : setSelection() 直到 notifyDataSetChanged()ListView 重绘之后才感到不高兴。所以我们必须 post() 到 View 中给它一个绘制的机会。 但是这看起来很糟糕。

我已经通过使用反射“修复”了它。我讨厌它。在其核心,我想要完成的是重置 ListView 的第一个位置,而无需经历绘制周期的繁琐,直到 我设置了位置。为此,ListView 有一个有用的字段:mFirstPosition。天哪,这正是我需要调整的!不幸的是,它是包私有(private)的。同样不幸的是,似乎没有任何方法可以以编程方式设置它或以任何不涉及无效循环的方式影响它......产生丑陋的行为。

所以,以失败为后备的反射(reflection):

try {
Field field = AdapterView.class.getDeclaredField("mFirstPosition");
field.setAccessible(true);
field.setInt(listView, positionToSave);
}
catch (Exception e) { // CATCH ALL THE EXCEPTIONS </meme>
e.printStackTrace();
listView.post(new Runnable() {

@Override
public void run() {
listView.setSelection(positionToSave);
}
});
}
}

有效吗?是的。可怕吗?是的。将来会起作用吗?谁知道?有没有更好的办法? 这是我的问题。

如何在不反射(reflection)的情况下完成此任务?

答案可能是“编写你自己的 ListView 来处理这个问题。”我只想问你有没有seen the code for ListView .

编辑:根据 Luksprog 的评论/答案,没有反射(reflection)的工作解决方案。

Luksprog推荐一个 OnPreDrawListener()。迷人!我以前搞过 ViewTreeObservers,但从来没有一个。经过一番折腾,以下类型的东西似乎工作得非常完美。

public void addNewItems(List<Item> items) {
final int positionToSave = listView.getFirstVisiblePosition();
adapter.addAll(items);
listView.post(new Runnable() {

@Override
public void run() {
listView.setSelection(positionToSave);
}
});

listView.getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener() {

@Override
public boolean onPreDraw() {
if(listView.getFirstVisiblePosition() == positionToSave) {
listView.getViewTreeObserver().removeOnPreDrawListener(this);
return true;
}
else {
return false;
}
}
});
}

很酷。

最佳答案

正如我在评论中所说,OnPreDrawlistener 可能是解决问题的另一种选择。使用监听器的想法是跳过显示两种状态之间的 ListView(在添加数据之后并将选择设置到正确的位置之后)。在 OnPreDrawListener(使用 listViewReference.getViewTreeObserver().addOnPreDrawListener(listener); 设置)中,您将检查 ListView 的当前可见位置并针对 ListView 应显示的位置对其进行测试。如果这些不匹配,则使监听器的方法返回 false 以跳过帧并将 ListView 上的选择设置到正确的位置。设置正确的选择将再次触发绘图监听器,这次位置将匹配,在这种情况下,您将取消注册 OnPreDrawlistener 并返回 true

关于android - 向 ListView 添加项目,保持滚动位置并且看不到滚动跳转,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19320214/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com