6

Ho lavorato principalmente con iOS e mi sono abituato a animazioni di cambio schermo molto fluide e fluide. Ora sto lavorando su un'app per Android e non riesco a ottenere una transazione frammentata per aggiungere/sostituire un frammento senza problemi.Come ottenere animazioni di transazione frammentate su Android

Il mio set up è la seguente: MainActivity ha un FrameLayout per il suo XML che ho subito carico FragmentA in data s' OnCreate il MainActivity. La mia app procede quindi alla sostituzione dello MainActivity di FrameLayout con FragmentB, FragmentC, ecc. Quindi la mia intera app ha 1 attività.

Su clic sul pulsante che io chiamo il seguente per aggiungere/sostituire il frammento corrente:

 getFragmentManager() 
      .beginTransaction() 
      .setCustomAnimations(R.animator.slide_in, android.R.animator.fade_out, android.R.animator.fade_in, R.animator.slide_out) 
      .addToBackStack(null) 
      .add(R.id.fragment_1, fragment) 
      .commit(); 

slide_in.xml assomiglia (slide_out.xml è ovviamente il contrario):

<?xml version="1.0" encoding="utf-8"?> 
<set xmlns:android="http://schemas.android.com/apk/res/android"> 
    <objectAnimator 
      android:interpolator="@android:interpolator/linear" 
      android:propertyName="xFraction" 
      android:valueType="floatType" 
      android:valueFrom="1.0" 
      android:valueTo="0" 
      android:duration="@android:integer/config_shortAnimTime" 
     /> 
</set> 

scorrevole in e fuori sto animando xFraction che ho sottoclassato LinearLayout da fare in questo modo:

public class SlidingLinearLayout extends LinearLayout { 

    private float yFraction = 0; 
    private float xFraction = 0; 

    public SlidingLinearLayout(Context context) { 
     super(context); 
    } 

    public SlidingLinearLayout(Context context, AttributeSet attrs) { 
     super(context, attrs); 
    } 

    public SlidingLinearLayout(Context context, AttributeSet attrs, int defStyle) { 
     super(context, attrs, defStyle); 
    } 

    private ViewTreeObserver.OnPreDrawListener preDrawListener = null; 

    public void setYFraction(float fraction) { 

     this.yFraction = fraction; 

     if (getHeight() == 0) { 
      if (preDrawListener == null) { 
       preDrawListener = new ViewTreeObserver.OnPreDrawListener() { 
        @Override 
        public boolean onPreDraw() { 
         getViewTreeObserver().removeOnPreDrawListener(preDrawListener); 
         setYFraction(yFraction); 
         return true; 
        } 
       }; 
       getViewTreeObserver().addOnPreDrawListener(preDrawListener); 
      } 
      return; 
     } 

     float translationY = getHeight() * fraction; 
     setTranslationY(translationY); 
    } 

    public float getYFraction() { 
     return this.yFraction; 
    } 

    public void setXFraction(float fraction) { 

     this.xFraction = fraction; 

     if (getWidth() == 0) { 
      if (preDrawListener == null) { 
       preDrawListener = new ViewTreeObserver.OnPreDrawListener() { 
        @Override 
        public boolean onPreDraw() { 
         getViewTreeObserver().removeOnPreDrawListener(preDrawListener); 
         setXFraction(xFraction); 
         return true; 
        } 
       }; 
       getViewTreeObserver().addOnPreDrawListener(preDrawListener); 
      } 
      return; 
     } 

     float translationX = getWidth() * fraction; 
     setTranslationX(translationX); 
    } 

    public float getxFraction() { 
     return xFraction; 
    } 
} 

Quindi il mio problema è il più delle volte quando inizialmente faccio clic su un pulsante per aggiungere/sostituire un frammento, non ottengo un'animazione, ma viene semplicemente inserito. Tuttavia più volte che non quando premo il pulsante Indietro e il frammento si apre dal backstack l'animazione si esegue come previsto. Sento che è un problema con l'inizializzazione durante il tentativo di animare. Quando il frammento è in memoria e animato fuori dallo schermo, lo fa molto meglio di quando viene creato un nuovo frammento e poi animato sullo schermo. Sono curioso di sapere se altri hanno sperimentato questo e, in tal caso, come lo hanno risolto.

Questo è un fastidio che ha afflitto la mia esperienza di sviluppo Android che mi piacerebbe davvero mettere a tacere! Qualsiasi aiuto sarebbe molto apprezzato. Grazie!

+0

Ultimamente ho avuto lo stesso problema. La prima volta che passa la transizione, è un po 'janky. Ho scoperto che eliminare gli alfa non necessari aiuta, ma non rimuove completamente il problema. – Eliezer

risposta

1

Nella mia esperienza, se il frammento sta facendo troppo lavoro sul caricamento, il sistema salterà fondamentalmente l'animazione di invio e mostrerà solo il frammento. Nel mio caso la soluzione era creare un listener di animazione in onCreateAnimation per attendere fino a quando l'animazione di inserimento non fosse terminata prima di eseguire il lavoro intensivo del processo che causava l'omissione dell'animazione.

@Override 
public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) { 
    if (nextAnim == 0) { 
     return super.onCreateAnimation(transit, enter, nextAnim); 
    } 

    Animation anim = android.view.animation.AnimationUtils.loadAnimation(getContext(), nextAnim); 
    anim.setAnimationListener(new Animation.AnimationListener() { 
     @Override 
     public void onAnimationStart(Animation animation) {} 
     @Override 
     public void onAnimationEnd(Animation animation) { 
      // Do any process intensive work that can wait until after fragment has loaded 
     } 

     @Override 
     public void onAnimationRepeat(Animation animation) {} 
    }); 
    return anim; 
} 
Problemi correlati