ViewPager в CoordinatorLayout неожиданно сжимается

В моем 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 для вызова другого действия, а иногда при возврате к моей работе мой список обрезается так, что видится только половина первого элемента:

введите описание изображения здесь

После поворота по горизонтали на другой пейджер в ViewPager, а затем обратно проблема исчезнет, ​​поэтому кажется, что повторная компоновка не была правильно запущена. Нажатие HOME и возобновление моей активности НЕ разрешают проблему. Обратите внимание, что это происходит, даже если я не изменяю свой макет каким-либо образом, я просто возвращаюсь из вызова startActivityForResult. И да, это случается иногда... И у меня нет фоновых потоков, которые могли бы объяснить кажущееся случайное поведение.

Сначала я подумал, что это уменьшилось RecyclerView, но с помощью HierarchyViewer я смог найти, что на самом деле весь ViewPager уменьшился примерно до половины его первоначальной высоты.

Я попробовал разные хаки, чтобы обойти это, включая вызов invalidate() и requestLayout() на весь мой просмотр hiearchy, но ничего не помогло (хотя прокрутка на другую страницу и обратно исправлена). Кроме того, это не те решения, к которым я хочу прибегнуть... Затем я попытался изменить высоту ViewPager на wrap_content, что фактически решило эту конкретную проблему; после возвращения в мою работу первый элемент в моем RecyclerView никогда не обрезается, и я могу прокручивать вниз до других элементов. Однако теперь вместо этого последний элемент моего списка всегда обрезается, как видно на этом скриншоте, где список прокручивается до конца:

введите описание изображения здесь

Поскольку я сейчас нахожусь в точке, где я действительно не понимаю, что происходит, мне нужна помощь. Что я должен использовать как layout_height для моего ViewPager и, прежде всего, почему? Для меня match_parent имеет смысл, но как я должен здесь думать? Есть ли разумная причина, которую мои взгляды обрезали при использовании match_parent, или я действительно столкнулся с ошибкой в ​​ViewPager, RecyclerView и/или CoordinatorLayout? Как я могу убедиться, что мой ViewPager последовательно заполняет всю область экрана под AppBar и что мой RecyclerView можно прокручивать по вертикали для правильного отображения всех элементов списка CardView?

Ответы

Ответ 1

У меня возникла аналогичная проблема при использовании более старой версии библиотеки поддержки.

См. следующие проблемы:

https://code.google.com/p/android/issues/detail?id=176406 https://code.google.com/p/android/issues/detail?id=176187

Убедитесь, что вы используете последнюю версию Support library, версия 23.1, начиная с этой записи.

Ответ 2

Оказывается, это почти наверняка ошибка в CoordinatorLayout или, что еще более вероятно, в AppBarLayout$ScrollingViewBehavior. Стремясь создать MCVE, я понял, что мой суб-активность имел IME на экране, что вызвало сокращение ViewPager - когда моя активность возобновляется после onActivityResult, ViewPager сокращается в результате уменьшенной экранной недвижимости от IME, но никогда не расширяется, несмотря на то, что IME больше не отображается и факт, что CoordinatorLayout действительно расширен.

После отладки и перехода через onLayout и onMeasure из CoordinatorLayout и ViewPager теперь я уверен, что CoordinatorLayout неправильно передает изменение размера своим дочерним элементам.

Я обнаружил, что могу "исправить" проблему, вызвав requestLayout на моем ViewPager, но только если вызов достаточно задерживается (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 решил проблему (но вызвал другие проблемы), вероятно, был просто из-за несоответствий, вызванных ошибкой.

Ответ 3

В вашем фрагменте просто удалите 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/>