将项目添加到 ListView,保持滚动位置并且看不到滚动跳跃

2024-04-10

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

然后用任何加载的历史记录就地替换它。

我已经完成了所有这些工作......除了一件事我必须诉诸反思才能完成。有很多问题和答案仅涉及在将项目添加到附加到 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 的顶部,然后快速闪回到正确的位置。问题相当明显并被发现被很多人 https://groups.google.com/forum/#!topic/android-developers/EnyldBQDUwE: setSelection()直到之后才不开心notifyDataSetChanged()和重绘ListView。所以我们必须post()给视图一个绘制的机会。But看起来很糟糕。

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

因此,反思失败后的回退:

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);
            }
        });
    }
}

有效吗?是的。是不是很丑陋?是的。将来有用吗?谁知道?有没有更好的办法?这就是我的问题。

我如何在不反思的情况下实现这一目标?

一个答案might是“自己写的ListView可以解决这个问题。”我只是问你是否已经看到了代码ListView http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.1.1_r1/android/widget/ListView.java.

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

Luksprog https://stackoverflow.com/users/493939/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.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将项目添加到 ListView,保持滚动位置并且看不到滚动跳跃 的相关文章

  • startActivity overridePendingTransition 只显示进入动画

    基本上 我遇到的问题是只显示输入幻灯片动画 调用 Activity 不会产生动画 startActivity intent overridePendingTransition R anim right in partly R anim le
  • Google Play 商店中基于服务的 Android 应用程序

    我正在开发一个应用程序 该应用程序仅包含一些服务 没有任何活动 即没有 UI 基本上 当用户在他 她的设备上安装应用程序时 我希望有 2 到 3 个服务在后台运行 对此我有几个疑问 应用程序安装后我的服务将如何启动 我的BroadcastR
  • 如何使用retrofit2进行GET请求?

    我有一个在本地主机上运行的安静的 Web 服务 我想在该剩余 URL 上发出 Retrofit2 GET 请求 MainActivity java private void requestData public static final S
  • Android Manifest 自动生成无效权限

    我不小心在 Android 清单中输入了无效的权限名称 并且无法将其删除 这是我的清单代码
  • 添加动态数据时 footable 出现问题

    我需要 jQuery Mobile 方面的一些帮助富表 http css tricks com footable a jquery plugin for responsive data tables 我正在表中动态添加数据 HTML tab
  • Android Facebook sdk 3.5 分享对话框

    您好 我正在为 android sdk 3 5 实现 facebook 共享对话框 但是我按照指南没有取得任何成功 FacebookDialog shareDialog new FacebookDialog ShareDialogBuild
  • Android 5.0 Lollipop 中屏幕固定关闭时如何收到通知?

    我有一个在后台运行的应用程序 并在手机上发生特定事件时启动活动 我发现在 Android 5 0 中 当用户使用另一个应用程序打开屏幕固定时 startActivity intent 调用将被完全忽略 我的应用程序不知道该活动尚未启动 因此
  • 游标索引越界异常

    打开后出现光标索引越界错误 数据库 请任何人告诉我如何打开现有数据库 sqllite Android 我想在数据库上触发一个选择查询 检索一些信息 public void getPatient SQLiteDatabase db Strin
  • 如何在 Android 应用程序中单击按钮时打开 Gmail Compose?

    当我的 Android 应用程序中单击按钮时 我尝试打开 Gmail 撰写屏幕 我需要 Google 提供的 API 密钥吗 或者我需要在按钮 onClickListener 中做什么 任何形式的见解都非常值得赞赏 正如 JeffC 指出的
  • Android CursorAdapter、ListView 和后台线程

    我一直在开发的这个应用程序有包含数兆字节数据的数据库可供筛选 许多活动只是列表视图 通过数据库中的各个级别的数据下降 直到到达 文档 即从数据库中提取并显示在手机上的 HTML 我遇到的问题是 其中一些活动需要能够通过捕获击键并重新运行带有
  • 多语言 Android 应用程序:在电子邮件和密码字段中显示英文键盘

    我们正在开发一款多语言 Android 应用程序 针对英语和阿拉伯语 面临的问题是在登录和注册屏幕中 我们希望仅以英文文本输入用户名和密码字段 从而显示英文键盘 无论设备区域设置语言如何 已尝试在 edittext 中设置 inputtyp
  • android:进程和进程名称

    我试图理解android process属性 Ref says http developer android com guide topics manifest application element html proc 如果分配给该属性的
  • 我应该选择的最低 SDK 版本是多少? (截至2018年11月)

    据我所知 android studio 中默认的最小 SDK 设置是 15 我读到我应该增加它 因为没有多少人 或者可能没有 仍在使用该 android 版本 另外 我计划使用 android studio 中的一些新功能 这些功能仅适用于
  • Android - 多次实例化一个片段?

    我正在创建一个在 ListView 中显示数据的应用程序 数据分为两种类型 热门 收藏夹 我有一个活动和两个片段 片段根据类别显示项目列表 我为此使用了 ListView 然后我有两个fragment layouts 它们在设计上完全相同
  • 在 android 版本 7.0 上膨胀类 android.widget.DatePicker 时出错

    我想显示弹出日期选择器并且我使用此代码 Calendar mcurrentDate Calendar getInstance int mYear mcurrentDate get Calendar YEAR int mMonth mcurr
  • 从Android客户端登录appengine

    我正在尝试登录应用程序引擎并访问应用程序引擎中的用户服务API 基本上我希望能够看到谁登录了我的 servlet 我正在使用从 android 获取 authtoken 然后从应用程序引擎获取 ASID 或 SACID cookie 的身份
  • 应用程序中空指针异常[重复]

    这个问题在这里已经有答案了 我正在尝试在我的应用程序中实施应用程序内计费 我写了这段代码 public class Settings extends PreferenceFragment ServiceConnection mService
  • Android Jasper 报告

    Jasper Reporting 可以集成到 Android 应用程序中吗 我正在尝试从 jrxml 文件生成 PDF CSV 文本和 XLS 报告 但是 我没有看到 Android SDK 支持 net sf jasperreports
  • 查询联系人 - 有时返回空游标

    我正在尝试查询联系人的显示名称 Override public void onActivityResult int requestCode int resultCode Intent data switch requestCode case
  • Android Espresso - 如果未选中,请单击复选框

    I have onView withId R id check box perform click 但我只想在尚未选中该复选框时执行此操作 我怎样才能在浓缩咖啡中做到这一点 我还想根据其之前的状态来切换复选框 开关 起初 我尝试用此方法打开

随机推荐

  • 体系结构 x86_64 的未定义符号:GCC

    我在我的 mac pro 上安装了 gcc 5 3 0 我想使用以下命令编译 c 程序 gcc main c o matrix mcmodel medium lm 但是我收到了这个错误 Undefined symbols for archi
  • Rails 资产管道和摘要价值

    有谁知道资产消化价值到底是怎么计算的吗 如果我有两个 JS 文件 其中包含各种其他包含的 JS 脚本 那么如果内部脚本都没有更改 每个文件是否会维护相同的摘要哈希 或者每次运行 asset precompile 操作时都会计算新的摘要值 接
  • 在 RStudio 中网络抓取 VIN 号码的品牌/型号/年份

    我目前正在开展一个项目 需要查找制造商 型号和 VIN 编号年份 我有 300 个不同 VIN 号码的列表 检查每个单独的 VIN 号码并将制造商 型号和年份手动输入到 Excel 中是非常低效且乏味的 我尝试使用带有 SelectorGa
  • 不使用循环打印 1 到 1000 [重复]

    这个问题在这里已经有答案了 我在 C 编程上下文中看到这个问题 我检查了一个解决方案 我的一位朋友给了我这段代码 它工作完美 但我无法理解它的逻辑以及它是如何工作的 我向他询问了这个问题 但他也不知道该程序实际上是如何工作的 我认为他也从某
  • 如何在 Play Framework 2.0 中使用 Evolutions?

    对于 1 x 版本 我们可以使用play evolutions apply 在 play 2 0 beta 中如何做到这一点 Evolution apply 在应用程序启动时自动运行 Play 2 0 rc1 缺少的是生成进化脚本并从 SB
  • 在 RSpec 请求规范中的每个请求之前设置标头

    如何在其中设置标题before each像下面这样 RSpec describe Users API type request do before each do host example org set a header for all
  • 更新对象时出现 HibernateOptimisticLockingFailureException

    我在更新对象时遇到以下异常 HibernateOptimisticLockingFailureException 类 用户 的对象 带有标识符 25614 乐观锁定失败 嵌套异常 是 org hibernate StaleObjectSta
  • Snowflake 中具有多个 JSON 对象的横向展平数组

    我有一个包含多个 JSON 对象的数组 表中任何 JSON 数组的最大元素数为 8 这是数组原始值的示例 variants id 12388362846279 inventory quantity 10 sku sku1 id 123883
  • 是否可以从命令行运行 Smalltalk 脚本?

    我发现了一个 可能过时且不正确 2004 年的博客文章 http www ianbicking org where smalltalk went wrong html它声称不可能从命令行运行 Smalltalk 脚本 从那时起有什么变化吗
  • 在 swift 中使用 TripleDes 和 MD5

    我有一个使用 TripleDes 和 MD5 的 Java 代码算法 这是我的java代码 private String encrypt String message String secretKey throws Exception Me
  • “找不到类型的属性”组合存储库 spring-data-neo4j

    我在用着spring data neo4j我正在尝试组合存储库以便能够使用自定义存储库 我认为我已经正确遵循了中指定的命名约定20 8 7 创建存储库 http docs spring io spring data neo4j docs 3
  • “双精度数组”和 TDoubleDynArray 之间的区别

    The System Typesunit 声明一个数组类型 TDoubleDynArray array of Double 如果我将一个方法声明为 procedure func x TDoubleDynArray 我注意到这个论点x行为就像
  • 使用 php ajax mysql 创建 3 个依赖下拉列表

    我正在使用 PHP MYSQL 和 JAVASCRIPT AJAX 我有多个下拉列表 我想使用 AJAX 使其相互依赖 其中这些下拉列表包含从 MYSQL 数据库检索的数据 用户从first下拉列表并根据其选择second and thir
  • 如何从矩阵中提取行名?

    我有一个行名称为日期的矩阵 我想将这些行名称提取到一个变量中 然后使用rownames 将这些日期应用到我拥有的另一个矩阵中 假设该矩阵称为 data matrix 每当我跑步时 data matrix 0 我得到了所有日期的打印输出 所以
  • Nodejs TCP连接客户端端口分配

    我使用nodejs在客户端和服务器之间创建了tcp连接 网络模块 https nodejs org api net html 服务器正在侦听已经预定义的端口 并且客户端正在连接到该端口 据我了解客户端的端口是由节点动态分配的 那是对的吗 节
  • 系统()的替代方案

    我最近开始接触C 编程 并且获得了很多经验 我过去的几个程序一直在使用 system 命令 我读过这应该是一个非常糟糕的主意 首先 为什么这是一个坏主意 我在 Linux 上使用它来执行诸如清除屏幕 例如 system clear 和启动程
  • 强制 Intellij IDEA 重新读取所有 Maven 依赖项

    如何强制intellij idea重新读取 更新pom文件中指定的所有依赖项 Press Ctrl Shift A to find actions and input reload you will find the Reload All
  • 如果事件处理程序不存在,则以编程方式在 VB.NET 中添加事件处理程序

    我正在尝试对 ASP NET 网页中的多个控件使用单个事件处理程序 当且仅当事件处理程序尚不存在时 我想在运行时添加事件处理程序 在 C 中 我将如下所示编写 if myTextBox OnTextChanged null myTextBo
  • 为什么 MicroMeter 定时器返回零?

    考虑以下代码 public static void main String args Timer timer Metrics timer item processing for int i 0 i lt 100 i timer record
  • 将项目添加到 ListView,保持滚动位置并且看不到滚动跳跃

    我正在构建一个类似于 Google Hangouts 聊天界面的界面 新消息将添加到列表底部 向上滚动到列表顶部将触发加载以前的消息历史记录 当历史记录从网络传入时 这些消息将添加到列表的顶部 并且不应从触发加载时用户停止的位置触发任何类型