【问题标题】:CoordinatorLayout: Hiding/Showing half visible toolbar?CoordinatorLayout:隐藏/显示一半可见的工具栏?
【发布时间】:2015-08-15 00:26:42
【问题描述】:

我想实现与您在 Google Play 商店 中看到的效果类似的效果,通过滚动内容,Toolbar 在您滚动时会离开屏幕。

这适用于 #io15 中引入的 CoordinatorLayout (1),但是:如果您在“中途”停止滚动,工具栏将保留在屏幕上,但会被切入half:我希望它在屏幕外显示动画,就像在 Google Play 商店中一样。 我怎样才能做到这一点?

【问题讨论】:

    标签: android android-toolbar


    【解决方案1】:

    现在 Android 支持库 23.1.0 有一个新的滚动标志 SCROLL_FLAG_SNAP 可以让您实现此效果。

    AppBarLayout 支持许多滚动标志,这些标志会影响子视图对滚动的反应(例如,滚动离开屏幕)。此版本的新增功能是 SCROLL_FLAG_SNAP,确保在滚动结束时,视图不会部分可见。相反,它将滚动到最近的边缘,使其完全可见或完全滚出屏幕。

    【讨论】:

      【解决方案2】:

      活动布局文件:

      <FrameLayout
          xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="match_parent"
          android:layout_height="match_parent">
      
          <android.support.v7.widget.RecyclerView
              android:id="@+id/recyclerView"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:paddingTop="?attr/actionBarSize"
              android:clipToPadding="false"/>
      
          <android.support.v7.widget.Toolbar
              android:id="@+id/toolbar"
              android:layout_width="match_parent"
              android:layout_height="?attr/actionBarSize"
              android:background="?attr/colorPrimary"/>
      
      </FrameLayout>
      

      现在在 Activity 内部,设置 Toolbar 和 RecyclerView。将 OnScrollListener 分配给 RecyclerView

       recyclerView.setOnScrollListener(new MyScrollListener(this));
      

      从 RecyclerView.OnScrollListener 扩展 MyScrollListerner。

      public abstract class MyScrollListener extends RecyclerView.OnScrollListener {
      
          private static final float TOOLBAR_HIDE_THRESHOLD = 10;
          private static final float TOOLBAR_SHOW_THRESHOLD = 70;
      
          private int mToolbarOffset = 0;
          private boolean mControlsVisible = true;
          private int mToolbarHeight;
          private int mTotalScrolledDistance;
      
          public MyScrollListener(Context context) {
      
              final TypedArray styledAttributes = context.getTheme().obtainStyledAttributes(
                      new int[]{R.attr.actionBarSize});
              mToolbarHeight = (int) styledAttributes.getDimension(0, 0);
              styledAttributes.recycle();
      
              return toolbarHeight;
              mToolbarHeight = Utils.getToolbarHeight(context);
          }
      
          @Override
          public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
              super.onScrollStateChanged(recyclerView, newState);
      
              if(newState == RecyclerView.SCROLL_STATE_IDLE) {
                  if(mTotalScrolledDistance < mToolbarHeight) {
                      setVisible();
                  } else {
                      if (mControlsVisible) {
                          if (mToolbarOffset > TOOLBAR_HIDE_THRESHOLD) {
                              setInvisible();
                          } else {
                             setVisible();
                          }
                      } else {
                          if ((mToolbarHeight - mToolbarOffset) > TOOLBAR_SHOW_THRESHOLD) {
                              setVisible();
                          } else {
                              setInvisible();
                          }
                      }
                  }
              }
          }
      
              @Override
          public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
              super.onScrolled(recyclerView, dx, dy);
              clipToolbarOffset();
              onMoved(mToolbarOffset);
      
              if((mToolbarOffset <mToolbarHeight && dy>0) || (mToolbarOffset >0 && dy<0)) {
                  mToolbarOffset += dy;
              }
              if (mTotalScrolledDistance < 0) {
                  mTotalScrolledDistance = 0;
              } else {
                  mTotalScrolledDistance += dy;
              }
          }
      
          private void clipToolbarOffset() {
           if(mToolbarOffset > mToolbarHeight) {
               mToolbarOffset = mToolbarHeight;
             } else if(mToolbarOffset < 0) {
                  mToolbarOffset = 0;
              }
          }
      
          private void setVisible() {
              if(mToolbarOffset > 0) {
                  onShow();
                  mToolbarOffset = 0;
              }
              mControlsVisible = true;
          }
      
          private void setInvisible() {
              if(mToolbarOffset < mToolbarHeight) {
                  onHide();
                  mToolbarOffset = mToolbarHeight;
              }
              mControlsVisible = false;
          }
      
          public abstract void onMoved(int distance);
          public abstract void onShow();
          public abstract void onHide();
      }
      

      【讨论】:

      • @zoltish 如果这对您有用,请告诉我,如果有用,请接受作为答案。 :)
      • appbar/toolbar 可以在不滚动 RecyclerView 的情况下滚动,在这种情况下不会触发监听器代码。这发生在 RecyclerView 在顶部并且没有任何内容可以向上滚动,并且用户向下拉时,这将导致整个 CoordinatorLayout 的滚动
      【解决方案3】:

      覆盖 AppBarLayout 似乎是一个更好的解决方案,因为有两个可能的滚动事件 - 整个 CoordinatorLayout 和 RecyclerView/NestedScrollView

      将此答案视为可能的工作代码: https://stackoverflow.com/a/32110089/819355

      【讨论】:

        猜你喜欢
        • 2017-06-28
        • 2016-03-01
        • 2023-03-26
        • 1970-01-01
        • 2012-01-07
        • 1970-01-01
        • 2017-12-01
        • 2015-08-18
        • 1970-01-01
        相关资源
        最近更新 更多