AppBarLayout с recyclerView во вложенном фрагменте

Поскольку изображения всегда лучше слов, я представляю вам мой текущий макет.

Панель инструментов/вкладки находится в файле activity.xml с viewPager, а recyclerView находится внутри фрагмента внутри viewPager. Таким образом, вы можете провести пальцем вправо / влево, чтобы увидеть другой контент.

Моя проблема в том, что я хочу, чтобы AppBarLayout был привязан в своем поведении прокрутки к recyclerView в первом фрагменте, но не к другим фрагментам.

В приведенном ниже коде я сделал эту привязку, но она не работает, потому что recyclerView не распознает AppBarLayout в внешнем макете. У вас есть обходной путь для этого?

Код активности:

<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:fab="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar_main"
            android:layout_width="match_parent"
            /* pretty stuff */
            app:layout_scrollFlags="scroll|enterAlways">

            <android.support.design.widget.TabLayout
                android:id="@+id/tabs"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                /* pretty stuff */ />

        </android.support.v7.widget.Toolbar>

    </android.support.design.widget.AppBarLayout>

    <android.support.v4.view.ViewPager
        android:id="@+id/main_pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <android.support.design.widget.SupportFloatingActionsMenu
           ...>
           /* Code for a fancy fab w/ menu */

    </android.support.design.widget.SupportFloatingActionsMenu>

</android.support.design.widget.CoordinatorLayout>

Для фрагмента, содержащего recyclerView :

<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.insa.burnd.view.MainActivity.NewsfeedFragment"
    android:id="@+id/fragment_newsfeed">

    <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/swipe_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <android.support.v7.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </android.support.v4.widget.SwipeRefreshLayout>

</android.support.design.widget.CoordinatorLayout>

Большое тебе спасибо :) !


person Mehdi    schedule 01.07.2015    source источник
comment
Вы задали тот же вопрос/код здесь: внутренняя панель инструментов   -  person Jared Burrows    schedule 22.07.2015
comment
Нет. Это не одно и то же. Вопрос совсем в другом, код почти тот же (и гифка та же).   -  person Mehdi    schedule 23.07.2015


Ответы (3)


Что со всем этим сумасшедшим кодом/макетами?

В фрагментах, где вы не хотите, чтобы панель инструментов прокручивалась, сделайте это в onCreateView() фрагмента:

    recyclerView.setNestedScrollingEnabled(false);
person kris larson    schedule 29.02.2016

Вы можете сделать это, внедрив ViewPager.OnPageChangeListener и включив/отключив AppBarLayout.LayoutParams флаги прокрутки.

Вот пример кода:

        viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

        }

        @Override
        public void onPageSelected(int position) {
            if (position == 0) {
                //turn on scrolling
                AppBarLayout.LayoutParams toolbarLayoutParams = (AppBarLayout.LayoutParams) mToolbar.getLayoutParams();
                toolbarLayoutParams.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL | AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS);
                mToolbar.setLayoutParams(toolbarLayoutParams);

                CoordinatorLayout.LayoutParams appBarLayoutParams = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
                appBarLayoutParams.setBehavior(new AppBarLayout.Behavior());
                appBarLayout.setLayoutParams(appBarLayoutParams);
            } else {
                //turn off scrolling
                AppBarLayout.LayoutParams toolbarLayoutParams = (AppBarLayout.LayoutParams) mToolbar.getLayoutParams();
                toolbarLayoutParams.setScrollFlags(0);
                mToolbar.setLayoutParams(toolbarLayoutParams);

                CoordinatorLayout.LayoutParams appBarLayoutParams = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
                appBarLayoutParams.setBehavior(null);
                appBarLayout.setLayoutParams(appBarLayoutParams);
            }
        }

        @Override
        public void onPageScrollStateChanged(int state) {

        }
    });

Но это не похоже на хороший шаблон UX. Это будет путать пользователей.

person Michał Z.    schedule 01.07.2015
comment
Благодарю вас ! Оно работает :) ! Что касается того, хороший ли это шаблон UX, меня это очень беспокоит, но другие фрагменты никоим образом не могут быть прокручены, так что, возможно, это менее запутанно... - person Mehdi; 01.07.2015
comment
Какой глюк? Можете ли вы описать это? - person Michał Z.; 02.07.2015
comment
Второй фрагмент неловко фиксируется, как только я заканчиваю прокручивать его. Вы видите всю уродливую анимацию, когда она становится непохожей на поведение, как только вы подходите к фрагменту. - person Mehdi; 03.07.2015
comment
Я думаю, это из-за этого appBarLayoutParams.setBehavior(new AppBarLayout.Behavior());, но это необходимо. Без него вы увидите пустое место под панелью инструментов, когда она скрыта на первой странице. - person Michał Z.; 03.07.2015
comment
Опубликовал это как проблему в google.code. Я посмотрю, планируют ли они использовать этот вариант использования. Потому что это интересная часть; Надежный API — это API, который позволит разработчикам обрабатывать самые разные варианты использования, а не только одну очевидную функцию, а в остальном делать это вручную. Кажется, что DSL все еще там на данный момент. - person Mehdi; 03.07.2015

Я думаю, что ключом к решению вашей проблемы является удаление макета координатора из макета представления ресайклера.

Это файл acitivity_main.xml, расширенный с помощью MainActivity с макетом-заполнителем для включения

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:openDrawer="start">

    <include
        layout="@layout/app_bar_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />


    <android.support.design.widget.NavigationView
        android:id="@+id/nav_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        app:itemIconTint="@color/drawer_item"
        app:itemTextColor="@color/drawer_item"
        android:fitsSystemWindows="true"
        app:headerLayout="@layout/nav_header_main"
        app:menu="@menu/activity_main_drawer" />

</android.support.v4.widget.DrawerLayout>

Это макет контента с вкладками, панелью приложений и ViewPager

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/grey_200"
    tools:context=".activities.MainActivity">


    <android.support.design.widget.AppBarLayout
        android:id="@+id/app_bar_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay"
        app:elevation="0dp">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|enterAlways|snap"
            app:popupTheme="@style/AppTheme.PopupOverlay" />

        <android.support.design.widget.TabLayout
            android:id="@+id/tabs"
            style="@style/MyCustomTabLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

    </android.support.design.widget.AppBarLayout>


    <android.support.v4.view.ViewPager
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginTop="12dp"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"></android.support.v4.view.ViewPager>


</android.support.design.widget.CoordinatorLayout>

И, наконец, макет RecyclerView, увеличенный фрагментом.

<?xml version="1.0" encoding="utf-8"?>

<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/your_recycler_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior" />

Если вам нужен хороший справочный код, вы можете проверить потрясающую демонстрацию, созданную Крисом Бейнсом из Google, о CoordinatorLayout и других функциях библиотеки поддержки дизайна.

Полный исходный код можно найти на github. Это был самый простой способ для меня понять логику, стоящую за этим.

Я надеюсь, что это помогает. (Наконец-то я что-то здесь написал! :D)

person iurysza    schedule 29.02.2016
comment
app:layout_behavior=@string/appbar_scrolling_view_behavior заставит viewpager переводить нижний уровень на высоту appBarLayout, поэтому, если внутри макета фрагмента есть какой-либо вид layout_gravity=bottom, он вообще не будет виден. - person Sjd; 01.03.2017