15

UPDATE: Soluzione trovata! Scorri verso il basso per la mia risposta accettata!Controllo preciso su Androidi Vettore Animazioni disegnabili

Desidero animare più elementi di un'immagine e collegare l'animazione alla posizione di ViewPagers (quindi più elementi si trasformano o entrano/escono a seconda della pagina corrente trascinata).

Quindi, c'è un modo per controllare con precisione il fotogramma corrente dell'animazione? Per esempio supponiamo ho questo set:

<?xml version="1.0" encoding="utf-8"?> 
<set xmlns:android="http://schemas.android.com/apk/res/android"> 
    <objectAnimator 
     android:interpolator="@android:anim/decelerate_interpolator" 
     android:duration="800" 
     android:propertyName="scaleY" 
     android:valueFrom="0" 
     android:valueTo="1" /> 
    <objectAnimator 
     android:interpolator="@android:anim/decelerate_interpolator" 
     android:duration="800" 
     android:propertyName="scaleX" 
     android:valueFrom="0" 
     android:valueTo="1" /> 
    <objectAnimator 
     android:interpolator="@android:anim/decelerate_interpolator" 
     android:duration="800" 
     android:propertyName="rotation" 
     android:valueFrom="0" 
     android:valueTo="360" /> 
</set> 

animato file vettoriale:

<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" 
    android:drawable="@drawable/pre_signup_1" > 
    <target 
     android:name="plus_button" 
     android:animation="@anim/pre_signup_1_plus_container" /> 
    <target 
     android:name="plus" 
     android:animation="@anim/pre_signup_1_plus_sign" /> 
</animated-vector> 

codice Java per eseguire l'animazione:

ImageView mImage1 = (ImageView) findViewById(R.id.image_1); 
AnimatedVectorDrawableCompat animated = (AnimatedVectorDrawableCompat) mImage1.getDrawable(); 

animated.start(); 

C'è un modo per controllare l'animazione come setCurrentDuration(400) che presumibilmente imposterà lo stato corrente dell'animazione a metà? Forse c'è un modo per dividere quel vettore estraibile in livelli e animarli a livello di codice? Grazie in anticipo!

+0

@pskink Ho aggiunto altro codice. Come posso usare l'animazione vettoriale 'setCurrentFraction' width? – Arthur

risposta

7

Sembra che sia possibile accedere a percorsi e gruppi all'interno di VectorDrawableCompat e animarli/trasformarli come si desidera!

Dopo un po 'di ricerca ho finito per duplicare le seguenti classi dal pacchetto android.support.graphics.drawable: AndroidResources, PathParser, TypedArrayUtils, VectorDrawableCommon e VectorDrawableCompat.

Successivamente è necessario rendere pubblico il seguente metodo e classi all'interno della classe VectorDrawableCompat: getTargetByName, VGroup e VFullPath.

Avanti nella classe VectorDrawableCompat rimuovere il blocco che verifica la versione per Android (Build.VERSION.SDK_INT >= 23). Non so perché, ma se non lo fai, l'animazione non funzionerà su Android API 23 e versioni successive (serve più ricerca).

Forse mi sono perso un paio di metodi privati, ma è solo questione di renderli pubblici se si incontrano problemi.

Così, ora abbiamo accesso agli strati del nostro VectorDrawable! Ecco un piccolo esempio di scalare un gruppo di vettore a seconda della posizione s' il ViewPager:

<?xml version="1.0" encoding="utf-8"?> 
<vector xmlns:android="http://schemas.android.com/apk/res/android" 
    android:width="276dp" 
    android:height="359dp" 
    android:viewportWidth="276" 
    android:viewportHeight="359"> 

    <group 
     android:pivotX="205.5" 
     android:pivotY="214.5" 
     android:name="my_group"> 
     <path 
      android:strokeColor="#4D394B" 
      android:strokeWidth="7" 
      android:strokeLineJoin="bevel" 
      android:fillColor="#1ED761" 
      android:pathData="M206.5,180 C186.9,180,171,195.9,171,215.5 S186.9,251,206.5,251 
C226.1,251,242,235.1,242,215.5 S226.1,180,206.5,180 Z" /> 
     <path 
      android:fillColor="#4D394B" 
      android:pathData="M210,211 L210,190 L202,190 L202,211 L181,211 L181,219 L202,219 L202,241 L210,241 
L210,219 L232,219 L232,211 Z" /> 
    </group> 
</vector> 

E questo è il codice utilizzato per animare il gruppo:

ImageView myImageView; 
VectorDrawableCompat.VGroup myVectorGroup; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_welcome); 

    myImageView = (ImageView) findViewById(R.id.image_1); 

    VectorDrawableCompat vectorDrawable = VectorDrawableCompat.create(getResources(), R.drawable.my_vector_drawable, null); 
    vectorDrawable.setAllowCaching(false); // Important to allow image updates 
    myVectorGroup = (VectorDrawableCompat.VGroup) vectorDrawable.getTargetByName("my_group"); 

    myImageView.setImageDrawable(vectorDrawable); 

    mViewPager = (ViewPager) findViewById(R.id.pager); 
    mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { 
     @Override 
     public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 
      if(myVectorGroup != null && position < 1) { 
       myVectorGroup.setScaleX(1f - positionOffset); 
       myVectorGroup.setScaleY(1f - positionOffset); 

       myImageView.invalidate(); 
      } 
     } 
    }); 
} 

Ho bisogno di ulteriori test per determinare compatibilità, ma funziona per ora!

+0

Non ancora provato, ma bel lavoro. E 'un peccato che AnimatedVectorDrawable non abbia questa abilità fuori dagli schemi. –

+0

Sì, questo è quello di cui sto parlando! :(Uso questa possibilità dappertutto ora e con animazioni davvero complesse! Ed è abbastanza veloce anche sui dispositivi più vecchi! – Arthur

+0

@Arthur Non vedo alcun codice per interpolare i dati del percorso dopo aver modificato il codice esistente per vectorDrawable. per favore condividi l'intero codice per capire chiaramente come hai ottenuto pathData morph nel dispositivo pre lollipop cioè API 15 sopra –

1

Per quanto riguarda la documentazione di AnimatedVectorDrawables, non è possibile tracciare lo stato dell'animazione o saltare in uno stato diverso da animationStart e animationEnd.

Potrebbe essere necessario utilizzare una soluzione personalizzata per ottenere questo effetto. This blog post spiega un modo utilizzando il monitoraggio dello stato dei widget di Android per ottenere un effetto simile.

+0

Forse c'è un altro modo per animare gli oggetti avanti e indietro? Non intendo gruppi di vettori, ma forse separo 'ImageView's? – Arthur

1

Credo che non sia possibile farlo con AnimatedVectorDrawable/AnimatedVectorDrawableCompat a livello di programmazione.

Una soluzione è quella di utilizzare un Level List drawable e animare le sue livelli: ma avrete bisogno di un sacco di immagini per i livelli per simulare il passaggio graduale, sto usando solo tre livelli qui per la dimostrazione.

Per prima cosa definire l'elenco drawable livello come questo: res/drawable/my_level_list.xml

<?xml version="1.0" encoding="utf-8"?> 
<level-list xmlns:android="http://schemas.android.com/apk/res/android"> 
<item android:drawable="@drawable/level0" 
    android:maxLevel="0"/> 
    <item android:drawable="@drawable/level1" 
     android:maxLevel="1"/> 

    <item android:drawable="@drawable/level2" 
     android:maxLevel="2"/> 
</level-list> 

Poi nel file di layout:

<ImageView 
     android:id="@+id/img" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_centerInParent="true" 
     android:src="@drawable/my_level_list" /> 

Poi nella vostra attività:

int MIN_LEVEL=0; 
int MAX_LEVEL=2; 

ImageView img=(ImageView)findViewById(R.id.img); 

Drawable myLevelSetDrawable= img.getDrawable(); 
ObjectAnimator anim=ObjectAnimator.ofInt(myLevelSetDrawable,"level",MIN_LEVEL,MAX_LEVEL); 
anim.setInterpolator(new BounceInterpolator()); 
AnimatorSet set=new AnimatorSet(); 
set.play(anim); 
set.setDuration(1000); 
set.start(); 

Spero che questo aiuti.