【问题标题】:How to reset the Toolbar position controlled by the CoordinatorLayout?如何重置 CoordinatorLayout 控制的 Toolbar 位置?
【发布时间】:2015-08-13 19:26:50
【问题描述】:

我正在开发的应用程序包含一个在 Activity 中实现的 Navigation Drawer。活动布局如下:

<FrameLayout 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.support.v4.widget.DrawerLayout
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.CoordinatorLayout
        android:id="@+id/coordinator"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <FrameLayout
            android:id="@+id/container"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <include
            android:id="@+id/appbar"
            layout="@layout/appbar" />

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

    <android.support.design.widget.NavigationView
        android:id="@+id/navigation_drawer"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        app:headerLayout="@layout/header_drawer"
        app:menu="@menu/menu_nav">
    </android.support.design.widget.NavigationView>

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

</FrameLayout>

这是一种很常见的模式,唯一变化频繁的就是容器布局里面的Fragment。

如果任何 Fragment 具有滚动元素,则在滚动时,CoordinatorLayout 将愉快地进行位置转换,包括 Toolbar/AppBarLayout。

这里真正的问题是,当 Fragment 被替换时,Toolbar 的位置保持不变,即如果 Toolbar 被隐藏,它将保持不变 这不是故意的。

结果是这样的:

这个:

卡住了:

在这种情况下如何重置工具栏位置?

编辑: 可能是一个错误,AppBarLayout 偏移量更改监听器仅在重新启动应用程序(按下返回按钮并打开应用程序)时被调用,并在激烈的甩动后停止再次被调用。

【问题讨论】:

  • 您找到解决方案了吗?
  • 还没有,有好心人在这里回答了,我还没来得及讨论他就删了他的帖子,他说他在AppBarLayout上使用setTranslationY()来操作它而不是重置它,并提到它应该可以工作,这对我来说不是,仍在寻找答案。找到后我一定会发布解决方案。
  • 嘿,@razzledazzle,我正在尝试将带有 recyclerview 的片段放入作为 CoordinatorLayout 一部分的 FrameLayout 中。我在 FrameLayout 中指定了 layout_behavior,但 AppBarLayout 不滚动。你有什么不同的做法吗?我必须在我的活动中初始化视图吗?
  • 修复了它。忘记在工具栏中添加app:layout_scrollFlags="scroll"
  • 还有一件事。即使我在回收站视图中没有项目,工具栏仍会滚动。知道如何解决这个问题吗?

标签: android navigation-drawer android-design-library androiddesignsupport


【解决方案1】:

要重置滚动状态,只需获取AppBarLayout.Behavior 对象

CoordinatorLayout coordinator = (CoordinatorLayout) findViewById(R.id.coordinator);
AppBarLayout appbar = (AppBarLayout) findViewById(R.id.appbar);
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) appbar.getLayoutParams();
AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior();       

并手动调用onNestedPreScroll方法:

int[] consumed = new int[2];
behavior.onNestedPreScroll(coordinator, appbar, null, 0, -1000, consumed);

如果您想通过动画顺利重置,可以尝试调用onNestedFling

behavior.onNestedFling(coordinator, appbar, null, 0, -1000, true);

【讨论】:

  • 对我来说,它只适用于通过设置正的“velocityY”值来折叠AppBarLayout。上面带有负“velocityY”值的代码无效。在ACTION_UP 操作之后,我从NestedScrollView's onTouchListener 调用它。我想实现 snap 行为 - 总是折叠或展开 AppBarLayout
  • 感谢您的回答,这是一个很好的解决方案,我在抽屉打开回调中使用了 onNestedFling(),效果很好。
  • 我的经历和@theb1uro 完全一样。仅适用于具有正“velocityY”值的崩溃。使用负 'velocityY' 值展开没有效果...
  • 我也在 cheesesquare 上进行了测试,结果相同,知道为什么这仅在折叠 AppBarLayout 时有效吗?
  • params.getBehavior() 返回 null。在 xml 中,layout_behaviour 标记设置在同级 NestedScrollView 上,而不是 AppBarLayout。请帮忙!
【解决方案2】:

首先在你的MainActivity中获取一个AppBarLayout引用,然后在被替换的fragment的暂停状态下,使用下面的方法展开工具栏:

MainActivity.appbar.setExpanded(true,true);

和或关闭工具栏:

MainActivity.appbar.setExpanded(false,true);

第二个参数用于平滑滚动工具栏。

【讨论】:

  • 这不包括你想要锁定AppBarLayout的用例。
  • AppBarLayout 没有这种方法setExpanded?
  • @MuhammadBabar 更新你的依赖,兄弟。
【解决方案3】:

将您的支持库更新到 v23,然后您就可以使用了:

appBarLayout.setExpanded(true/false);

public void setExpanded (boolean expanded)

设置此 AppBarLayout 是否展开,如果已经布局则动画。

与 AppBarLayout 的滚动一样,此方法依赖此布局作为 CoordinatorLayout 的直接子级。

expanded 如果布局应该完全展开,则为 true,如果应该完全折叠,则为 false

【讨论】:

  • 这无法将AppBarLayout 锁定到位。但是,它确实适用于常规情况。
【解决方案4】:

@razzledazzle AppBarLayout 将 onOffsetChangedListeners 存储为 WeakReferences,这意味着它们会在需要时被垃圾收集,例如当您进行激烈的投掷时。在此处查看解决方案:

https://code.google.com/p/android/issues/detail?id=176328

【讨论】:

  • 啊,确实是这样,我确实在源代码中看到了 WeakReferences,但从没想过它们可以多么容易地被 GCed。这也解释了为什么在 onResume() 下将侦听器作为字段引用比在 onCreate() 期间初始化匿名类效果更好。如链接中所述,将侦听器实现为类是有保证的解决方案。非常感谢您的意见!
  • 根据那个帖子已经修复了。
【解决方案5】:

我在片段更改之前使用此代码。

scrollingElement.startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL);
scrollingElement.dispatchNestedPreScroll(0, -Integer.MAX_VALUE, null, null);
scrollingElement.stopNestedScroll();

【讨论】:

【解决方案6】:

android.support.v4.widget.NestedScrollView 替换或包裹 android.support.design.widget.CoordinatorLayout 内的 FrameLayout,这将自动完成这项工作,而无需任何其他黑客攻击......所以它看起来像这样:

<android.support.design.widget.CoordinatorLayout
    android:id="@+id/coordinator"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

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

    <include
        android:id="@+id/appbar"
        layout="@layout/appbar" />

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

【讨论】:

    【解决方案7】:

    正如document所说的

    AppBarLayout 支持
    void setExpanded(布尔扩展,布尔动画);
    设置此 AppBarLayout 是否展开。

    • expanded 布尔值:如果布局应该完全展开,则为 true,如果应该完全折叠,则为 false
    • animate boolean:是否动画到新的状态

    所以首先,你需要

    AppBarLayout appBarLayout = findViewById(R.id.appBarLayout);
    

    然后展开布局

    appBarLayout.setExpanded(true, true); // with animation
    appBarLayout.setExpanded(true, false); // without animation  
    

    折叠布局

    appBarLayout.setExpanded(false, true); // with animation
    appBarLayout.setExpanded(false, false); // without animation 
    

    【讨论】:

      【解决方案8】:
      // Get the reference for appbar from layout
      AppBarLayout appbar = rootView.findViewById(R.id.appbar);
      //boolean expanded, boolean animate
      appbar.setExpanded(true, true);
      

      【讨论】:

        【解决方案9】:

        我遇到了类似的问题。当我动态调整它的大小时,我的布局要么高于需要(如这里),要么低于需要。它是在 FrameLayout 中以编程方式替换的 Fragment。 我做了什么:我开始在更改 FrameLayout 大小时重新创建我的 Fragment。

        myFragment = new MyFragment();
        getSupportFragmentManager().beginTransaction()
                        .replace(R.id.frame_layout, myFragment)
                        .commit();
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-06-28
          • 1970-01-01
          相关资源
          最近更新 更多