默认情况下,在 Android 3.0+ 中,当调用 ActionBar.hide()/show() 时,该栏会使用简短的淡入/淡出动画进行动画处理。
此列表中似乎没有与动画资源关联的 XML 样式属性。
有没有办法改变这个动画?就我而言,我只是想改变动画时间,但也可以有滑动动画吗?
默认情况下,在 Android 3.0+ 中,当调用 ActionBar.hide()/show() 时,该栏会使用简短的淡入/淡出动画进行动画处理。
此列表中似乎没有与动画资源关联的 XML 样式属性。
有没有办法改变这个动画?就我而言,我只是想改变动画时间,但也可以有滑动动画吗?
不。
至少在 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 也是如此
禁用 ActionBar 动画(通过检查源代码找到)的 hack 可以通过自省来完成:
try
{
getActionBar().getClass().getDeclaredMethod("setShowHideAnimationEnabled", boolean.class).invoke(getActionBar(), false);
}
catch (Exception exception)
{
// Too bad, the animation will be run ;(
}
丑,当然,但这确实有效,至少从 Android v4.2 开始。
如果你使用 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){
//....
}
}
}
这两种解决方案都不适合我,所以我尝试这个来禁用动画:
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);
}
}
它对我来说很好用。您可以尝试为整个操作栏 viewGroup 设置动画以达到类似的效果。
是的,你当然可以。
你首先得到这样的 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