CoordinatorLayout 中的 ViewPager 意外收缩

ViewPager in CoordinatorLayout shrinks unexpectedly

在我的 Android 应用程序 运行 上 Android 5.1.1 我有一个使用 ToolbarTabLayout 的布局,下面是一个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 时我的视图被裁剪是否有合理的原因,或者我实际上遇到了 ViewPagerRecyclerView 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 确实扩展了。

在调试并逐步完成 CoordinatorLayoutViewPageronLayoutonMeasure 之后,我现在相当确定 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,因为我实际上没有任何高级滚动行为。所以我的解决方案是简单地使用 LinearLayoutRelativeLayout 作为我的根视图组。很好很简单,不需要把事情复杂化。

<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。