更改ActionBar隐藏动画?

24

在Android 3.0+中,默认情况下,当调用ActionBar.hide()/show()时,该栏会带有短暂的淡入/淡出动画。

此列表中似乎没有与动画资源相关联的XML样式属性。

是否有一些方法可以更改此动画?在我的情况下,我只想更改动画时间,但是否也可能有滑动动画?


现在只需要使用 getSupportActionBar().setShowHideAnimationEnabled(false); - Ivan Mir
5个回答

34

不行。

至少在3.0、3.1或3.2版本中不行。如果你查看com.android.internal.app.ActionBarImpl的反编译源代码,会发现这些动画是硬编码的。

例如,在3.2中:

.method public hide()V
    .locals 8

    .prologue
    const/4 v5, 0x0

    const/4 v7, 0x0

    const/4 v6, 0x1

    .line 529
    iget-object v2, p0, Lcom/android/internal/app/ActionBarImpl;->mCurrentAnim:Landroid/animation/Animator;

    if-eqz v2, :cond_0

    .line 530
    iget-object v2, p0, Lcom/android/internal/app/ActionBarImpl;->mCurrentAnim:Landroid/animation/Animator;

    invoke-virtual {v2}, Landroid/animation/Animator;->end()V

    .line 532
    :cond_0
    iget-object v2, p0, Lcom/android/internal/app/ActionBarImpl;->mContainerView:Lcom/android/internal/widget/ActionBarContainer;

    invoke-virtual {v2}, Lcom/android/internal/widget/ActionBarContainer;->getVisibility()I

    move-result v2

    const/16 v3, 0x8

    if-ne v2, v3, :cond_1

    .line 553
    :goto_0
    return-void

    .line 536
    :cond_1
    iget-boolean v2, p0, Lcom/android/internal/app/ActionBarImpl;->mShowHideAnimationEnabled:Z

    if-eqz v2, :cond_3

    .line 537
    iget-object v2, p0, Lcom/android/internal/app/ActionBarImpl;->mContainerView:Lcom/android/internal/widget/ActionBarContainer;

    const/high16 v3, 0x3f80

    invoke-virtual {v2, v3}, Lcom/android/internal/widget/ActionBarContainer;->setAlpha(F)V

    .line 538
    iget-object v2, p0, Lcom/android/internal/app/ActionBarImpl;->mContainerView:Lcom/android/internal/widget/ActionBarContainer;

    invoke-virtual {v2, v6}, Lcom/android/internal/widget/ActionBarContainer;->setTransitioning(Z)V

    .line 539
    new-instance v0, Landroid/animation/AnimatorSet;

    invoke-direct {v0}, Landroid/animation/AnimatorSet;-><init>()V

    .line 540
    .local v0, anim:Landroid/animation/AnimatorSet;
    iget-object v2, p0, Lcom/android/internal/app/ActionBarImpl;->mContainerView:Lcom/android/internal/widget/ActionBarContainer;

    const-string v3, "alpha"

    new-array v4, v6, [F

    aput v5, v4, v7

    invoke-static {v2, v3, v4}, Landroid/animation/ObjectAnimator;->ofFloat(Ljava/lang/Object;Ljava/lang/String;[F)Landroid/animation/ObjectAnimator;

    move-result-object v2

    invoke-virtual {v0, v2}, Landroid/animation/AnimatorSet;->play(Landroid/animation/Animator;)Landroid/animation/AnimatorSet$Builder;

    move-result-object v1

    .line 541
    .local v1, b:Landroid/animation/AnimatorSet$Builder;
    iget-object v2, p0, Lcom/android/internal/app/ActionBarImpl;->mContentView:Landroid/view/View;

    if-eqz v2, :cond_2

    .line 542
    iget-object v2, p0, Lcom/android/internal/app/ActionBarImpl;->mContentView:Landroid/view/View;

    const-string/jumbo v3, "translationY"

    const/4 v4, 0x2

    new-array v4, v4, [F

    aput v5, v4, v7

    iget-object v5, p0, Lcom/android/internal/app/ActionBarImpl;->mContainerView:Lcom/android/internal/widget/ActionBarContainer;

    invoke-virtual {v5}, Lcom/android/internal/widget/ActionBarContainer;->getHeight()I

    move-result v5

    neg-int v5, v5

    int-to-float v5, v5

    aput v5, v4, v6

    invoke-static {v2, v3, v4}, Landroid/animation/ObjectAnimator;->ofFloat(Ljava/lang/Object;Ljava/lang/String;[F)Landroid/animation/ObjectAnimator;

    move-result-object v2

    invoke-virtual {v1, v2}, Landroid/animation/AnimatorSet$Builder;->with(Landroid/animation/Animator;)Landroid/animation/AnimatorSet$Builder;

    .line 544
    iget-object v2, p0, Lcom/android/internal/app/ActionBarImpl;->mContainerView:Lcom/android/internal/widget/ActionBarContainer;

    const-string/jumbo v3, "translationY"

    new-array v4, v6, [F

    iget-object v5, p0, Lcom/android/internal/app/ActionBarImpl;->mContainerView:Lcom/android/internal/widget/ActionBarContainer;

    invoke-virtual {v5}, Lcom/android/internal/widget/ActionBarContainer;->getHeight()I

    move-result v5

    neg-int v5, v5

    int-to-float v5, v5

    aput v5, v4, v7

    invoke-static {v2, v3, v4}, Landroid/animation/ObjectAnimator;->ofFloat(Ljava/lang/Object;Ljava/lang/String;[F)Landroid/animation/ObjectAnimator;

    move-result-object v2

    invoke-virtual {v1, v2}, Landroid/animation/AnimatorSet$Builder;->with(Landroid/animation/Animator;)Landroid/animation/AnimatorSet$Builder;

    .line 547
    :cond_2
    iget-object v2, p0, Lcom/android/internal/app/ActionBarImpl;->mHideListener:Landroid/animation/Animator$AnimatorListener;

    invoke-virtual {v0, v2}, Landroid/animation/AnimatorSet;->addListener(Landroid/animation/Animator$AnimatorListener;)V

    .line 548
    iput-object v0, p0, Lcom/android/internal/app/ActionBarImpl;->mCurrentAnim:Landroid/animation/Animator;

    .line 549
    invoke-virtual {v0}, Landroid/animation/AnimatorSet;->start()V

    goto :goto_0

    .line 551
    .end local v0           #anim:Landroid/animation/AnimatorSet;
    .end local v1           #b:Landroid/animation/AnimatorSet$Builder;
    :cond_3
    iget-object v2, p0, Lcom/android/internal/app/ActionBarImpl;->mHideListener:Landroid/animation/Animator$AnimatorListener;

    const/4 v3, 0x0

    invoke-interface {v2, v3}, Landroid/animation/Animator$AnimatorListener;->onAnimationEnd(Landroid/animation/Animator;)V

    goto :goto_0
.end method

更新

对于ICS和JellyBean同样适用。


@N.R.S.Sowrabh 没有。也不是果冻豆。 - Jake Wharton

15
可以通过内省的方式,使用以下代码来禁用ActionBar动画(在检查源代码后发现):
try
{
  getActionBar().getClass().getDeclaredMethod("setShowHideAnimationEnabled", boolean.class).invoke(getActionBar(), false);
}
catch (Exception exception)
{
  // Too bad, the animation will be run ;(
}

当然很丑,但这实际上是有效的,至少在Android v4.2以上可用。


1
太棒了!那帮助并且同时教会了我很多 ^_^ - Marcel Blanck

4
如果您使用的是 support-v7-compat,您可以像这样禁用隐藏动画:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    //消除动画效果
    disableABCShowHideAnimation(getSupportActionBar());
    return super.onCreateOptionsMenu(menu);
}



public static void disableABCShowHideAnimation(ActionBar actionBar) {
    try
    {
        actionBar.getClass().getDeclaredMethod("setShowHideAnimationEnabled", boolean.class).invoke(actionBar, false);
    }
    catch (Exception exception)
    {
        try {
            Field mActionBarField = actionBar.getClass().getSuperclass().getDeclaredField("mActionBar");
            mActionBarField.setAccessible(true);
            Object icsActionBar = mActionBarField.get(actionBar);
            Field mShowHideAnimationEnabledField = icsActionBar.getClass().getDeclaredField("mShowHideAnimationEnabled");
            mShowHideAnimationEnabledField.setAccessible(true);
            mShowHideAnimationEnabledField.set(icsActionBar,false);
            Field mCurrentShowAnimField = icsActionBar.getClass().getDeclaredField("mCurrentShowAnim");
            mCurrentShowAnimField.setAccessible(true);
            mCurrentShowAnimField.set(icsActionBar,null);
            //icsActionBar.getClass().getDeclaredMethod("setShowHideAnimationEnabled", boolean.class).invoke(icsActionBar, false);
        }catch (Exception e){
            //....
        }
    }
}

4

对我来说,这两个解决方案都不起作用,所以我尝试禁用所有动画:

public void setActionBarVisible(boolean isVisible) {
    View decorView = getWindow().getDecorView();
    int resId;
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB
        || Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        resId = getResources().getIdentifier(
                "action_bar_container", "id", getPackageName());
    } else {
        resId = Resources.getSystem().getIdentifier(
                "action_bar_container", "id", "android");
    }
    if (resId != 0) {
        decorView.findViewById(resId).setVisibility(isVisible ? View.VISIBLE : View.GONE);
    }
}

对我来说,它可以正常工作。你可以尝试将整个操作栏视图组动画化以实现类似的效果。


我已经为API21+添加了修复。 - MikhailKrishtop

1

是的,你当然可以。

首先要像这样获取ActionBar视图:

public View getActionBarView() {
    Window window = getActivity().getWindow();
    View v = window.getDecorView();
    int resId = getResources().getIdentifier("action_bar_container", "id", "android");
    return v.findViewById(resId);
}

然后,您可以直接在视图上应用动画,如下所示:
View actionbar = getActionBarView();
actionbar.setTranslation(-48); // move it out of the screen

视图中没有setTranslation方法。 - mc.dev
@Mik,你可以使用setVisibility()代替。 - torvin
是的,但它不能帮助消除或更改动画。 - mc.dev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接