24

Per impostazione predefinita in Android 3.0+, quando ActionBar.hide()/show() viene chiamato, la barra viene animata con una breve animazione di dissolvenza in entrata/uscita.Cambiare la barra delle azioni nasconde l'animazione?

Non sembra essere un attributo di stile XML in this list associato a una risorsa di animazione.

C'è qualche modo per cambiare questa animazione? Nel mio caso, voglio semplicemente cambiare il tempo di animazione, ma è anche possibile avere un'animazione scorrevole?

risposta

34

No.

Almeno non in 3.0, 3.1 o 3.2. Se guardi le fonti decompilate di com.android.internal.app.ActionBarImpl troverai che le animazioni sono hard-coded.

Ad esempio, dal 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 

UPDATE

stesso vale per ICS e Jellybean

+3

+1 per groking codice decompilato! – dokkaebi

+1

Qualche aggiornamento per ICS? –

+0

@ N.R.S.Sowrabh No. Né Jelly Bean. –

15

Un hack per disabilitare l'animazione ActionBar (trovato esaminando il codice sorgente) può essere fatto attraverso l'introspezione tramite:

try 
{ 
    getActionBar().getClass().getDeclaredMethod("setShowHideAnimationEnabled", boolean.class).invoke(getActionBar(), false); 
} 
catch (Exception exception) 
{ 
    // Too bad, the animation will be run ;(
} 

Brutto, ovviamente, ma in realtà funziona, almeno da Android v4.2.

+0

come farlo funzionare dalla 3.0? –

+0

Buon lavoro! Odio incidere ma a volte non c'è scelta! – PiersyP

+0

Davvero utile !! – user782104

4

se si utilizza il supporto-v7-compat, è possibile disattivare nascondere l'animazione in questo modo:

@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){ 
      //.... 
     } 
    } 
} 
3

Nessuna delle soluzioni non funziona per me così provo questo per disattivare l'animazione a tutti :

public View 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); 
    } 
} 

E funziona bene per me. Puoi provare ad animare tutta la barra delle azioni viewGroup per ottenere un effetto simile.

+0

Ho aggiunto la correzione per API21 + – MikhailKrishtop

1

Sì, lo puoi sicuramente.

Per prima cosa ottiene la vista ActionBar in questo modo:

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

Quindi è possibile applicare animazioni direttamente sulla vista in questo modo:

View actionbar = getActionBarView(); 
actionbar.setTranslation(-48); // move it out of the screen 
+0

Non ci sono metodi setTranslation in vista –

+0

@Mik è possibile utilizzare setVisibility() invece – torvin

+0

Sì, ma non aiuta a eliminare o modificare l'animazione. –