Не сворачивайте панель инструментов, когда RecyclerView подходит к экрану


Я сделал приложение, используя Android Design Library, с помощью панели инструментов и TabLayout.
Фактически присутствуют 2 вкладки, оба с 2 RecyclerView, которые автоматически сбрасывают панель инструментов при прокрутке.

Мой вопрос: могу ли я отключить сбой панели инструментов, когда RecyclerView имеет несколько элементов и полностью соответствует экрану (например, в TAB 2)?

Я видел много примеров, например CheeseSquare, сделанных сотрудником Google, где проблема все еще присутствует: даже если RecyclerView имеет всего 1 элемент, панель инструментов скрывается от прокрутки.

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

Я думаю, что могу просто узнать, отображается ли первый элемент RecyclerView на экране, и если да, отключите панель инструментов. Первое легко реализовать, а что же последнее?

Это мой макет:

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

        <android.support.design.widget.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:fitsSystemWindows="true"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_scrollFlags="scroll|enterAlwaysCollapsed"
            android:background="?attr/colorPrimary"
            app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>

        <android.support.design.widget.TabLayout
            android:id="@+id/tab_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/glucosio_pink"
            app:tabSelectedTextColor="@android:color/white"
            app:tabIndicatorColor="@color/glucosio_accent"
            app:tabTextColor="#80ffffff"/>
        </android.support.design.widget.AppBarLayout>

        <android.support.v4.view.ViewPager
            android:id="@+id/pager"
            app:layout_behavior="@string/appbar_scrolling_view_behavior"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>

    <android.support.design.widget.FloatingActionButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/main_fab"
        android:layout_margin="16dp"
        android:onClick="onFabClicked"
        app:backgroundTint="@color/glucosio_accent"
        android:src="@drawable/ic_add_black_24dp"
        android:layout_gravity="bottom|right"
        />
    </android.support.design.widget.CoordinatorLayout>




Ответ 1

Окончательное решение (спасибо Michał Z.)

Способы отключения/включения прокрутки панели инструментов:

public void turnOffToolbarScrolling() {
    Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar);
    AppBarLayout appBarLayout = (AppBarLayout) findViewById(R.id.appbar_layout);

    //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);
}

public void turnOnToolbarScrolling() {
    Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar);
    AppBarLayout appBarLayout = (AppBarLayout) findViewById(R.id.appbar_layout);

    //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);
}


Узнайте, отображается ли последний элемент RecyclerView в моем фрагменте.
Если да, отключите прокрутку:

public void updateToolbarBehaviour(){
    if (mLayoutManager.findLastCompletelyVisibleItemPosition() == items.size()-1) {
        ((MainActivity) getActivity()).turnOffToolbarScrolling();
    } else {
        ((MainActivity)getActivity()).turnOnToolbarScrolling();
    }
}

Ответ 2

Вы можете проверить, отображается ли последний элемент в RecyclerView. Если он не выключен, прокрутите программно с помощью этого метода:

            //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);

Ответ 3

RecyclerView теперь (начиная с версии 23.2) поддерживает wrap_content. Просто используйте wrap_content как высоту.

Ответ 4

Я принял несколько иной подход, чтобы решить эту проблему.

Я создал настраиваемое AppBarBehavior, которое отключает его сам, основанный на ячейках.

public class CustomAppBarBehavior extends AppBarLayout.Behavior {

    private RecyclerView recyclerView;
    private boolean enabled;

    public CustomAppBarBehavior() {
    }

    public CustomAppBarBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onInterceptTouchEvent(CoordinatorLayout parent, AppBarLayout child, MotionEvent ev) {
        updatedEnabled();
        return enabled && super.onInterceptTouchEvent(parent, child, ev);
    }

    @Override
    public boolean onStartNestedScroll(CoordinatorLayout parent, AppBarLayout child, View directTargetChild, View target, int nestedScrollAxes) {
        return enabled && super.onStartNestedScroll(parent, child, directTargetChild, target, nestedScrollAxes);
    }

    @Override
    public boolean onNestedFling(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, float velocityX, float velocityY, boolean consumed) {
        return enabled && super.onNestedFling(coordinatorLayout, child, target, velocityX, velocityY, consumed);
    }

    private void updatedEnabled() {
        enabled = false;
        if(recyclerView != null) {
            RecyclerView.Adapter adapter = recyclerView.getAdapter();
            if (adapter != null) {
                int count = adapter.getItemCount();
                RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
                if (layoutManager != null) {
                    int lastItem = 0;
                    if (layoutManager instanceof LinearLayoutManager) {
                        LinearLayoutManager linearLayoutManager = (LinearLayoutManager) layoutManager;
                        lastItem = Math.abs(linearLayoutManager.findLastCompletelyVisibleItemPosition());
                    } else if (layoutManager instanceof StaggeredGridLayoutManager) {
                        StaggeredGridLayoutManager staggeredGridLayoutManager = (StaggeredGridLayoutManager) layoutManager;
                        int[] lastItems = staggeredGridLayoutManager.findLastCompletelyVisibleItemPositions(new int[staggeredGridLayoutManager.getSpanCount()]);
                        lastItem = Math.abs(lastItems[lastItems.length - 1]);
                    }
                    enabled = lastItem < count - 1;
                }
            }
        }
    }

    public void setRecyclerView(RecyclerView recyclerView) {
        this.recyclerView = recyclerView;
    }
}

Затем установите настраиваемое поведение на макете панели приложений

appBarBehavior = new CustomAppBarBehavior();
CoordinatorLayout.LayoutParams appBarLayoutParams = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
appBarLayoutParams.setBehavior(appBarBehavior);
appBarLayout.setLayoutParams(appBarLayoutParams);

Последнее изменение страницы пейджера просмотра обновило RecyclerView при поведении

private ViewPager.OnPageChangeListener pageChangeListener = new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { }

        @Override
        public void onPageSelected(final int position) {             
            appBarLayout.setExpanded(true, true);
            appBarLayout.post(new Runnable() {
                @Override
                public void run() {
                    appBarBehavior.setRecyclerView(childFragments.get(position).getRecyclerView());
                }
            });
        }

        @Override
        public void onPageScrollStateChanged(int state) { }
    };

Это должно работать с изменением наборов данных.

Ответ 5

Просто удалите прокрутку из

app:layout_scrollFlags="scroll|enterAlways"

Так что это должно быть

app:layout_scrollFlags="enterAlways"

Ответ 6

//turn off scrolling
AppBarLayout.LayoutParams toolbarLayoutParams = (AppBarLayout.LayoutParams) mToolbar.getLayoutParams();
toolbarLayoutParams.setScrollFlags(0);
mToolbar.setLayoutParams(toolbarLayoutParams);