【问题标题】:Toolbar expands on swipe down工具栏在向下滑动时展开
【发布时间】:2016-06-19 16:34:28
【问题描述】:

在我的应用程序中,我有一个折叠工具栏。如果我启动一个特定的片段,我想折叠工具栏,使其表现得像一个“正常”的片段,并且用户不能自己消耗它。这是我用于工具栏的布局:

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

    <android.support.design.widget.CollapsingToolbarLayout
        android:id="@+id/collapsing_toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:contentScrim="?attr/colorPrimary"
        app:expandedTitleMarginEnd="64dp"
        app:expandedTitleMarginStart="48dp"
        app:titleEnabled="false"
        app:layout_scrollFlags="scroll|exitUntilCollapsed">

        <ImageView
            android:src="@drawable/drawer_background"
            app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed"
            android:layout_width="match_parent"
            android:layout_height="172dp"
            android:scaleType="centerCrop"
            app:layout_collapseMode="parallax"
            android:minHeight="100dp" />

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolBar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            app:layout_collapseMode="pin"
            app:layout_scrollFlags="scroll|enterAlways" />

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

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

我也可以像这样从代码中折叠布局:

appBarLayout.setExpanded(false, false);

final AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams) collapsingToolbarLayout.getLayoutParams();
params.setScrollFlags(0);
collapsingToolbarLayout.setLayoutParams(params);

但这无济于事。如果用户从工具栏向下滑动,它将展开。

你有什么想法吗?

【问题讨论】:

  • 如何以编程方式设置AppBarLayout 高度,使其与工具栏的高度相匹配?那样它就无处可扩展了。
  • 布局中的 ImageView 和 Toolbar 中的滚动标志似乎很乱。尝试将它们也删除。
  • @IlyaPolenov 我将两者都更改为scroll|enterAlways,但这并没有改变任何东西。你还有别的意思吗?
  • 试试 collapsingToolbarLayout.requestLayout();应用这些标志后的方法可能会有所帮助..

标签: android android-toolbar android-appbarlayout


【解决方案1】:

核心问题是直到现在还没有CollapsingToolbarLayout.lock();方法(支持设计的v23.2.1)。希望此功能将包含在未来的版本中。在此之前,我建议采用以下解决方法:

您可以通过以下方式折叠和锁定工具栏:

appbar.setExpanded(false,false);
CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams)appbar.getLayoutParams();
lp.height = (int) getResources().getDimension(R.dimen.toolbar_height);

并使用以下命令解锁:

 CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams)appbar.getLayoutParams();
 lp.height = (int) getResources().getDimension(R.dimen.nav_header_height);

但是,上面的代码出现了问题:

当强制折叠 CoordinatorLayout 时,我们的工具栏的标题消失了,CollapsingToolbarLayout.setTitle(CharSequence title); 不再起作用。为了解决这个问题,我们在 Toolbar 中添加一个 TextView 并相应地操纵它的可见性。 (我们希望它在工具栏“解锁”的片段中“消失”,而在工具栏“锁定”的片段中“可见”。

我们必须将 TextView 的 android:textAppearance 设置为与 CollapsingToolbarLayout 的 app:collapsedTitleTextAppearance 保持一致,避免使用不同的工具栏文本大小和颜色干扰用户。

总之,界面如下:

public interface ToolbarManipulation {
    void collapseToolbar();
    void expandToolbar();
    void setTitle(String s);
}

这样的实现:

@Override
    public void collapseToolbar(){
        appbar.setExpanded(false,false);
        CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams)appbar.getLayoutParams();
        lp.height = (int) getResources().getDimension(R.dimen.toolbar_height);
        toolbarCollapsedTitle.setVisibility(View.VISIBLE);
    }

    @Override
    public void expandToolbar() {
        CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams)appbar.getLayoutParams();
        lp.height = (int) getResources().getDimension(R.dimen.nav_header_height);
        toolbarCollapsedTitle.setVisibility(View.GONE);
    }

    @Override
    public void setTitle(String s) {
        collapsingToolbarLayout.setTitle(s);
        toolbarCollapsedTitle.setText(s);
        collapsingToolbarLayout.invalidate();
        toolbarCollapsedTitle.invalidate();
    }

和这样的主xml:

....
  <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|exitUntilCollapsed"
            app:collapsedTitleTextAppearance="@style/CollapsedAppBar"

            >
                <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_collapseMode="pin"
                    app:popupTheme="@style/AppTheme.PopupOverlay"
                    >
                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="?attr/actionBarSize"
                        android:visibility="gone"
                        android:layout_gravity="center_vertical|start"
                        android:gravity="center_vertical|start"
                        android:id="@+id/toolbar_collapsed_title"
                        android:textAppearance="@style/CollapsedAppBar"
                        />
                </android.support.v7.widget.Toolbar>
        </android.support.design.widget.CollapsingToolbarLayout>
......

您可以根据需要锁定和解锁工具栏。您的片段应在其 onResume() 中调用这些函数;

我已经上传了一个示例实现here

注意:这只是一种解决方法,显然不是最干净的解决方案。我们正在等待更新版本的 com.android.support 来解决此问题。

【讨论】:

  • 非常感谢您的出色回答。我希望有人参考支持库及其限制,所以谢谢你的详细回答!
  • 什么是默认工具栏高度? @Sevle
  • 横向 48dp,纵向 56dp,来源:google.com/design/spec/layout/metrics-keylines.html
  • 有一个小问题,当你按回时工具栏中的标题文本会跳动一点,我建议将其样式更改为继承自@style/TextAppearance.AppCompat.Widget.ActionBar.Title而不是@android:style/TextAppearance.Medium
  • 谢谢你))花了一天时间解决这个问题终于用你的解决方案完美地做到了)按预期工作
【解决方案2】:

我不确定这是否是你要找的东西

CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams(); 
AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior(); 
behavior.setDragCallback(new AppBarLayout.Behavior.DragCallback() {
    @Override
    public boolean canDrag(@NonNull AppBarLayout appBarLayout) {
        return false;
    } 
});

【讨论】:

    【解决方案3】:

    尝试改变 AppBar 的高度。它对我有用。

    public void lockAppBar() {
        int appbarHeight = (int)getResources().getDimension(R.dimen.your_fixed_appbar_height);
        getView().findViewById(R.id.my_appbar).getLayoutParams().height = appbarHeight; 
    }
    

    【讨论】:

      【解决方案4】:

      findViewById(R.id.image_view).setVisibility(View.GONE); image_view折叠工具栏中的 imageView 的 id。 但如果你想为特定片段执行此操作,我建议调用使用片段活动通信也是如此。

      【讨论】:

        【解决方案5】:

        除了这个之外,所提供的解决方案都不适合我。使用此解决方案,我可以轻松管理折叠工具栏的状态。这将防止展开/启用折叠工具栏的折叠并为其设置标题。

        public void lockAppBar(boolean locked,String title) {
            if(locked){
                appBarLayout.setExpanded(false, true);
                int px = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 80, getResources().getDisplayMetrics());
                CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams)appBarLayout.getLayoutParams();
                lp.height = px;
                appBarLayout.setLayoutParams(lp);
                collapsingToolbarLayout.setTitleEnabled(false);
                toolbar.setTitle(title);
            }else{
                appBarLayout.setExpanded(true, false);
                appBarLayout.setActivated(true);
                CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
                lp.height = (int) getResources().getDimension(R.dimen.toolbarExpandHeight);
                collapsingToolbarLayout.setTitleEnabled(true);
                collapsingToolbarLayout.setTitle(title);
            }
        
        }
        

        【讨论】:

          【解决方案6】:

          尝试以编程方式为 toolBar、tabLayout 设置一些参数,我在 onPageSelected(int) 上有 ViewPager 更改标志

                  @Override
                  public void onPageSelected(int position) {
                      AppBarLayout.LayoutParams params = new AppBarLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
                      if (position == 3) {//listen for scrolls only for Fragment 3
                          params.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL | AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS);
                          toolBar.setLayoutParams(params);//hide as per scroll
                          params = new AppBarLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
                          params.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS);
                          tabLayout.setLayoutParams(params);//always visible
                      } else {
                          appBarLayout.setExpanded(false, true);
                          params.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS | AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED);
                          toolBar.setLayoutParams(params);//don't listen to scrolls
                          tabLayout.setLayoutParams(params);//dont listen to scrolls
                      }
                  }
          

          根据需要使用/设置上述标志。 AppBarLayout.LayoutParams

          【讨论】:

            【解决方案7】:

            最简单的做法是扩展 AppBarLayout.Behavior 类

            public class AppBarBehavior extends AppBarLayout.Behavior {
              private boolean locked;
            
              public AppBarBehavior() {
                super();
              }
            
              public AppBarBehavior(Context context, AttributeSet attrs) {
                super(context, attrs);
              }
            
              @Override
              public boolean onStartNestedScroll(@NonNull CoordinatorLayout parent, @NonNull AppBarLayout child, @NonNull View directTargetChild, View target, int nestedScrollAxes, int type) {
                if (locked) return false;       // Lock when content scrolled
                else return super.onStartNestedScroll(parent, child, directTargetChild, target, nestedScrollAxes, type);
              }
            
              @Override
              public boolean onTouchEvent(@NonNull CoordinatorLayout parent, @NonNull AppBarLayout child, @NonNull MotionEvent ev) {
                if (locked) return false;       // Lock when appBar swiped
                else return super.onTouchEvent(parent, child, ev);
              }
            
              public void lock(boolean locked) {
                this.locked = locked;
              }
            }
            

            然后在 XML 中设置新的 layout_behavior

            <com.google.android.material.appbar.AppBarLayout
                android:id="@+id/main.appbar"
                android:layout_width="match_parent"
                android:layout_height="200dp"
                android:fitsSystemWindows="false"
                app:layout_behavior="<full path to package>.AppBarBehavior">
            

            现在您可以通过以下方式管理锁定:

            AppBarLayout appBar = findViewById(R.id.main_appbar);
            appBar.setExpanded(false, true);   // collapse appBar
            CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) appBar.getLayoutParams();
            AppBarBehavior behavior = (AppBarBehavior) params.getBehavior();
            behavior.lock(true);   // lock appBar
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2014-04-02
              • 2018-05-06
              • 2018-01-19
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多