【问题标题】:Android SupportActionBar not animating on show / hideAndroid SupportActionBar 在显示/隐藏时没有动画
【发布时间】:2016-02-13 13:08:43
【问题描述】:

我发现很多关于如何禁用 Android ActionBar 动画的问题。我有完全相反的问题。我确实想要动画,但它应该开箱即用吧?

我认为问题出在我的自定义工具栏上:

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

    <android.support.v7.widget.Toolbar android:id="@+id/toolbar"
        android:layout_width="match_parent" android:layout_height="@dimen/menu_height"
        android:minHeight="@dimen/menu_height"
        android:background="@color/backgroundColor" app:popupTheme="@style/AppTheme.PopupOverlay"
        android:theme="@style/ToolbarColoredBackArrow"/>

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

我在 mij 活动中这样设置:

 Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
 setSupportActionBar(toolbar);

工具栏工作正常,但当我调用以下任一方法时没有动画:

protected void hideActionBar(){
    ActionBar ab = getSupportActionBar();
    if (ab.isShowing()) {
        ab.hide();
    }

}

protected void showActionBar(){
    ActionBar ab = getSupportActionBar();
    if (!ab.isShowing()) {
        ab.show();
    }
}

这是什么原因?

【问题讨论】:

  • 这是在黑暗中的镜头:您可能必须明确启用动画。试试getSupportActionBar().setShowHideAnimationEnabled(true)。请注意,动画显示和隐藏仅适用于 API 14 及更高版本。
  • 我之前试过了,还是不行。无论如何,它应该默认为它设置动画。在这个实现的某个地方,我有一些东西会阻止动画,但是在哪里?
  • @Bart Burg,你在用什么 - ActionBarToolBar
  • @VladimirMarkeev,工具栏,虽然我确实设置了它:setSupportActionBar(toolbar);
  • @Bart Burg,尝试将动画应用到ToolBar,正如 Anoop M 回复的那样,点击此链接 - stackoverflow.com/questions/26539623/…

标签: android animation android-actionbar


【解决方案1】:

您可以在 xml 中使用以下代码,即,当您调用隐藏/显示时,工具栏父级将对其进行动画处理。

android:animateLayoutChanges="true"

或者这个

隐藏

toolbarParent.animate().translationY(-toolbarHeight).setInterpolator(new AccelerateInterpolator(2)).start();

显示

toolbarParent.animate().translationY(0).setInterpolator(new DecelerateInterpolator(2)).start();

【讨论】:

    【解决方案2】:

    请放弃我上面的评论。我对此做了一些研究,我上面的建议没有任何意义。

    当您拨打setSupportActionBar(Toolbar) 时,会发生以下情况:

    public void setSupportActionBar(Toolbar toolbar) {
        ....
        ToolbarActionBar tbab = new ToolbarActionBar(toolbar, ((Activity) mContext).getTitle(),
                mAppCompatWindowCallback);
        mActionBar = tbab;
        ....
    }
    

    因此,对getSupportActionBar() 的后续调用会返回ToolbarActionBar 的实例。看看这个类是如何实现我们感兴趣的功能的:

    setShowHideAnimationEnabled(boolean):正如你所说,这个方法没有区别。

    @Override
    public void setShowHideAnimationEnabled(boolean enabled) {
        // This space for rent; no-op.
    }
    

    show(): 仅使操作栏可见 - 不支持动画。

    @Override
    public void show() {
        // TODO: Consider a better transition for this.
        // Right now use no automatic transition so that the app can supply one if desired.
        mDecorToolbar.setVisibility(View.VISIBLE);
    }
    

    hide(): 仅使操作栏可见 - 同样,不支持动画。

    @Override
    public void hide() {
        // TODO: Consider a better transition for this.
        // Right now use no automatic transition so that the app can supply one if desired.
        mDecorToolbar.setVisibility(View.GONE);
    }
    

    show()hide() 中的 cmets 提示开发人员应提供动画过渡。或许,是这样的:

    protected void hideActionBar(){
        final ActionBar ab = getSupportActionBar();
        if (ab != null && ab.isShowing()) {
            if(mToolbar != null) {
                mToolbar.animate().translationY(-112).setDuration(600L)
                        .withEndAction(new Runnable() {
                            @Override
                            public void run() {
                                ab.hide();
                            }
                        }).start();
            } else {
                ab.hide();
            }
        }
    }
    
    protected void showActionBar(){
        ActionBar ab = getSupportActionBar();
        if (ab != null && !ab.isShowing()) {
            ab.show();
            if(mToolbar != null) {
                mToolbar.animate().translationY(0).setDuration(600L).start();
            }
        }
    }
    

    mToolbar.animate()..... 部分是从内存中写入的 - 语法可能不正确 :(。您还可以添加 .alpha(0(during hide) or 1(during show)) 以使过渡看起来更好。

    实施:

    现在应该清楚的是,getSupportActionBar().show() &amp; hide() 并不关心您如何处理您的 Toolbar 以及这些方法调用。此外,Toolbar 将被视为 Activity 中的任何其他 View。牢记这些要点,问题归结为 - 我们如何动画隐藏(以及稍后显示)View。由于我们需要 Activity 内容与隐藏(或显示)Toolbar 一起滑动,我建议以下实现。请注意,这只是一个基本的常规例程。您当然可以对此进行微调,或者提出一个完全不同的(阅读更好)动画过渡:

    // holds the original Toolbar height.
    // this can also be obtained via (an)other method(s)
    int mToolbarHeight, mAnimDuration = 600/* milliseconds */;
    
    ValueAnimator mVaActionBar;
    
    void hideActionBar() {
        // initialize `mToolbarHeight`
        if (mToolbarHeight == 0) {
            mToolbarHeight = mToolbar.getHeight();
        }
    
        if (mVaActionBar != null && mVaActionBar.isRunning()) {
            // we are already animating a transition - block here
            return;
        }
    
        // animate `Toolbar's` height to zero.
        mVaActionBar = ValueAnimator.ofInt(mToolbarHeight , 0);
        mVaActionBar.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                // update LayoutParams
                ((AppBarLayout.LayoutParams)mToolbar.getLayoutParams()).height
                        = (Integer)animation.getAnimatedValue();
                mToolbar.requestLayout();
            }
        });
    
        mVaActionBar.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
    
                if (getSupportActionBar() != null) { // sanity check
                    getSupportActionBar().hide();
                }
            }
        });
    
        mVaActionBar.setDuration(mAnimDuration);
        mVaActionBar.start();
    }
    
    void showActionBar() {
        if (mVaActionBar != null && mVaActionBar.isRunning()) {
            // we are already animating a transition - block here
            return;
        }
    
        // restore `Toolbar's` height
        mVaActionBar = ValueAnimator.ofInt(0 , mToolbarHeight);
        mVaActionBar.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                // update LayoutParams
                ((AppBarLayout.LayoutParams)mToolbar.getLayoutParams()).height
                        = (Integer)animation.getAnimatedValue();
                mToolbar.requestLayout();
            }
        });
    
        mVaActionBar.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationStart(Animator animation) {
                super.onAnimationStart(animation);
    
                if (getSupportActionBar() != null) { // sanity check
                    getSupportActionBar().show();
                }
            }
        });
    
        mVaActionBar.setDuration(mAnimDuration);
        mVaActionBar.start();
    }
    

    在您的评论中,您提到了I do see an animation now but the space still gets reserved for the toolbar until ab.hide() happens。对我来说,这意味着您使用AppBarLayout 来托管Toolbar。如果不是这样,请告诉我,我们会想办法解决的。

    最后,对这些方法的调用将基于:

    if (getSupportActionBar().isShowing()) {
        hideActionBar();
    } else {
        showActionBar();
    }
    

    【讨论】:

    • 感谢您的广泛研究。我现在确实看到了一个动画,但是在 ab.hide() 发生之前,该空间仍然保留给工具栏。这将使内容在动画之后跳转,而不是与动画一起跳转。
    • @BartBurg 感谢您的编辑。我在上面的示例代码中添加了更多信息。看看这是否能让你按照你的想法去做。
    【解决方案3】:

    我建议您尝试cheesesquare 示例。这是一个折叠和展开工具栏的布局。

    <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/main_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <android.support.design.widget.AppBarLayout
            android:id="@+id/appbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
    
            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="?attr/colorPrimary"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
                app:layout_scrollFlags="scroll|enterAlways|snap" />
    
            <android.support.design.widget.TabLayout
                android:id="@+id/tabs"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />
    
        </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.FloatingActionButton
            android:id="@+id/fab"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="end|bottom"
            android:layout_margin="@dimen/fab_margin"
            android:src="@drawable/ic_done" />
    
    </android.support.design.widget.CoordinatorLayout>
    

    【讨论】:

      【解决方案4】:

      如果您在活动中使用 CoordinatorLayout,请使用:

      <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_scrollFlags="scroll|enterAlways" />
      

      app:layout_scrollFlags="scroll|enterAlways" 行将导致我们的工具栏在用户向下滚动列表时滚动到屏幕之外,而一旦他开始向上滚动,工具栏就会再次出现。

      【讨论】:

        【解决方案5】:

        如果您使用默认动画隐藏或显示,请尝试以下操作:

        在您的父级toolbar 中添加android:animateLayoutChanges="true" 在本例中为AppBarLayout

        <android.support.design.widget.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:theme="@style/AppTheme.AppBarOverlay"
            android:animateLayoutChanges="true">
        
            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="?attr/colorPrimary"
                app:popupTheme="@style/AppTheme.PopupOverlay"
        
                />
        
        </android.support.design.widget.AppBarLayout>
        

        切换代码hideshow

        final ActionBar actionBar = getSupportActionBar();
        
        if (actionBar != null) {
        
            if (actionBar.isShowing()) {
                actionBar.hide();
            } else {
                actionBar.show();
            }
        
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-10-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-02-25
          • 2016-02-02
          相关资源
          最近更新 更多