L'explication d'animation la plus complète pour Android

Les animations Android sont divisées en trois types : l'animation de vue, l'animation d'image et l'animation d'attribut.

Voir l'animation

Qu'est-ce que l'animation de vue ? L'objet de l'animation ne peut être qu'une animation de vue, appelée animation de vue. Il existe quatre types d'animation de vue : TranslateAnimation (traduction), ScaleAnimation (zoom), RotateAnimation (rotation) et AlphaAnimation (transparence). Il existe également un AnimationSet (animation combinée), et ils héritent tous de la classe Animation . N'oubliez pas que l'animation de la vue est réalisée via les paramètres liés à Convas, plutôt que de modifier les propriétés de la vue, donc un problème surviendra : la vue est traduite, mais l'événement de clic ne change pas.

N'oubliez pas que les coordonnées d'origine de toutes les animations sont relatives au sommet supérieur gauche de la vue.

Il existe deux manières d'implémenter l'animation de vue : le code dynamique et l'implémentation de fichiers XML. Il est recommandé d'utiliser XML, qui est fortement réutilisable.

 Lorsqu'il est utilisé en XML, un fichier XML doit être créé. Le chemin du fichier est : res/anim/filename.xml

TraduireAnimationAnimation

Code:

Si fromXType n’est pas spécifié, la valeur par défaut est ABSOLUTE.

 Il existe trois méthodes de construction comme ci-dessus.

formXType : Spécifie comment fromXValue doit être interprété. Il existe trois modes :

ABSOLU //Valeur absolue, l'unité est le px
RELATIVE_TO_SELF //Par rapport à lui-même, c'est-à-dire la largeur de fromXValue* lui-même
RELATIVE_TO_PARENT //Par rapport à la classe parent, c'est-à-dire fromXvalue*width de la classe parent

Propriétés couramment utilisées :

durée : durée de l'animation, la valeur par défaut est 0, ce qui signifie immédiatement
fillAfter : une fois l'animation exécutée, s'il faut conserver la position finale
fillBefore : une fois l'animation terminée, s'il faut conserver la position de départ
repeatCount : l'animation se répète, la valeur par défaut est 1 fois, -1 représente une boucle invalide
RepeatMode : Mode de répétition de l'animation Animation.REVERSE (répéter dans le sens inverse après la fin de l'animation) Animation.RESTART (recommencer à chaque fois)
interpolateur : interpolateur d'animation, changements dans le temps, changement en pourcentage des propriétés de l'animation
réinitialiser : réinitialiser l'animation
setStartOffset : combien de temps l'animation est retardée par rapport à l'heure de début, offset-offset
setStartTime : définit l'heure spécifique d'exécution de l'animation, l'unité est l'heure de début en millisecondes.
Cancel() : Arrête l'animation et arrête l'animation de la vue en même temps. Vous pouvez également l'utiliser.clearAnimation(). La différence est que Cancel arrête l'animation spécifiée et clearAnimation() arrête l'animation qui affecte la vue actuelle. Ils rappellera la méthode onAnimationEnd.
Implémentation XML :

Créez d'abord le dossier anim en résolution, 

Sélectionnez l'option d'animation vers le haut, le nom ne peut être qu'une animation fixe 

Après la création, faites un clic droit et créez une animation XML

Créer slide_1.xml  

第一种写法:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    >
<translate
    android:duration="500"
    android:fillAfter="true"
    android:fromXDelta="0"
    android:toXDelta="200"
    ></translate>
</set>

<set>是animationSet的xml写法,如果这样写的话,会发现一个问题,就是在<tramslate  标签里面,基本不会提示duration等,这个时候把xmlns:android="http://schemas.android.com/apk/res/android"引用写到<translate>标签中就可以了。

第二种写法:
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500"
    android:fillAfter="true"
    android:fromXDelta="0"
    android:toXDelta="200"
    >
</translate>

Il n'y a pas d'attributs formXType ou formYType dans XML , alors comment les exprimer ?

android:toYDelta="50" sans modificateur, représente ABSOLU, l'unité est px

android:toYDelta="50%" // %代表RELATIVE_TO_SELF

android:toYDelta="50%p" // %p代表 RELATIVE_TO_PARENT

utiliser:

      val loadAnimation = AnimationUtils.loadAnimation(this, R.anim.slide_1)
                it.startAnimation(loadAnimation)

Configurer la surveillance :

     loadAnimation.setAnimationListener(object :AnimationListener{
                override fun onAnimationStart(animation: Animation?) {
                }

                override fun onAnimationEnd(animation: Animation?) {
                }

                override fun onAnimationRepeat(animation: Animation?) {
                }

            })

ÉchelleAnimationAnimation

  Code:

 Explication des paramètres :

fromX : commencez la mise à l'échelle à partir de 0,5 fois la longueur de son propre axe X. (Une attention particulière ne fait pas référence à la valeur px de la mise à l'échelle.) Par exemple : fromX= 0,5 signifie à partir de 0,5 fois la longueur de son propre axe X.

tox : La mise à l'échelle se termine à combien de fois la longueur de son propre axe X. Par exemple : toX = 2,0 signifie que la mise à l'échelle de l'axe X se termine à 2 fois la longueur de son propre axe X.

formY : commencez la mise à l'échelle à partir de 0,5 fois la longueur de son propre axe Y. Par exemple : fromY=0,5 signifie commencer à partir de 0,5 fois la longueur de son propre axe Y.

toY : combien de fois la longueur de l'axe Y sera mise à l'échelle, par exemple : toY=2,0, ce qui signifie que l'axe Y sera mis à l'échelle à deux fois la longueur de l'axe Y.

pivot (point central)

pivotX : démarrer la mise à l'échelle par rapport à la position de l'axe de contrôle X

pivotY : commencer la mise à l'échelle par rapport à la position de l'axe de contrôle y

pivotXType : expliquez la signification de la valeur pivotx, la valeur par défaut est ABSOLUE

pivotYType : expliquez la signification de la valeur pivot, la valeur par défaut est ABSOLUTE

Il convient de noter que lors du zoom, pivotx et pivoty sont utilisés comme points centraux pour zoomer des deux côtés en même temps.

Implémentation XML :
<?xml version="1.0" encoding="utf-8"?>
<set
    xmlns:android="http://schemas.android.com/apk/res/android"
    >
<scale
    android:duration="500"
    android:fillAfter="true"
    android:fromXScale="1"
    android:toXScale="0.5"
    android:fromYScale="1"
    android:toYScale="0.5"
    android:pivotY="50%"
    android:pivotX="50%"
    ></scale>
</set>
切记,不要在xml中添加float的修饰符 f,不然编译不过
如:
<scale
    android:duration="500"
    android:fillAfter="true"
    android:fromXScale="1"
    android:toXScale="0.5f"   //这样编译不过
    android:fromYScale="1"
    android:toYScale="0.5"
    android:pivotY="50%"
    android:pivotX="50%"
    ></scale>

RotateAnimationanimation de rotation

Code:

 formDegrees : sous quel angle commencer la rotation

toDegrees : à combien de degrés la rotation se terminera-t-elle ?

pivotX : à la position centrale de rotation de l'axe X

pivoty : position du centre de rotation sur l'axe y

pivotXtype : expliquez la signification de pivotx, la valeur par défaut est ABSOLU

Animation de transparence AlphaAnimation

    /**
     * Constructor to use when building an AlphaAnimation from code
     * 
     * @param fromAlpha Starting alpha value for the animation, where 1.0 means
     *        fully opaque and 0.0 means fully transparent.
     * @param toAlpha Ending alpha value for the animation.
     */
    源码的注解已经说明,透明度的值是0.0-1.0
    public AlphaAnimation(float fromAlpha, float toAlpha) {
        mFromAlpha = fromAlpha;
        mToAlpha = toAlpha;
    }
Code:
     val alphaAnimation = AlphaAnimation(1f, 0f).
               apply {
                   duration =500
               }
              it.startAnimation(alphaAnimation)
implémentation XML

anim->nouveau->fichier de ressources animaltion ->

 À ce stade, j'ai découvert qu'une grande partie du code ne pouvait pas être écrite, comme la durée. À ce stade, vous pouvez envelopper une balise set dans la couche externe, copier la valeur, puis supprimer la balise <set>.

<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    Android : fromAlpha="1"
   Android : durée =" 500 »
    Android :toAlpha="0,5"
    />

Animation combinée AnimationSet

Combinez plusieurs animations

Code

Exécuté via la méthode addAnimation d'AnimationSet.

val apply = AnimationSet(true).apply {
    addAnimation(RotateAnimation(
        0f, -90f, Animation.RELATIVE_TO_SELF, 0.5f,
        Animation.RELATIVE_TO_SELF, 0.5f
    ).apply {
        duration = 300
    })
    addAnimation(AlphaAnimation(1.0f, 0.3f).apply {
        duration = 300
        startOffset = 300
    })
}
it.startAnimation(apply)
Exécuter en XML
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="300"
    android:interpolator="@android:anim/linear_interpolator" //动画集合的插值器
    android:shareInterpolator="true"  
   //表示动画集合是否共享一个插值器,如果不指定插值器,那么子动画就需要自己指定插值器,或者使用默认的
    android:fillAfter="true"
    >
<rotate
    android:fromDegrees="0"
    android:toDegrees="90"
    ></rotate>

    <alpha
        android:fromAlpha="1"
        android:duration="800"  //子类的设置的时间会替换动画集合的时间
        android:toAlpha="0.0"
        ></alpha>

</set>

Comment implémenter un total de trois animations dans une vue. Lorsqu'une animation se termine, une autre animation est exécutée ?

L'animation de propriété a un attribut de classement, mais l'animation de vue est exécutée ensemble et n'a aucun attribut de classement.

Ensuite, nous pouvons passer

Attribut startOffset à exécuter.
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    >
    <translate
        android:fromXDelta="0"
        android:toXDelta="200"
        android:duration="500"
        ></translate>
    <rotate
        android:startOffset="500"
        android:fromDegrees="0"
        android:toDegrees="180"
        android:pivotX="100%"
        android:pivotY="50%"
        android:duration="500"
        ></rotate>

    <alpha
        android:startOffset="1000"
        android:fromAlpha="1"
        android:toAlpha="0.2"
        android:duration="500"
        ></alpha>


</set>

mise en pageAnimation

layoutAnimation agit sur tous les ViewGroups. Lorsque cette animation est spécifiée pour ce ViewGroup, tous les autres sous-éléments auront cet effet d'animation lorsqu'ils apparaîtront. layoutAnimation ne fait pas référence à une animation distincte, mais à un moyen. Il peut également être visualisé sous forme d’animation de vue.

méthode d'écriture XML

Créez un fichier de type layoutAnimation dans le dossier anim.

lyanimation.xml

<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
    android:animation="@anim/slide_1"   
    android:animationOrder="normal"
    android:delay="0.5"
    >
</layoutAnimation>

animation //引用的view动画
animationOrder //子元素执行动画的顺序,有三种选项:normal、reverse和random,其中normal表示顺
序显示,即排在前面的子元素先开始播放入场动画;reverse表示逆向显示,即排在后面的
子元素先开始播放入场动画;random则是随机播放入场动画。
delay //表示子元素开始动画的时间延迟,比如子元素入场动画的时间周期为300ms,那么0.5
表示每个子元素都需要延迟150ms才能播放入场动画。总体来说,第一个子元素延迟
150ms开始播放入场动画,第2个子元素延迟300ms开始播放入场动画,依次类推。

 slide_1.xml

<?xml version="1.0" encoding="utf-8"?>
<set
    android:duration="300"
    xmlns:android="http://schemas.android.com/apk/res/android"
    >
<translate
    android:fromXDelta="-100%"
    android:toXDelta="0"
    ></translate>
</set>

Référencé par android:layoutAnimation="@anim/lyanimation" dans ViewGroup.

 <LinearLayout
        android:gravity="center_horizontal"
        android:layout_width="match_parent"
        android:orientation="vertical"
        android:id="@+id/tv_click_12"
        android:layout_marginBottom="@dimen/dp_300"
        android:layoutAnimation="@anim/lyanimation" //引用
        android:layout_height="wrap_content">

        <TextView
            android:background="@drawable/img"
            android:layout_width="400px"
            android:text="组合动画"
            android:gravity="center"
            android:layout_marginTop="@dimen/dp_30"
            android:layout_height="100px"></TextView>
        <TextView
            android:layout_marginTop="@dimen/dp_30"
            android:background="@drawable/img_1"
            android:layout_width="400px"
            android:text="组合动画"
            android:gravity="center"
            android:layout_height="100px"></TextView>
        <TextView
            android:layout_marginTop="@dimen/dp_30"
            android:background="@drawable/img_2"
            android:layout_width="400px"
            android:text="组合动画"
            android:gravity="center"
            android:layout_height="100px"></TextView>
        <TextView
            android:layout_marginTop="@dimen/dp_30"
            android:background="@drawable/img_3"
            android:layout_width="400px"
            android:text="组合动画"
            android:gravity="center"
            android:layout_height="100px"></TextView>
    </LinearLayout>
Définir dans le code

Notez qu'il s'agit de l'animation de sortie. Si le viewGroup est déjà visible, cela n'aura aucun effet si vous définissez cette animation via l'événement click.

        val tv_click_12 = findViewById<LinearLayout>(R.id.tv_click_12);//获得viewGroup
 
     
val loadAnimation = AnimationUtils.loadAnimation(this, R.anim.slide_1) //加载view动画
val LayoutAnimationController = LayoutAnimationController(loadAnimation).apply { //创建LayoutAnimationController
 delay = 0.5f
order = LayoutAnimationController.ORDER_NORMAL
            }
            tv_click_12.layoutAnimation = LayoutAnimationController  //设置
      

L'effet est comme le montre la figure :

Effet de changement d'activité 

Le saut d'activité a un effet d'animation par défaut, mais nous pouvons également personnaliser cette animation. Principalement à travers

public void overridePendingTransition (int enterAnim, int exitAnim) {
    ActivityClient.getInstance().overridePendingTransition(mToken, getPackageName(),
            enterAnim, exitAnim);
}

Par ici. Cette méthode doit être appelée après startActivity(intent) ou finish() pour prendre effet.

enterAnim - l' identifiant de la ressource d'animation requis lorsque l'activité est ouverte ;
exitAnim - l' identifiant de la ressource d'animation requis lorsque l'activité est suspendue .
La commutation de fragments peut également être animée. Étant donné que Fragment est une classe nouvellement introduite dans l'API 11, pour des raisons de compatibilité
Pour la capacité, nous devons utiliser le package de compatibilité support-v4 . Dans ce cas, nous pouvons utiliser FragmentTransaction
Méthode setCustomAnimations () pour ajouter des animations de commutation. Cette animation de changement doit être une animation de vue . La raison pour laquelle
L'animation de propriété ne peut pas être utilisée car l'animation de propriété est également nouvellement introduite dans l'API 11 . Existe-t-il d'autres moyens de donner Activity et
Fragment ajoute des animations de commutation, mais la plupart d'entre elles ont des problèmes de compatibilité et ne peuvent pas être utilisées sur les versions inférieures, elles n'ont donc pas
Il a une grande valeur d’usage, je ne les présenterai donc pas un par un ici.

animation d'image

L'animation d'images lit un ensemble d'images prédéfinies en séquence, similaire à la lecture d'un film. Différent de l'animation de vue, le système fournit une classe AnimationDrawable pour utiliser l'animation de trame. AnimationDrawable appartient à Drawable, donc faites un clic droit directement dans le dossier dessinable -> nouveau -> fichier de ressources dessinable ->

Créer un fichier XML

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="true"  oneshot = tru表示执行一遍,false是一直重复执行
    >
<item android:duration="200" android:drawable="@drawable/img"></item>
    <item android:duration="200" android:drawable="@drawable/img_1"></item>
    <item android:duration="200" android:drawable="@drawable/img_2"></item>
    <item android:duration="200" android:drawable="@drawable/img_3"></item>
</animation-list>

 Définir la vue pour définir la couleur de Pékin

Utilisé dans le code :

      val mAnimationDrawable = findViewById<View>(R.id.tv_click_11).background as AnimationDrawable
            mAnimationDrawable.start()

C'est ça.

Animation immobilière

L'animation de propriété étend l'animation de vue et fonctionne sur n'importe quel objet, même aucun objet. L'animation des propriétés ne se limite pas aux quatre simples changements de translation, de mise à l'échelle, de rotation et de transparence.

Les animations de propriétés incluent ValueAnimator, ObjectAnimator et AnimtorSet. Avec ces trois éléments, des animations complexes peuvent être réalisées.

Avant de comprendre l'animation d'attributs, vous devez comprendre deux classes :

interpolateur interpolateur, cette animation de vue l'a également. Évaluateur TypeEvaluator

La fonction de l'interpolateur est de calculer la variation en pourcentage de la valeur actuelle de l'attribut au fil du temps.

Android dispose de plusieurs interpolateurs intégrés

LinearInterpolator (interpolateur linéaire : animation uniforme)

AccelerateDecelerateInterpolator (interpolateur d'accélération et de décélération : l'animation est lente aux deux extrémités et rapide au milieu)

DecelerateInterpolator (interpolateur de décélération : l'animation devient de plus en plus lente)

La fonction de TypeEvaluator est de calculer la valeur d'attribut modifiée en fonction du pourcentage de modification d'attribut actuelle. Le système a intégré

IntEvaluator (pour les propriétés entières)

FloatEvaluator (pour les propriétés à virgule flottante)
ArgbEvaluator (pour les attributs du type de couleur)
Si nos cibles d'animation immobilière (non-int,
float , Color ), vous devez personnaliser l'estimateur de type .
Comment personnaliser l'estimateur :
public class IntEvaluator implements TypeEvaluator<Integer> {
public Integer evaluate(float fraction,Integer startValue,Integer
endValue) {
int startInt = startValue;
return (int)(startInt + fraction * (endValue -startInt));
}
}

​​​​​​​

Animateur d'objets

objectAnimator est destiné aux objets. objectAnimator est une sous-classe de ValueAnimator. ObjectAnimator possède les méthodes importantes suivantes.

ObjectAnimator.ofInt()  
ObjectAnimator.ofFloat()
ObjectAnimator.ofArgb()
ObjectAnimator.ofObject()

//android fournit des estimateurs par défaut tels que int, float, argb, etc. Si vous utilisez ObjectAnimator.ofObject(), vous devez personnaliser l'estimateur. Vous pouvez vous référer à cet article Android Animation Learning (3) : Animation d'attributs personnalisés - Bref livre


public static ObjectAnimator ofInt (Object target, String propertyName, int... valeurs) {
    ObjectAnimator anim = new ObjectAnimator(target, propertyName);
    anim.setIntValues(valeurs);
    renvoyer l'animation ;
}

cible : l'objet de l'animation

propertyName : Le nom de la propriété à modifier. Lors de l'exécution de l'animation, la méthode set de cette propriété sera appelée en continu.

int... valeur : la valeur de l'attribut change, est un tableau, par exemple : transparence, de 0->1->0

Étant donné que le principe de l'animation d'attribut est de modifier dynamiquement la valeur de l'attribut à une certaine vitesse pour obtenir l'effet d'animation, deux conditions doivent être remplies pour configurer une animation d'attribut :

1 : Si vous définissez une animation d'attribut pour un attribut AB, elle doit être remplie. Cet attribut a une méthode setAB, et si la valeur de départ n'est pas définie, il doit avoir une méthode getAB. L'animation d'attribut obtiendra la valeur initiale grâce à cela méthode.

2. Les modifications des valeurs d'attribut lors de l'exécution d'une animation d'attribut doivent être reflétées dans l'interface utilisateur, sinon cela n'aura aucun effet.

Par exemple : Comment utiliser les attributs pour obtenir les effets suivants.

Code d'analyse : L'image de gauche est une mise en page développée et réduite. Nous pouvons faire apparaître l'image de gauche en cliquant sur la mise en page rouge.

marginLeft change pour obtenir cet effet.

D'après les deux conditions que doit remplir l'attribut animation, nous savons que l'ImageView de gauche n'a pas l' attribut marginLeft. Alors comment résoudre le problème de l’exécution d’animations sur des attributs qui ne remplissent pas les deux conditions ci-dessus ? La solution officielle est la suivante :

  1. Fournissez une classe wrapper pour que l'objet encapsule l'objet d'origine. S'il n'existe pas d'attribut de ce type, fournissez cet attribut indirectement et fournissez les méthodes get et set.
  2. Utilisez ValueAnimator pour surveiller le processus d'animation et modifier vous-même les propriétés.

 Code dynamique :

XML :

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    android:id="@+id/ln_content"
    tools:context=".AnimationActivity2">
    <TextView
        android:id="@+id/slide_s"
        android:layout_width="400px"
        android:text="点击显示全"
        android:background="@drawable/img_2"
        android:layout_height="match_parent"></TextView>
    <TextView
        android:text="点击展开和关闭"
        android:layout_width="50dp"
        android:id="@+id/click_button"
        android:background="@color/color_f74e00"
        android:layout_height="match_parent"></TextView>
    <HorizontalScrollView
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="match_parent">
    <LinearLayout
        android:layout_width="match_parent"
        android:orientation="horizontal"
        android:layout_height="match_parent">
        <TextView
            android:layout_width="200dp"
            android:text="1"
            android:textSize="32sp"
            android:gravity="center"
            android:textColor="#ffffff"
            android:layout_margin="@dimen/dp_20"
            android:background="#00b5ad"
            android:layout_height="match_parent"/>
        <TextView
            android:layout_width="200dp"
            android:layout_margin="@dimen/dp_20"
            android:background="#00b5ad"
            android:text="2"
            android:textSize="32sp"
            android:gravity="center"
            android:textColor="#ffffff"
            android:layout_height="match_parent"/>
        <TextView
            android:layout_width="200dp"
            android:text="3"
            android:textSize="32sp"
            android:gravity="center"
            android:textColor="#ffffff"
            android:layout_margin="@dimen/dp_20"
            android:background="#00b5ad"
            android:layout_height="match_parent"/>
        <TextView
            android:layout_width="200dp"
            android:layout_margin="@dimen/dp_20"
            android:background="#00b5ad"
            android:text="4"
            android:textSize="32sp"
            android:gravity="center"
            android:textColor="#ffffff"
            android:layout_height="match_parent"/>
        <TextView
            android:layout_width="200dp"
            android:layout_margin="@dimen/dp_20"
            android:background="#00b5ad"
            android:text="5"
            android:textSize="32sp"
            android:gravity="center"
            android:textColor="#ffffff"
            android:layout_height="match_parent"/>
        <TextView
            android:layout_width="200dp"
            android:layout_margin="@dimen/dp_20"
            android:background="#00b5ad"
            android:text="6"
            android:textSize="32sp"
            android:gravity="center"
            android:textColor="#ffffff"
            android:layout_height="match_parent"/>
        <TextView
            android:layout_width="200dp"
            android:layout_margin="@dimen/dp_20"
            android:background="#00b5ad"
            android:text="7"
            android:textSize="32sp"
            android:gravity="center"
            android:textColor="#ffffff"
            android:layout_height="match_parent"/>
        <TextView
            android:layout_width="200dp"
            android:text="8"
            android:textSize="32sp"
            android:gravity="center"
            android:textColor="#ffffff"
            android:layout_margin="@dimen/dp_20"
            android:background="#00b5ad"
            android:layout_height="match_parent"/>
        <TextView
            android:layout_width="200dp"
            android:text="9"
            android:textSize="32sp"
            android:gravity="center"
            android:textColor="#ffffff"
            android:layout_margin="@dimen/dp_20"
            android:background="#00b5ad"
            android:layout_height="match_parent"/>
    </LinearLayout>


    </HorizontalScrollView>


</LinearLayout>
Code:
Implémenté à l'aide d'une classe wrapper :

Créer une classe wrapper : SlideWrapper

    class SlideWrapper(val mSlide: View) {
        private var marginLeft :Int  //提供这个属性
        get() {   //重新这个属性的get方法
            return (mSlide.layoutParams as LinearLayout.LayoutParams).leftMargin
        }
        set(value) {  //重写这个属性的set方法,满足属性值的改变会体验在ui效果上
          
            val apply = (mSlide.layoutParams as LinearLayout.LayoutParams).apply {
                leftMargin = value
            }
            mSlide.layoutParams = apply
        }

    }

var isExpand:Boolean = true  //定义一个字段记录展开和收起的状态
 val slideView  = SlideWrapper(slide_s)
findViewById<View>(R.id.click_button).setOnClickListener {
              it.isEnabled = false
              if (isExpand){
                  //这是属性动画
                  ObjectAnimator.ofInt(slideView,"marginLeft",-400).apply {
                      duration = 500
                    addListener(object :AnimatorListener{
                        override fun onAnimationStart(animation: Animator?) {
                        }

                        override fun onAnimationEnd(animation: Animator?) {
                            it.isEnabled = true
                            isExpand = false
                        }

                        override fun onAnimationCancel(animation: Animator?) {
                        }

                        override fun onAnimationRepeat(animation: Animator?) {
                        }

                    })
                      start()
                  }
              }  else{
              
                  ObjectAnimator.ofInt(slideView,"marginLeft",-400,0).apply {
                      duration =500
                      addListener(object:AnimatorListener{
                          override fun onAnimationStart(animation: Animator?) {
                          }

                          override fun onAnimationEnd(animation: Animator?) {
                              it.isEnabled = true
                              isExpand = true
                          }

                          override fun onAnimationCancel(animation: Animator?) {
                          }

                          override fun onAnimationRepeat(animation: Animator?) {
                          }

                      })
                      start()
                  }
              }
        }
Mise en place du processus de suivi d'animation à l'aide de ValueAnimator

ValueAnimator lui-même n'agit sur aucun objet, ce qui signifie que son utilisation directe n'a aucun effet. Il peut animer une valeur. Nous pouvons surveiller son processus d'animation et modifier les valeurs des propriétés de nos objets pendant le processus d'animation. Cela équivaut également à animer notre objet.

  slide_s = findViewById<ImageView>(R.id.slide_s)
        findViewById<View>(R.id.click_button).setOnClickListener {
            it.isEnabled = false //防止动画没有执行完,触发点击事件
            if (isOpen){
                //执行关闭动画,我们监听从0到 -400的int值的变化
                ValueAnimator.ofInt(0,-400).apply {
                    duration = 500 //动画执行时间
                    //监听动画的每一帧
                    addUpdateListener(object :AnimatorUpdateListener{
                        override fun onAnimationUpdate(animation: ValueAnimator) {
                            val animatedValue = animation.animatedValue as Int //获得动画当前的值
                            val apply = (slide_s.layoutParams as LinearLayout.LayoutParams).apply {
                                leftMargin = animatedValue
                            }
                          
                        }

                    })
                    //监听动画的执行过程
                    addListener(object :AnimatorListener{
                        override fun onAnimationStart(animation: Animator?) {
                        }

                        override fun onAnimationEnd(animation: Animator?) {
                            it.isEnabled =true
                        }

                        override fun onAnimationCancel(animation: Animator?) {
                        }

                        override fun onAnimationRepeat(animation: Animator?) {
                        }

                    })
                    start()
                }


            }else{
                //执行打开动画
    ValueAnimator.ofInt(-400,0).apply {
        duration =500
        addUpdateListener(object :AnimatorUpdateListener{
            override fun onAnimationUpdate(animation: ValueAnimator) {
                val animatedValue = animation.animatedValue as Int //获得动画当前值
                val apply = (slide_s.layoutParams as LinearLayout.LayoutParams).apply {
                    leftMargin = animatedValue
                }
             
            }

        })

        addListener(object :AnimatorListener{
            override fun onAnimationStart(animation: Animator?) {
            }

            override fun onAnimationEnd(animation: Animator?) {
                it.isEnabled =true
            }

            override fun onAnimationCancel(animation: Animator?) {
            }

            override fun onAnimationRepeat(animation: Animator?) {
            }

        })
        start()
    }
            }
        }

AnimatorUpdateListener est utilisé ici . Cet écouteur est spécial. Il surveillera l'ensemble du processus d'animation. L'animation est composée de plusieurs images. Chaque fois qu'une image est lue, onAnimationUpdate sera appelé une fois.

L'effet est le même.

En plus d'être implémentée via du code, l'animation d'attributs peut également être définie via XML. L'animation des propriétés doit être définie dans

res/animator/ , sa syntaxe est la suivante.
<set
android:ordering=["together" | "sequentially"]>
<objectAnimator
android:propertyName="string"
android:duration="int"
android:valueFrom="float | int | color"
android:valueTo="float | int | color"
android:startOffset="int"
android:repeatCount="int"
android:repeatMode=["repeat" | "reverse"]
android:valueType=["intType" | "floatType"]/>
<animator
android:duration="int"
android:valueFrom="float | int | color"
android:valueTo="float | int | color"
android:startOffset="int"
android:repeatCount="int"
android:repeatMode=["repeat" | "reverse"]
android:valueType=["intType" | "floatType"]/>

</set>
属性动画的各种参数都比较好理解,在XML中可以定义ValueAnimator、ObjectAnimator以及AnimatorSet,其中<set>标签对应AnimatorSet,<Animator>标签对应
ValueAnimator,而<objectAnimator>则对应ObjectAnimator。<set>标签的android:ordering
属性有两个可选值:“together”和“sequentially”,其中“together”表示动画集合中的子动画
同时播放,“sequentially”则表示动画集合中的子动画按照前后顺序依次播放,
android:ordering属性的默认值是“together”。
对于<objectAnimator>标签的各个属性的含义,下面简单说明一下,对于<Animator>
标签这里就不再介绍了,因为它只是比<objectAnimator>少了一个android:propertyName属
性而已,其他都是一样的。
android:propertyName——表示属性动画的作用对象的属性的名称;
android:duration——表示动画的时长;
android:valueFrom——表示属性的起始值;
android:valueTo——表示属性的结束值;
android:startOffset——表示动画的延迟时间,当动画开始后,需要延迟多少毫秒才会
真正播放此动画;
android:repeatCount——表示动画的重复次数;
android:repeatMode——表示动画的重复模式;
android:valueType——表示android:propertyName所指定的属性的类型,
有“intType”和“floatType”两个可选项,分别表示属性的类型为整型和浮点型。另外,
如果android:propertyName所指定的属性表示的是颜色,那么不需要指定
android:valueType,系统会自动对颜色类型的属性做处理。
对于一个动画来说,有两个属性这里要特殊说明一下,一个是android:repeatCount,
它表示动画循环的次数,默认值为0,其中-1表示无限循环;另一个是
android:repeatMode,它表示动画循环的模式,有两个选项:“repeat”和“reverse”,分别表
示连续重复和逆向重复。连续重复比较好理解,就是动画每次都重新开始播放,而逆向重
复是指第一次播放完以后,第二次会倒着播放动画,第三次再重头开始播放动画,第四次
再倒着播放动画,如此反复

 

Guess you like

Origin blog.csdn.net/xueyoubangbang/article/details/132109140