Animation d'attribut de collection d'animation Android - revoir


Introduction à cette section :

Dans la dernière section, nous avons mené une étude préliminaire de l'animation d'attributs d'Android. Je pense que tout le monde n'est plus familier avec l'animation d'attributs. Maintenant que nous en avons un peu connaissance, dans cette section, nous allons continuer à explorer des utilisations plus avancées des animations de propriétés Android ! Je publie toujours trois articles de Guo Shen~

Analyse complète de l'animation d'attribut Android (Partie 1), comprenant d'abord l'utilisation de base de l'animation d'attribut

Attribut Android animation Analyse complète (Partie 2), utilisation avancée de ValueAnimator et ObjectAnimator

Analyse complète de l'animation des propriétés Android (Partie 2), utilisation d'Interpolator et ViewPropertyAnimator

Le contenu est toujours Référez-vous aux trois articles ci-dessus, d'accord, commençons cette section~


1.Personnalisation de l'évaluateur

1) Introduction à l'évaluateur

8.4.3 Animation d'attributs de la collection d'animations Android - Premier aperçu dans la section précédente, la première étape de l'utilisation de l'animation est :

Appelez ofInt<🎜 de ValueAnimator > (), ofFloat() ou ofObject() crée une instance ValueAnimator !

Dans l'exemple, nous avons utilisé à la fois ofInt et ofFloat, qui sont utilisés respectivement pour animer des données à virgule flottante et entières !

Et

ofObject() ? Objet initial et objet final ? Comment faire la transition ? Ou comment utiliser cette chose ?

D'accord, avec des questions, comprenons d'abord quelque chose : Évaluateur. En fait, nous avons parlé de cette chose lorsque nous avons parlé du concept d'animation d'attributs :

1.png< 🎜. >

est utilisé pour indiquer au système d'animation comment passer de la valeur initiale à la valeur finale

 ! D'accord, notre point de départ est le bon ! Allons dans le code source d'IntEvaluator et voyons ce qui y est écrit ?

2.pngEh bien, l'interface

TypeEvaluator

est implémentée, puis la méthode evaluate() est réécrite, avec trois paramètres, dans ordre :

    fraction
  •  : Le degré d'achèvement de l'animation, sur la base duquel nous calculons quelle devrait être la valeur de l'animation
  • startValue
  •  : Le début de l'animation Valeur initiale
  • endValue
  •  : Valeur de fin de l'animation
Valeur de l'animation = valeur initiale + achèvement * ( valeur finale - valeur initiale)

La même chose est vraie pour FloatEvaluator Nous voulons indiquer au système comment passer de l'objet initial à l'objet final, nous devons alors le faire. Implémentez l'interface

TypeEvaluator

par vous-même, c'est-à-dire personnalisez l'évaluateur. Il est inutile d'en dire plus. Écrivez un exemple pour voir :

2) Exemple d'utilisation

<. 🎜>Rendu des opérations

 :

3.gif

Implémentation du code :

Définir un objet Point.java L'objet n'a que deux attributs : x et y. . get, set method~

/**
 * Created by Jay on 2015/11/18 0018.
 */
public class Point {

    private float x;
    private float y;

    public Point() {
    }

    public Point(float x, float y) {
        this.x = x;
        this.y = y;
    }

    public float getX() {
        return x;
    }

    public float getY() {
        return y;
    }

    public void setX(float x) {
        this.x = x;
    }

    public void setY(float y) {
        this.y = y;
    }
}

Puis personnalisez la classe Evaluator : PointEvaluator.java, implémentez l'interface et réécrivez la méthode d'évaluation~

/**
 * Created by Jay on 2015/11/18 0018.
 */
public class PointEvaluator implements TypeEvaluator{
    @Override
    public Point evaluate(float fraction, Point startValue, Point endValue) {
        float x = startValue.getX() + fraction * (endValue.getX() - startValue.getX());
        float y = startValue.getY() + fraction * (endValue.getY() - startValue.getY());
        Point point = new Point(x, y);
        return point;
    }
}

Puis personnalisez une classe View :AnimView.java, très simple~

/**
 * Created by Jay on 2015/11/18 0018.
 */
public class AnimView extends View {

    public static final float RADIUS = 80.0f;
    private Point currentPoint;
    private Paint mPaint;

    public AnimView(Context context) {
        this(context, null);
    }

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

    public AnimView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    private void init() {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(Color.BLUE);
    }

    private void drawCircle(Canvas canvas){
        float x = currentPoint.getX();
        float y = currentPoint.getY();
        canvas.drawCircle(x, y, RADIUS, mPaint);
    }

    private void startAnimation() {
        Point startPoint = new Point(RADIUS, RADIUS);
        Point endPoint = new Point(getWidth() - RADIUS, getHeight() - RADIUS);
        ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);
        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                currentPoint = (Point) animation.getAnimatedValue();
                invalidate();
            }
        });
        anim.setDuration(3000l);
        anim.start();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (currentPoint == null) {
            currentPoint = new Point(RADIUS, RADIUS);
            drawCircle(canvas);
            startAnimation();
        } else {
            drawCircle(canvas);
        }
    }
}

Enfin, instanciez cette vue à MainActivity.java~

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new AnimView(this));
    }
}

3) Exemple Version améliorée

Sur la base de notre exemple ci-dessus, nous ajoutons le changement de couleur lorsque le cercle bouge~ Ici, nous utilisons un autre ObjectAnimator pour charger l'animation de changement de couleur. Nous en ajoutons plusieurs. int color pour contrôler la couleur, et écrivons les méthodes getColor() et setColor(). Personnalisons d'abord un évaluateur~

Exécutons le rendu  :

4.gif.

Code d'implémentation:

ColorEvaluator.java:

/**
 * Created by Jay on 2015/11/18 0018.
 */
public class ColorEvaluator implements TypeEvaluator{
    @Override
    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
        int alpha = (int) (Color.alpha(startValue) + fraction *
                (Color.alpha(endValue) - Color.alpha(startValue)));
        int red = (int) (Color.red(startValue) + fraction *
                (Color.red(endValue) - Color.red(startValue)));
        int green = (int) (Color.green(startValue) + fraction *
                (Color.green(endValue) - Color.green(startValue)));
        int blue = (int) (Color.blue(startValue) + fraction *
                (Color.blue(endValue) - Color.blue(startValue)));
        return Color.argb(alpha, red, green, blue);
    }
}

Ensuite, personnalisez la vue et ajoutez une couleur, obtenez et définissez méthode ; créer un ObjectAnimator, et AnimatorSet, puis combiner les animations ensemble. Je vais juste ajouter quelques éléments ici, au cas où les lecteurs auraient des questions. Créez simplement une autre vue ~

AnimView2.java:

/**
 * Created by Jay on 2015/11/18 0018.
 */
public class AnimView2 extends View {

    public static final float RADIUS = 80.0f;
    private Point currentPoint;
    private Paint mPaint;
    private int mColor;

    public AnimView2(Context context) {
        this(context, null);
    }

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

    public AnimView2(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    private void init() {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(Color.BLUE);
    }



    private void drawCircle(Canvas canvas){
        float x = currentPoint.getX();
        float y = currentPoint.getY();
        canvas.drawCircle(x, y, RADIUS, mPaint);
    }

    private void startAnimation() {
        Point startPoint = new Point(RADIUS, RADIUS);
        Point endPoint = new Point(getWidth() - RADIUS, getHeight() - RADIUS);
        ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);
        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                currentPoint = (Point) animation.getAnimatedValue();
                invalidate();
            }
        });

        ObjectAnimator objectAnimator = ObjectAnimator.ofObject(this, "color", new ColorEvaluator(),
                Color.BLUE, Color.RED);
        //动画集合将前面两个动画加到一起,with同时播放
        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.play(anim).with(objectAnimator);
        animatorSet.setStartDelay(1000l);
        animatorSet.setDuration(3000l);
        animatorSet.start();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (currentPoint == null) {
            currentPoint = new Point(RADIUS, RADIUS);
            drawCircle(canvas);
            startAnimation();
        } else {
            drawCircle(canvas);
        }
    }

    //color的get和set方法~
    public int getColor() {
        return mColor;
    }

    public void setColor(int color) {
        mColor = color;
        mPaint.setColor(color);
        invalidate();
    }
}

Ensuite, dans MainActivity, setContentView, changez simplement AnimView en AnimView2~


2 .Interpolateur

Eh bien, nous avons parlé de ce genre de choses lorsque nous avons parlé d'animation d'interpolation~ Je me demande si vous vous en souvenez encore ?

L'animation d'interpolation et l'animation d'attribut ci-dessus sont disponibles, et l'animation d'interpolation ajoute également une nouvelle interface TimeInterpolator Cette interface est utilisée pour être compatible avec l'Interpolateur précédent, ce qui permet d'utiliser directement toutes les classes d'implémentation de l'Interpolateur antérieures. Utilisez-le dans l'animation d'attributs ! Nous pouvons appeler la méthode setInterpolator() de l'objet d'animation pour définir différents interpolateurs ! Nous devons d'abord cliquer sur quelque chose et laisser la balle tomber de haut en bas au centre de l'écran ~ Ensuite, nous appellerons l'instruction suivante pour notre animation d'ensemble : animatorSet.setInterpolator(new AccelerateInterpolator(2f));La valeur entre parenthèses est utilisée pour contrôler l'accélération~

Exécuter Effet  :

5.gif

semble un peu inhabituel. Normalement, il devrait rebondir avec BounceInterpolator~

<🎜. >6.gif

Hé, l'effet est assez étonnant. Bien sûr, il existe également de bons interpolateurs fournis par N nombre de systèmes. Vous pouvez les essayer un par un. Je ne veux pas m'inquiéter pour vous tous~

Jetons un coup d'œil ci-dessous :

1) Mécanisme d'implémentation interne d'Interpolator

Nous allons d'abord au code source de l'interface TimeInterpolator et constatons qu'il n'y a qu'une seule méthode getInterpolation()

7.png

Explication simple : La méthode getInterpolation() reçoit un paramètre d'entrée La valeur de ce paramètre continuera à changer au fur et à mesure de l'exécution de l'animation. Cependant, ses changements sont très réguliers, c'est-à-dire qu'ils augmentent à une vitesse constante en fonction de la durée d'animation définie, et la plage de changement est de 0 à 1. C'est-à-dire que lorsque l'animation commence, la valeur d'entrée est 0, lorsque l'animation se termine, la valeur d'entrée est 1 et la valeur au milieu est Il change entre 0 et 1 au fur et à mesure que l'animation s'exécute.

La valeur de input détermine ici la valeur de fraction dans notre interface TypeEvaluator. La valeur d'entrée est calculée par le système et transmise à la méthode getInterpolation(). Nous pouvons ensuite implémenter nous-mêmes l'algorithme dans la méthode getInterpolation() et calculer une valeur de retour basée sur la valeur d'entrée. est la fraction.

On peut regarder le code dans LinearInterpolator :

8.png

Il n'y a pas de traitement ici pour renvoyer directement la valeur d'entrée, c'est-à-dire , la valeur de la fraction est égale à la valeur de l'entrée, c'est un mouvement uniforme Comment Interpolator est implémenté ! En fait, il ne s’agit que de différents algorithmes, qui impliquent encore une fois des éléments mathématiques. Maintenant que j'ai réalisé l'importance des mathématiques, voici le code source de BounceInterpolator :

9.png

Ne me posez pas de questions sur l'algorithme ici, je je ne sais pas non plus. , trouvons quelque chose de plus facile à comprendre : AccelerateDecelerateInterpolator

Cet interpolateur accélère d'abord puis décélère : (float)(Math. cos( (input + 1) * Math.PI) / 2.0f) + 0.5fCompréhension algorithmique : 10.png

Solution : par entrée La plage de valeurs est [0,1]. On peut conclure que la plage de valeurs de cos est [π,2π] et les valeurs correspondantes sont -1 et 1 ; Après avoir divisé cette valeur par 2 et ajouté 0,5, la valeur du résultat final renvoyée par la méthode getInterpolation() est toujours dans la plage [0,1]. Le graphique de courbe correspondant est le suivant :

C'est donc un processus d'accélération d'abord puis de décélération !

Eh bien, je suis un salaud et je ne peux plus jouer...11.gif, tout ce qui précède est copié de l'article d'Oncle Guo... Je veux me taire...

2) Interpolateur personnalisé

D'accord, nous en occuperons plus tard. Écrivons d'abord un exemple d'interpolateur personnalisé : Très simple, implémentez l'interface TimeInterpolator, réécrivez la méthode getInterpolation

L'exemple de code est le suivant

private class DecelerateAccelerateInterpolator implements TimeInterpolator {
    @Override
    public float getInterpolation(float input) {
        if (input < 0.5) {
            return (float) (Math.sin(input * Math.PI) / 2);
        } else {
            return 1 - (float) (Math.sin(input * Math.PI) / 2);
        }
    }
}

Appelez setInterpolator(new DecelerateAccelerateInterpolator()) pour le définir~ En raison du manque d'espace, aucune image ne sera publiée~


3. ViewPropertyAnimator

Une nouvelle fonction ajoutée au système après la version 3.1 offre une utilisation plus pratique pour les opérations d'animation de vue ! Si c'était dans le passé, pour faire passer un TextView de l'état normal à l'état transparent, cela s'écrirait comme ceci :

ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "alpha", 0f);  
animator.start();

Utiliser ViewPropertyAnimator pour obtenir le même effet est plus compréhensible :

textview.animate().alpha(0f);
<🎜. > prend également en charge

Utilisation de la concaténation, combinez plusieurs animations, définissez la durée, définissez l'interpolateur, etc.~

textview.animate().x(500).y(500).setDuration(5000)  
        .setInterpolator(new BounceInterpolator());

L'utilisation est très simple, il suffit de consulter la documentation lors de son utilisation~, et il existe un quelques détails ci-dessous Faites attention !

    L'ensemble de la fonction ViewPropertyAnimator est basé sur la nouvelle méthode animate() de la classe View. Cette méthode créera et renverra une instance de ViewPropertyAnimator, et toutes les méthodes suivantes seront appelées. Toutes les propriétés définies sont effectuées via cette instance.
  • Utilisez ViewPropertyAnimator pour définir l'
  • animation, et l'animation démarrera automatiquement. Et ce mécanisme est également efficace pour les animations combinées, à condition de continuer à ajouter de nouvelles méthodes, Ensuite, l'animation ne sera pas exécutée immédiatement. Une fois toutes les méthodes définies sur ViewPropertyAnimator exécutées, L'animation démarrera automatiquement. Bien entendu, si nous ne souhaitons pas utiliser ce mécanisme par défaut, nous pouvons également appeler explicitement la méthode start() pour démarrer l'animation.
  • Toutes les interfaces de ViewPropertyAnimator sont conçues en utilisant une syntaxe concaténée, et la valeur de retour de chaque méthode est C'est
  • une instance d'elle-même, donc après avoir appelé une méthode, vous pouvez directement appeler une autre de ses méthodes successivement, de sorte que toutes Les fonctions sont toutes connectées en série et nous pouvons même réaliser des fonctions d'animation de toute complexité avec une seule ligne de code.

4. Téléchargez l'exemple de code pour cette section

AnimatorDemo3.zip

Trouvez un projet de collection d'animation sur Github, avec de nombreux effets d'animation. l'adresse ci-dessous :

Collection d'animations BaseAnimation

Si vous souhaitez étudier comment diverses animations sont implémentées, vous pouvez consulter le code source vous-même~


Résumé de ceci section

Eh bien, dans cette section, nous avons parlé de choses légèrement plus avancées : l'évaluateur, l'interpolateur et ViewPropertyAnimator, a-t-il élargi les connaissances de chacun ~ Cette section est également le dessin d'introduction de base d'Android Il s'agit de la dernière section du chapitre. Si vous maîtrisez le contenu de ce chapitre, découvrez les contrôles personnalisés. Ou si vous regardez les contrôles personnalisés écrits par d’autres, vous ne devriez plus vous demander par où commencer et rencontrer un tas de nouveaux visages !

Eh bien, merci à Guo Shen pour votre article. La plupart du contenu de la partie animation des attributs a été déplacé directement de Guo Shen 12.jpg Hehe~ C'est tout pour cette section, merci~

PS : Plus tard Le schéma de principe du simulateur a été modifié parce que le N5 était trop drôle...