ListView加载完数据为什么屏幕会自动和ListView的顶部对齐,而不是最布局中最顶部的控件?

发布于 2022-09-01 16:42:47 字数 267 浏览 15 评论 0

我在ScrollView里先后放了一个ViewPager,可以显示几页广告;下边是一个ListView里,会从网络请求数据,并加载出一些图片出来。

正常应该显示ViewPager里的内容,ViewPager没占满屏幕,ViewPager下面再显示ListView部分。

但是我的ListView请求完数据就会自动将其滑到屏幕顶部,也就是说ViewPager被滑上去了。屏幕里从ListView开始显示。

怎么才能不让ListView影响默认显示的效果呢?

求教

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

迷你仙 2022-09-08 16:42:47

遇到过一个类似的问题,不过当时ScrollView里嵌套的是GridView,分享下解决方案及过程,只想要解决方案的话看分隔线上面的就好了

  • grid.setFocusable(false)

  • update数据后,手动scrollto(0,0)

  • 重写ScrollView中的computeScrollDeltaToGetChildRectOnScreen,让该方法返回0


ScrollView中嵌套 GridView 导致 ScrollView 默认不停留在顶部的解决方案和分析

发生情况大概是我在ScrollView顶部放了一个ViewPager用来做广告Banner,底部放了个GridVie, 来实现一个类似9宫格效果的展示.

然后出现的状况是,当我获取完数据并调用notifyDataSetChanged();后 ScrollView自动滚到了最底部,也就是GridView所在的位置.

研究了一下,获取了一些解决方案

-- 让界面顶部的某一个View获取focus
-- grid.setFocusable(false);
-- 手动scrollto(0,0)
-- 重写ScrollView中的computeScrollDeltaToGetChildRectOnScreen,让该方法返回0

目前简单的用setFocusable(false)解决了该问题

试着分析一下这个问题产生的原因. 从解决方案反推,可以发现这个问题和 focus 有关系

一个猜测是 notifyDataSetChanged()之后,grid由于加载了数据的关系高度产生了变化

这导致了ScrollView内部重新走了 onLayout / onMeaure 流程 在这个流程中 ScrollView会将自身滚动到 获得 focus 的 child 位置

上面关于focus的解决方案即是从这个角度去解决问题

跟踪一下调用链

protected void onLayout(boolean changed, int l, int t, int r, int b) {
 super.onLayout(changed, l, t, r, b);
 mIsLayoutDirty = false;
 // Give a child focus if it needs it
 if (mChildToScrollTo != null && isViewDescendantOf(mChildToScrollTo, this)) {
 scrollToChild(mChildToScrollTo);
 }
 ...
}

可以看到 onLayout 的时候确实会将ScrollView滚动到focus child位置

private void scrollToChild(View child) {
 child.getDrawingRect(mTempRect);

 /* Offset from child's local coordinates to ScrollView coordinates */
 offsetDescendantRectToMyCoords(child, mTempRect);

 int scrollDelta = computeScrollDeltaToGetChildRectOnScreen(mTempRect);

 if (scrollDelta != 0) {
 scrollBy(0, scrollDelta);
 }
}

从代码逻辑上来看 避免 GridView获取focus可以解决该问题.

而重写ScrollView中的computeScrollDeltaToGetChildRectOnScreen则是从另一个角度解决该问题

而scrollToChild这个方法会根据computeScrollDeltaToGetChildRectOnScreen的返回值来计算滚动的位置

重载computeScrollDeltaToGetChildRectOnScreen让其返回0 会导致ScrollView内布局产生变化时,不能正确滚动到focus child位置,当然,这也就是我们想要的效果,布局变化时ScrollView不需要自己去滚动.

至于computeScrollDeltaToGetChildRectOnScreen代码太长就不贴了

大致代码是 根据当前 scrollY和focus child 的 rect.bottom 去计算要滚到哪

逻辑理顺以后觉得这个问题也没什么奇怪的.

若无相欠,怎会相见 2022-09-08 16:42:47

scrollview 里面嵌套 listview 会有高度计算的问题,不过也是listview 显示不全,没试过会自己滑上去,具体情况还要根据的代码的实现。你这种需求可以考虑用 listview 里面加个headerView 里面包含 ViewPager来实现

时光无声 2022-09-08 16:42:47

参考一下这个吧,https://github.com/MaybeMercy/zhihutoday 这个客户端的显示界面使用的就是 ViewPager和ListView,具体的外面的是自定义的ScrollView,ViewPager和ListView是动态加载的

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文