禁用AppBarLayout的扩展

时间:2015-12-07 11:40:42

标签: android android-support-library

我有一个工具栏和一个TabLayout以及一个包含在CollapsingToolbarLayout中的图像。这个gif几乎总结了一下:

https://raw.githubusercontent.com/vitovalov/TabbedCoordinatorLayout/master/art/demo.gif

这是XML:

<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

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

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapse_toolbar"
            android:layout_width="match_parent"
            android:layout_height="250dp"
            android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <ImageView
                android:id="@+id/header"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@drawable/photo"
                android:fitsSystemWindows="true"
                android:scaleType="centerCrop"
                app:layout_collapseMode="parallax"/>

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="100dp"
                android:gravity="top"
                android:minHeight="?attr/actionBarSize"
                app:layout_collapseMode="pin"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
                app:titleMarginTop="15dp"/>

            <android.support.design.widget.TabLayout
                android:id="@+id/tabs"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:layout_gravity="bottom"
                app:tabIndicatorColor="@color/colorAccent"/>

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

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

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

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

我想要实现的是,例如在Tab 2上,我不想让用户能够看到图像。因此,即使他试图将AppBarLayout拉下来,他也不应该在任何情况下看到图像。

在显示标签2时调用appBarLayout.setExpanded(false);会隐藏图像并将所有内容折叠回来。虽然当你按下AppBarLayout并向下滑动时,你可以恢复图像。情况并非如此。

如何防止此行为?

我正在使用支持库的v23.1.1。对于图书馆的第22版,已经有this question。但是,解决方法不再适用于版本23.

4 个答案:

答案 0 :(得分:14)

我找到了一招!

  • 当我希望我的appbar保持折叠时:

    public void lockAppBarClosed() {
        mAppBarLayout.setExpanded(false, false);
        mAppBarLayout.setActivated(false);
        CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams)mAppBarLayout.getLayoutParams();
        lp.height = (int) getResources().getDimension(R.dimen.toolbar_height);
    }
    
  • 当我希望我的appbar可以再次展开和滚动时

    public void unlockAppBarOpen() {
        mAppBarLayout.setExpanded(true, false);
        mAppBarLayout.setActivated(true);
        CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams)mAppBarLayout.getLayoutParams();
        lp.height = (int) getResources().getDimension(R.dimen.toolbar_expand_height);
    }
    

希望它会对你有所帮助!

答案 1 :(得分:8)

Anne-Claire提供的技巧有效,但你最终失去了动画。我所做的是创建一个扩展AppBarLayout.Behavior类的自定义行为,允许我在每次选择时启用/禁用滚动。

public class CustomAppBarLayoutBehavior extends AppBarLayout.Behavior {

    private boolean shouldScroll = false;

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

    @Override
    public boolean onStartNestedScroll(CoordinatorLayout parent, AppBarLayout child, View directTargetChild, View target, int nestedScrollAxes, int type) {
        return shouldScroll;
    }

    @Override
    public boolean onTouchEvent(CoordinatorLayout parent, AppBarLayout child, MotionEvent ev) {
        if(shouldScroll){
            return super.onTouchEvent(parent, child, ev);
        }else{
            return false;
        }
    }

    public void setScrollBehavior(boolean shouldScroll){
        this.shouldScroll = shouldScroll;
    }

    public boolean isShouldScroll(){
        return shouldScroll;
    }
}

然后,您应该将此行为应用于xml布局中的AppBarLayout

<android.support.design.widget.AppBarLayout
    android:id="@+id/app_bar_layout"
    android:layout_width="wrap_content"
    android:layout_height="@dimen/activity_main_toolbar_height_extended"
    android:theme="@style/ThemeOverlay.AppCompat.Dark"
    android:fitsSystemWindows="true"
    android:elevation="4dp"
    app:layout_behavior="io.eighttails.mvp.widgets.CustomAppBarLayoutBehavior">

然后您可以通过以下方式打开和关闭它:

CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) mAppBarLayout.getLayoutParams();
((CustomAppBarLayoutBehavior)layoutParams.getBehavior()).setScrollBehavior(true);

CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) mAppBarLayout.getLayoutParams();
((CustomAppBarLayoutBehavior)layoutParams.getBehavior()).setScrollBehavior(false);

答案 2 :(得分:2)

根据“Bilthon”(here)的答案,我认为这个解决方案要短得多,在Kotlin:

//allows to block scrolling of AppBarLayout https://stackoverflow.com/a/48086783/878126
class BlockableAppBarLayoutBehavior(context: Context, attrs: AttributeSet) : AppBarLayout.Behavior(context, attrs) {
    var isShouldScroll = false

    override fun onStartNestedScroll(parent: CoordinatorLayout, child: AppBarLayout, directTargetChild: View, target: View, nestedScrollAxes: Int, type: Int) = isShouldScroll

    override fun onTouchEvent(parent: CoordinatorLayout?, child: AppBarLayout?, ev: MotionEvent) = isShouldScroll && super.onTouchEvent(parent, child, ev)

}

用法:

滚动时禁用更改其大小:

((app_bar.layoutParams as CoordinatorLayout.LayoutParams).behavior as BlockableAppBarLayoutBehavior).isShouldScroll = false

并启用:

((app_bar.layoutParams as CoordinatorLayout.LayoutParams).behavior as BlockableAppBarLayoutBehavior).isShouldScroll = false

如果你有一个RecyclerView,并希望阻止它滚动,你也可以使用我发现的this解决方案。

答案 3 :(得分:0)

我敢肯定,OP确实解决了他的问题,但是..

对于尚未为您的特定案例找到答案的人,请考虑(如果您一直在密切关注)关于任何相关问题的答案的与禁用此折叠/滚动行为有关的操作没有NestedScrollView

对于那些使用通用工具栏/布局而不是AppBarLayout(如果可能的话……我可能不知道)的人来说,情况是一样的。

>

此问题的特殊性在于,如果有人选择不禁用折叠式滚动,则ViewPager / RecyclerViews / etc ..的组合绝对可以正常工作,而无需使用NestedScrollView ...,但在您需要的情况下禁用它,就不可能了(就我所阅读和尝试的而言)

更糟糕的是,在XML / Kotlin / Java代码上有这么多的变量和这些相同变量的如此多的组合,并且同时所有这些变量很可能最终都到达相同的位置甚至可能提供类似行为的外观,这使得忽略解决方案甚至问题本身变得极为容易。

所以也许解决方案就是使用NestedScrollView ...

@BindingAdapter("scrollable")
public static void setScrollable(@NotNull AppBarLayout appBarLayout, boolean scrollable) {

    CoordinatorLayout.LayoutParams layoutParams =
            (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
    AppBarLayout.Behavior layoutBehavior =
            (AppBarLayout.Behavior) layoutParams.getBehavior();

    AppBarLayout.Behavior finalBehavior =
            layoutBehavior == null? new AppBarLayout.Behavior() : layoutBehavior;
    finalBehavior
            .setDragCallback(
                    new AppBarLayout.Behavior.DragCallback() {
                        @Override
                        public boolean canDrag(@NonNull AppBarLayout appBarLayout) {

                            return scrollable;
                        }
                    }
            );
    if (layoutBehavior == null) {

        layoutParams.setBehavior(finalBehavior);
    }
}

@BindingAdapter("setNestedScrollViewScrollable")
public static void setNestedScrollViewScrollable(@NotNull NestedScrollView nestedScrollView, boolean scrollable) {

    nestedScrollView.setNestedScrollingEnabled(scrollable);
}

在XML:

        <com.google.android.material.appbar.AppBarLayout
            android:id="@+id/app_bar_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            scrollable="@{false}"    //here
            android:theme="@style/Theme.PieceVolumeCalculator.AppBarOverlay"
            >


        <androidx.core.widget.NestedScrollView
            android:id="@+id/activity_main_nestedscrollview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fillViewport="true"
            app:layout_behavior="@string/appbar_scrolling_view_behavior"
            setNestedScrollViewScrollable="@{false}"    //here
            >
         // your ViewPager/ RecyclerView/ etc.. here
       </androidx.core.widget.NestedScrollView>