15

UPDATE: Lösung gefunden! Scrollen Sie nach unten für meine angenommene Antwort!Präzise Kontrolle über Androiden VectorDrawable Animationen

Ich möchte mehrere Elemente eines Bildes animieren und die Animation mit der Position von ViewPagers verknüpfen (so dass mehrere Elemente morphen oder hineinfliegen, abhängig von der aktuellen Seite, die gezogen wird).

Gibt es also eine Möglichkeit, den aktuellen Frame der Animation präzise zu steuern? Zum Beispiel nehmen wir an, ich habe diesen Satz:

<?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> 

animierte Vektordatei:

<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> 

Java Code, um die Animation zu starten:

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

animated.start(); 

Gibt es einen Weg, um die Animation zu steuern, wie setCurrentDuration(400) welcher wird vermutlich den aktuellen Stand der Animation auf die Hälfte setzen? Vielleicht gibt es eine Möglichkeit, den Vektor in Ebenen zu teilen und sie programmatisch zu animieren? Danke im Voraus!

+0

@pskink Ich habe etwas mehr Code hinzugefügt. Wie kann ich 'setCurrentFraction' Breitenvektoranimation verwenden? – Arthur

Antwort

7

Sieht aus wie es möglich ist, auf Pfade und Gruppen innerhalb VectorDrawableCompat zuzugreifen und sie zu animieren/zu morphen, wie Sie wollen!

Nach einigen Recherchen habe ich die folgenden Klassen aus dem android.support.graphics.drawable Paket duplizieren endete: AndroidResources, PathParser, TypedArrayUtils, VectorDrawableCommon und VectorDrawableCompat.

Als nächstes müssen wir innerhalb der VectorDrawableCompat Klasse der folgenden Methode und Klassen öffentlich machen: getTargetByName, VGroup und VFullPath.

Als nächstes in der VectorDrawableCompat Klasse entfernen Sie den Block, der für Android-Version (Build.VERSION.SDK_INT >= 23) überprüft. Ich weiß nicht warum, aber wenn du es nicht machst, funktioniert das Animieren nicht auf Android API 23 und höher (brauche mehr Nachforschungen).

Ich habe vielleicht ein paar private Methoden verpasst, aber es ist nur eine Frage der Veröffentlichung sie, wenn Sie auf Probleme stoßen.

So, jetzt haben wir Zugriff auf die Schichten unserer VectorDrawable! Hier ist ein kleines Beispiel eine Vektorgruppe der Skalierung in Abhängigkeit von den ViewPager ‚s Position:

<?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> 

Und dies ist der Code verwendet, um die Gruppe zu animieren:

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(); 
      } 
     } 
    }); 
} 

ich einige Tests müssen zu bestimmen, Kompatibilität, aber es funktioniert für jetzt!

+0

Noch nicht ausprobiert, aber nette Arbeit. Es ist eine Schande, dass die AnimatedVectorDrawable diese Fähigkeit out of the Box fehlt. –

+0

Ja, darüber spreche ich! :(Ich benutze diese Möglichkeit jetzt überall und mit wirklich komplexen Animationen! Und es ist ziemlich schnell auch auf älteren Geräten! – Arthur

+0

@Arthur Ich sehe keinen Code, um Pfaddaten zu interpolieren, nachdem Sie den vorhandenen Code für vectorDrawable geändert haben Bitte teilen Sie den ganzen Code, um klar zu verstehen, wie Sie erreicht haben pathData Morph in Pre-Lollipop-Gerät dh API 15 über –

1

Soweit die Dokumentation für AnimatedVectorDrawables besagt, gibt es keine Möglichkeit, den Status der Animation zu verfolgen oder in einen anderen Zustand als animationStart und animationEnd zu springen.

Möglicherweise müssen Sie eine benutzerdefinierte Lösung verwenden, um diesen Effekt zu erzielen. This blog post erläutert eine Möglichkeit, die Android-Widget-Statusverfolgung zu verwenden, um einen ähnlichen Effekt zu erzielen.

+0

Vielleicht gibt es eine andere Möglichkeit, Objekte vor und zurück zu animieren? Ich meine nicht Vektorgruppen, aber vielleicht getrennte 'ImageView's? – Arthur

1

Ich glaube, dass Sie dies nicht mit der AnimatedVectorDrawable/AnimatedVectorDrawableCompat programmgesteuert tun können.

Eine Abhilfe ein Level List drawable zu verwenden ist und animieren ihre Ebene: aber Sie werden für die Ebene viele Bilder brauchen den reibungslosen Übergang zu simulieren, ich bin nur mit drei Ebenen hier zur Demonstration.

Zuerst werden Sie die ziehbar Ebene Liste wie folgt definieren: res/ziehbar/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> 

dann in der Layout-Datei:

<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" /> 

Dann in Ihrer Aktivität:

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(); 

Hoffe, dass hilft.