CoordinatorLayout 中的 ViewPager 意外收缩
ViewPager in CoordinatorLayout shrinks unexpectedly
在我的 Android 应用程序 运行 上 Android 5.1.1 我有一个使用 Toolbar
和 TabLayout
的布局,下面是一个ViewPager
。所有这些都放在一个 CoordinatorLayout
中。
ViewPager
的第一页是 RecyclerView
服务 CardView
项。
我的问题是我的 ViewPager
不断调整大小,因此我的 CardView
列表项被裁剪了。
我的主要布局基本上是这样的:
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<android.support.design.widget.AppBarLayout
android:layout_height="wrap_content"
android:layout_width="match_parent" >
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<android.support.design.widget.TabLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</android.support.design.widget.CoordinatorLayout>
我的 ViewPager
提供的第一个片段看起来像:
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<android.support.v7.widget.RecyclerView
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="8dp"/>
</FrameLayout>
这会呈现如下所示的内容:
单击我的布局中的一个按钮时,我使用 startActivityForResult
调用另一个 activity,当返回到我的 activity 有时 突然我的列表被裁剪,所以第一个项目只有一半是可见的:
在 ViewPager
中水平滑动到另一个寻呼机然后返回后,问题消失了,因此似乎没有正确触发重新布局。按 HOME 然后恢复我的 activity 并不能解决问题。请注意,即使我没有以任何方式修改我的布局,也会发生这种情况,我只是从 startActivityForResult 调用返回。是的,它只发生 有时 ... 而且我没有后台线程 运行 可以解释明显的随机行为。
起初我以为是RecyclerView
缩小了,但是使用HierarchyViewer我发现它实际上是整个ViewPager
缩小到原来高度的一半左右。
我尝试了各种 hack 来解决这个问题,包括在我的整个视图层次结构上调用 invalidate()
和 requestLayout()
,但似乎没有任何帮助(虽然滑动到另一个页面并再次返回修复它) .此外,这些不是我想要求助的解决方案......然后我尝试将我的 ViewPager 高度更改为 wrap_content
,这实际上解决了这个特定问题;返回到我的 activity 后,我的 RecyclerView
中的第一项永远不会被裁剪,我可以向下滚动到其他项目。但是,现在我列表的最后一项 总是 被裁剪了,如以下屏幕截图所示,列表一直滚动到底部:
因为我现在不明白发生了什么,所以我需要一些帮助。我真正应该将什么用作我的 ViewPager 的 layout_height,以及 - 最重要的 - 为什么?对我来说,match_parent
是有道理的,但我应该怎么想呢?使用 match_parent
时我的视图被裁剪是否有合理的原因,或者我实际上遇到了 ViewPager
、RecyclerView
and/or CoordinatorLayout
中的错误?如何确保我的 ViewPager
始终填充 AppBar 下面的整个屏幕区域,并且我的 RecyclerView
可以垂直滚动以正确呈现所有 CardView
列表项?
在您的片段中,只需删除 frameLayout 并使 recyclerView 成为父视图...我希望它会起作用:
<android.support.v7.widget.RecyclerView
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="8dp">
<android.support.v7.widget.RecyclerView/>
事实证明,这几乎可以肯定是 CoordinatorLayout
中的错误,甚至更有可能是 AppBarLayout$ScrollingViewBehavior
中的错误。在创建 MCVE 的过程中,我意识到我的 sub-activity 在屏幕上有一个 IME 导致 ViewPager 缩小 - 当我的 activity 在 onActivityResult
之后恢复时, ViewPager
由于来自 IME 的屏幕缩小 real-estate 而缩小,但尽管 IME 不再显示 和 但再也不会展开事实上 CoordinatorLayout
确实扩展了。
在调试并逐步完成 CoordinatorLayout
和 ViewPager
的 onLayout
和 onMeasure
之后,我现在相当确定 CoordinatorLayout
没有正确传播大小更改为 children。
我发现我可以通过在我的 ViewPager
上调用 requestLayout
来 "fix" 解决问题,但前提是调用延迟足够长(10 毫秒无效,100 毫秒有效 大部分时间):
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
mViewPager.requestLayout();
}
}, 100);
}
这显然不是一个可靠的解决方案,但在进一步调查后发现我可能甚至不需要 CoordinatorLayout
,因为我实际上没有任何高级滚动行为。所以我的解决方案是简单地使用 LinearLayout
或 RelativeLayout
作为我的根视图组。很好很简单,不需要把事情复杂化。
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<android.support.design.widget.AppBarLayout
android:layout_height="wrap_content"
android:layout_width="match_parent" >
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<android.support.design.widget.TabLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
不过,我会尝试将其压缩成一个简单的示例,并使用 Google 提交错误。
至于我应该用什么作为我的ViewPager
的高度,我原来使用的match_parent
似乎还是合理的。 wrap_content
解决了问题(但引起了其他问题)的事实可能只是由于错误引起的不一致。
我在使用旧版本的支持库时遇到过类似的问题。
查看这些相关问题:
https://code.google.com/p/android/issues/detail?id=176406
https://code.google.com/p/android/issues/detail?id=176187
确保您在撰写本文时使用的是最新的 Support library
版本 23.1。
在我的 Android 应用程序 运行 上 Android 5.1.1 我有一个使用 Toolbar
和 TabLayout
的布局,下面是一个ViewPager
。所有这些都放在一个 CoordinatorLayout
中。
ViewPager
的第一页是 RecyclerView
服务 CardView
项。
我的问题是我的 ViewPager
不断调整大小,因此我的 CardView
列表项被裁剪了。
我的主要布局基本上是这样的:
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<android.support.design.widget.AppBarLayout
android:layout_height="wrap_content"
android:layout_width="match_parent" >
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<android.support.design.widget.TabLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</android.support.design.widget.CoordinatorLayout>
我的 ViewPager
提供的第一个片段看起来像:
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<android.support.v7.widget.RecyclerView
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="8dp"/>
</FrameLayout>
这会呈现如下所示的内容:
单击我的布局中的一个按钮时,我使用 startActivityForResult
调用另一个 activity,当返回到我的 activity 有时 突然我的列表被裁剪,所以第一个项目只有一半是可见的:
在 ViewPager
中水平滑动到另一个寻呼机然后返回后,问题消失了,因此似乎没有正确触发重新布局。按 HOME 然后恢复我的 activity 并不能解决问题。请注意,即使我没有以任何方式修改我的布局,也会发生这种情况,我只是从 startActivityForResult 调用返回。是的,它只发生 有时 ... 而且我没有后台线程 运行 可以解释明显的随机行为。
起初我以为是RecyclerView
缩小了,但是使用HierarchyViewer我发现它实际上是整个ViewPager
缩小到原来高度的一半左右。
我尝试了各种 hack 来解决这个问题,包括在我的整个视图层次结构上调用 invalidate()
和 requestLayout()
,但似乎没有任何帮助(虽然滑动到另一个页面并再次返回修复它) .此外,这些不是我想要求助的解决方案......然后我尝试将我的 ViewPager 高度更改为 wrap_content
,这实际上解决了这个特定问题;返回到我的 activity 后,我的 RecyclerView
中的第一项永远不会被裁剪,我可以向下滚动到其他项目。但是,现在我列表的最后一项 总是 被裁剪了,如以下屏幕截图所示,列表一直滚动到底部:
因为我现在不明白发生了什么,所以我需要一些帮助。我真正应该将什么用作我的 ViewPager 的 layout_height,以及 - 最重要的 - 为什么?对我来说,match_parent
是有道理的,但我应该怎么想呢?使用 match_parent
时我的视图被裁剪是否有合理的原因,或者我实际上遇到了 ViewPager
、RecyclerView
and/or CoordinatorLayout
中的错误?如何确保我的 ViewPager
始终填充 AppBar 下面的整个屏幕区域,并且我的 RecyclerView
可以垂直滚动以正确呈现所有 CardView
列表项?
在您的片段中,只需删除 frameLayout 并使 recyclerView 成为父视图...我希望它会起作用:
<android.support.v7.widget.RecyclerView
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="8dp">
<android.support.v7.widget.RecyclerView/>
事实证明,这几乎可以肯定是 CoordinatorLayout
中的错误,甚至更有可能是 AppBarLayout$ScrollingViewBehavior
中的错误。在创建 MCVE 的过程中,我意识到我的 sub-activity 在屏幕上有一个 IME 导致 ViewPager 缩小 - 当我的 activity 在 onActivityResult
之后恢复时, ViewPager
由于来自 IME 的屏幕缩小 real-estate 而缩小,但尽管 IME 不再显示 和 但再也不会展开事实上 CoordinatorLayout
确实扩展了。
在调试并逐步完成 CoordinatorLayout
和 ViewPager
的 onLayout
和 onMeasure
之后,我现在相当确定 CoordinatorLayout
没有正确传播大小更改为 children。
我发现我可以通过在我的 ViewPager
上调用 requestLayout
来 "fix" 解决问题,但前提是调用延迟足够长(10 毫秒无效,100 毫秒有效 大部分时间):
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
mViewPager.requestLayout();
}
}, 100);
}
这显然不是一个可靠的解决方案,但在进一步调查后发现我可能甚至不需要 CoordinatorLayout
,因为我实际上没有任何高级滚动行为。所以我的解决方案是简单地使用 LinearLayout
或 RelativeLayout
作为我的根视图组。很好很简单,不需要把事情复杂化。
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<android.support.design.widget.AppBarLayout
android:layout_height="wrap_content"
android:layout_width="match_parent" >
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<android.support.design.widget.TabLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
不过,我会尝试将其压缩成一个简单的示例,并使用 Google 提交错误。
至于我应该用什么作为我的ViewPager
的高度,我原来使用的match_parent
似乎还是合理的。 wrap_content
解决了问题(但引起了其他问题)的事实可能只是由于错误引起的不一致。
我在使用旧版本的支持库时遇到过类似的问题。
查看这些相关问题:
https://code.google.com/p/android/issues/detail?id=176406 https://code.google.com/p/android/issues/detail?id=176187
确保您在撰写本文时使用的是最新的 Support library
版本 23.1。