Pendant l'utilisation de votre application, de nouvelles informations et d'anciennes informations apparaissent à l'écran les informations sont supprimées. Modifier ce qui s’affiche immédiatement à l’écran peut être gênants, et les utilisateurs peuvent passer à côté de nouveaux contenus qui apparaissent soudainement. Animations lentes les modifications et attirer l'attention de l'utilisateur à l'aide de mouvements pour que les mises à jour soient est plus évidente.
Il existe trois animations courantes que vous pouvez utiliser pour afficher ou masquer une vue : des animations, des animations en fondu enchaîné et des animations Cardflip.
Créer une animation de fondu enchaîné
Une animation de fondu enchaîné (ou Fondu enchaîné) s'estompe progressivement
un View
ou
ViewGroup
tout en
qui se fond dans une autre. Cette animation est utile lorsque vous souhaitez
changer de contenu ou de vue dans votre application. L'animation en fondu enchaîné présenté ici utilise
ViewPropertyAnimator
,
disponible pour Android 3.1 (niveau d'API 12) ou version ultérieure.
Voici un exemple de fondu enchaîné entre un indicateur de progression et un contenu textuel:
Créer les vues
Créez les deux vues que vous souhaitez effectuer en fondu enchaîné. L'exemple suivant crée un indicateur de progression et affichage de texte déroulant:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView style="?android:textAppearanceMedium"
android:lineSpacingMultiplier="1.2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/lorem_ipsum"
android:padding="16dp" />
</ScrollView>
<ProgressBar android:id="@+id/loading_spinner"
style="?android:progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
</FrameLayout>
Configurer l'animation de fondu enchaîné
Pour configurer l'animation en fondu enchaîné, procédez comme suit:
- Créez des variables de membre pour les vues que vous souhaitez effectuer en fondu enchaîné. Vous devez ces références lors de la modification des vues au cours de l'animation.
- Définir la visibilité de la vue en cours de fondu
GONE
Cela empêche la vue d'utiliser l'espace de mise en page et l'omet des calculs de mise en page, ce qui accélère traitement - Mettre en cache
config_shortAnimTime
système dans une variable de membre. Cette propriété définit un type "short" standard la durée de l'animation. Cette durée est idéale pour les animations ou des animations qui se produisent fréquemment.config_longAnimTime
etconfig_mediumAnimTime
sont également à disposition.
Voici un exemple utilisant la mise en page de l'extrait de code précédent en tant que Affichage du contenu de l'activité:
Kotlin
class CrossfadeActivity : Activity() { private lateinit var contentView: View private lateinit var loadingView: View private var shortAnimationDuration: Int = 0 ... override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_crossfade) contentView = findViewById(R.id.content) loadingView = findViewById(R.id.loading_spinner) // Initially hide the content view. contentView.visibility = View.GONE // Retrieve and cache the system's default "short" animation time. shortAnimationDuration = resources.getInteger(android.R.integer.config_shortAnimTime) } ... }
Java
public class CrossfadeActivity extends Activity { private View contentView; private View loadingView; private int shortAnimationDuration; ... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_crossfade); contentView = findViewById(R.id.content); loadingView = findViewById(R.id.loading_spinner); // Initially hide the content view. contentView.setVisibility(View.GONE); // Retrieve and cache the system's default "short" animation time. shortAnimationDuration = getResources().getInteger( android.R.integer.config_shortAnimTime); } ... }
Faites un fondu enchaîné sur les vues
Lorsque les vues sont correctement configurées, effectuez un fondu enchaîné en procédant comme suit:
- Pour la vue qui apparaît en fondu, définissez la valeur alpha sur 0 et la visibilité
à
VISIBLE
à partir de son surGONE
. La vue est alors visible, mais transparente. - Animez la valeur alpha de la vue qui apparaît en fondu de 0 à 1. Pour le qui disparaît, animez la valeur alpha de 1 à 0.
- En utilisant
onAnimationEnd()
dans unAnimator.AnimatorListener
, définissez la visibilité de la vue qui passe en fondu surGONE
. Même si la valeur alpha est 0, le fait de définir la visibilité de la vue surGONE
empêche la vue d'utiliser l'espace de mise en page et l'omet des calculs de mise en page, ce qui accélère en cours de traitement.
La méthode suivante montre comment procéder:
Kotlin
class CrossfadeActivity : Activity() { private lateinit var contentView: View private lateinit var loadingView: View private var shortAnimationDuration: Int = 0 ... private fun crossfade() { contentView.apply { // Set the content view to 0% opacity but visible, so that it is // visible but fully transparent during the animation. alpha = 0f visibility = View.VISIBLE // Animate the content view to 100% opacity and clear any animation // listener set on the view. animate() .alpha(1f) .setDuration(shortAnimationDuration.toLong()) .setListener(null) } // Animate the loading view to 0% opacity. After the animation ends, // set its visibility to GONE as an optimization step so it doesn't // participate in layout passes. loadingView.animate() .alpha(0f) .setDuration(shortAnimationDuration.toLong()) .setListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator) { loadingView.visibility = View.GONE } }) } }
Java
public class CrossfadeActivity extends Activity { private View contentView; private View loadingView; private int shortAnimationDuration; ... private void crossfade() { // Set the content view to 0% opacity but visible, so that it is // visible but fully transparent during the animation. contentView.setAlpha(0f); contentView.setVisibility(View.VISIBLE); // Animate the content view to 100% opacity and clear any animation // listener set on the view. contentView.animate() .alpha(1f) .setDuration(shortAnimationDuration) .setListener(null); // Animate the loading view to 0% opacity. After the animation ends, // set its visibility to GONE as an optimization step so it doesn't // participate in layout passes. loadingView.animate() .alpha(0f) .setDuration(shortAnimationDuration) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { loadingView.setVisibility(View.GONE); } }); } }
Créer une animation de retournement de carte
La fiche passe d'une vue de contenu à l'autre en affichant une animation qui émule
une carte qui se retourne. L'animation de retournement de carte
illustrée ici utilise
FragmentTransaction
Voici à quoi ressemble un tirage de cartes:
Créer les objets Animator
Pour créer l'animation de retournement de carte, vous avez besoin de quatre animateurs. Deux animateurs pour indiquer quand le recto de la carte s'anime vers l'extérieur et vers la gauche, et quand elle s'anime à l'intérieur et à la gauche. Les deux autres sont destinés aux animations au verso de la carte. s'anime de droite à gauche et de droite à gauche.
carte_flip_left_in.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Before rotating, immediately set the alpha to 0. -->
<objectAnimator
android:valueFrom="1.0"
android:valueTo="0.0"
android:propertyName="alpha"
android:duration="0" />
<!-- Rotate. -->
<objectAnimator
android:valueFrom="-180"
android:valueTo="0"
android:propertyName="rotationY"
android:interpolator="@android:interpolator/accelerate_decelerate"
android:duration="@integer/card_flip_time_full" />
<!-- Halfway through the rotation, set the alpha to 1. See startOffset. -->
<objectAnimator
android:valueFrom="0.0"
android:valueTo="1.0"
android:propertyName="alpha"
android:startOffset="@integer/card_flip_time_half"
android:duration="1" />
</set>
card_flip_left_out.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Rotate. -->
<objectAnimator
android:valueFrom="0"
android:valueTo="180"
android:propertyName="rotationY"
android:interpolator="@android:interpolator/accelerate_decelerate"
android:duration="@integer/card_flip_time_full" />
<!-- Halfway through the rotation, set the alpha to 0. See startOffset. -->
<objectAnimator
android:valueFrom="1.0"
android:valueTo="0.0"
android:propertyName="alpha"
android:startOffset="@integer/card_flip_time_half"
android:duration="1" />
</set>
carte_flip_droite_in.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Before rotating, immediately set the alpha to 0. -->
<objectAnimator
android:valueFrom="1.0"
android:valueTo="0.0"
android:propertyName="alpha"
android:duration="0" />
<!-- Rotate. -->
<objectAnimator
android:valueFrom="180"
android:valueTo="0"
android:propertyName="rotationY"
android:interpolator="@android:interpolator/accelerate_decelerate"
android:duration="@integer/card_flip_time_full" />
<!-- Halfway through the rotation, set the alpha to 1. See startOffset. -->
<objectAnimator
android:valueFrom="0.0"
android:valueTo="1.0"
android:propertyName="alpha"
android:startOffset="@integer/card_flip_time_half"
android:duration="1" />
</set>
carte_flip_right_out.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Rotate. -->
<objectAnimator
android:valueFrom="0"
android:valueTo="-180"
android:propertyName="rotationY"
android:interpolator="@android:interpolator/accelerate_decelerate"
android:duration="@integer/card_flip_time_full" />
<!-- Halfway through the rotation, set the alpha to 0. See startOffset. -->
<objectAnimator
android:valueFrom="1.0"
android:valueTo="0.0"
android:propertyName="alpha"
android:startOffset="@integer/card_flip_time_half"
android:duration="1" />
</set>
Créer les vues
Chaque côté de la carte est une mise en page distincte qui peut contenir tout contenu que vous comme deux affichages de texte, deux images ou n'importe quelle combinaison de vues à retourner entre les deux. Utilisez les deux mises en page dans les fragments que vous animerez par la suite. La La mise en page suivante crée un côté d'une carte, qui affiche du texte:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#a6c"
android:padding="16dp"
android:gravity="bottom">
<TextView android:id="@android:id/text1"
style="?android:textAppearanceLarge"
android:textStyle="bold"
android:textColor="#fff"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/card_back_title" />
<TextView style="?android:textAppearanceSmall"
android:textAllCaps="true"
android:textColor="#80ffffff"
android:textStyle="bold"
android:lineSpacingMultiplier="1.2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/card_back_description" />
</LinearLayout>
La mise en page suivante crée l'autre côté de la carte, qui affiche une
ImageView
:
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/image1"
android:scaleType="centerCrop"
android:contentDescription="@string/description_image_1" />
Créer les fragments
Créez des classes de fragment pour le recto et le verso de la carte. Dans votre fragment
renvoient les mises en page que vous avez créées à partir du
onCreateView()
. Vous pouvez ensuite créer des instances de ce fragment dans l'activité parente.
où vous souhaitez afficher la fiche.
L'exemple suivant montre des classes de fragment imbriquées dans l'activité parente qui les utilise:
Kotlin
class CardFlipActivity : FragmentActivity() { ... /** * A fragment representing the front of the card. */ class CardFrontFragment : Fragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View = inflater.inflate(R.layout.fragment_card_front, container, false) } /** * A fragment representing the back of the card. */ class CardBackFragment : Fragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View = inflater.inflate(R.layout.fragment_card_back, container, false) } }
Java
public class CardFlipActivity extends FragmentActivity { ... /** * A fragment representing the front of the card. */ public class CardFrontFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_card_front, container, false); } } /** * A fragment representing the back of the card. */ public class CardBackFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_card_back, container, false); } } }
Animer le retournement des cartes
Affichez les fragments dans une activité parente. Pour ce faire, créez la mise en page
pour votre activité. L'exemple suivant crée un
FrameLayout
que vous pouvez ajouter
fragments au moment de l'exécution:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Dans le code de l'activité, définissez la vue de contenu sur la mise en page que vous créez. Il est recommandé d'afficher un fragment par défaut lorsque l'activité est créée. La L'exemple d'activité suivant montre comment afficher le recto de la carte en default:
Kotlin
class CardFlipActivity : FragmentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_activity_card_flip) if (savedInstanceState == null) { supportFragmentManager.beginTransaction() .add(R.id.container, CardFrontFragment()) .commit() } } ... }
Java
public class CardFlipActivity extends FragmentActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_activity_card_flip); if (savedInstanceState == null) { getSupportFragmentManager() .beginTransaction() .add(R.id.container, new CardFrontFragment()) .commit(); } } ... }
Le recto de la carte étant visible, vous pouvez montrer le verso avec l'icône l'animation de retournement au bon moment. Créez une méthode pour montrer l'autre côté de la carte qui:
- Définit les animations personnalisées que vous avez créées pour les transitions de fragment.
- Remplace le fragment affiché par un nouveau fragment et anime cet événement. avec les animations personnalisées que vous avez créées.
- Ajoute le fragment précédemment affiché à la pile "Retour" du fragment. Ainsi, lorsque l'utilisateur appuie sur le bouton Retour, la carte se retourne.
Kotlin
class CardFlipActivity : FragmentActivity() { ... private fun flipCard() { if (showingBack) { supportFragmentManager.popBackStack() return } // Flip to the back. showingBack = true // Create and commit a new fragment transaction that adds the fragment // for the back of the card, uses custom animations, and is part of the // fragment manager's back stack. supportFragmentManager.beginTransaction() // Replace the default fragment animations with animator // resources representing rotations when switching to the back // of the card, as well as animator resources representing // rotations when flipping back to the front, such as when the // system Back button is tapped. .setCustomAnimations( R.animator.card_flip_right_in, R.animator.card_flip_right_out, R.animator.card_flip_left_in, R.animator.card_flip_left_out ) // Replace any fragments in the container view with a fragment // representing the next page, indicated by the just-incremented // currentPage variable. .replace(R.id.container, CardBackFragment()) // Add this transaction to the back stack, letting users press // the Back button to get to the front of the card. .addToBackStack(null) // Commit the transaction. .commit() } }
Java
public class CardFlipActivity extends FragmentActivity { ... private void flipCard() { if (showingBack) { getSupportFragmentManager().popBackStack(); return; } // Flip to the back. showingBack = true; // Create and commit a new fragment transaction that adds the fragment // for the back of the card, uses custom animations, and is part of the // fragment manager's back stack. getSupportFragmentManager() .beginTransaction() // Replace the default fragment animations with animator // resources representing rotations when switching to the back // of the card, as well as animator resources representing // rotations when flipping back to the front, such as when the // system Back button is pressed. .setCustomAnimations( R.animator.card_flip_right_in, R.animator.card_flip_right_out, R.animator.card_flip_left_in, R.animator.card_flip_left_out) // Replace any fragments in the container view with a fragment // representing the next page, indicated by the just-incremented // currentPage variable. .replace(R.id.container, new CardBackFragment()) // Add this transaction to the back stack, letting users press // Back to get to the front of the card. .addToBackStack(null) // Commit the transaction. .commit(); } }
Créer une animation d'affichage circulaire
Les animations d'affichage offrent aux utilisateurs une continuité visuelle lorsque vous affichez ou masquez un groupe
d'éléments d'UI. La
ViewAnimationUtils.createCircularReveal()
vous permet d'animer un cercle de rognage pour afficher ou masquer une vue. Ce
l'animation est fournie dans
la classe ViewAnimationUtils
,
disponible pour Android 5.0 (niveau d'API 21) ou version ultérieure.
Voici un exemple montrant comment afficher une vue auparavant invisible:
Kotlin
// A previously invisible view. val myView: View = findViewById(R.id.my_view) // Check whether the runtime version is at least Android 5.0. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { // Get the center for the clipping circle. val cx = myView.width / 2 val cy = myView.height / 2 // Get the final radius for the clipping circle. val finalRadius = Math.hypot(cx.toDouble(), cy.toDouble()).toFloat() // Create the animator for this view. The start radius is 0. val anim = ViewAnimationUtils.createCircularReveal(myView, cx, cy, 0f, finalRadius) // Make the view visible and start the animation. myView.visibility = View.VISIBLE anim.start() } else { // Set the view to invisible without a circular reveal animation below // Android 5.0. myView.visibility = View.INVISIBLE }
Java
// A previously invisible view. View myView = findViewById(R.id.my_view); // Check whether the runtime version is at least Android 5.0. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { // Get the center for the clipping circle. int cx = myView.getWidth() / 2; int cy = myView.getHeight() / 2; // Get the final radius for the clipping circle. float finalRadius = (float) Math.hypot(cx, cy); // Create the animator for this view. The start radius is 0. Animator anim = ViewAnimationUtils.createCircularReveal(myView, cx, cy, 0f, finalRadius); // Make the view visible and start the animation. myView.setVisibility(View.VISIBLE); anim.start(); } else { // Set the view to invisible without a circular reveal animation below // Android 5.0. myView.setVisibility(View.INVISIBLE); }
L'animation ViewAnimationUtils.createCircularReveal()
utilise cinq paramètres.
Le premier paramètre correspond à la vue que vous souhaitez masquer ou afficher à l'écran. La
les deux paramètres suivants sont les coordonnées X et Y du centre du rognage
cercle. Il s'agit généralement du centre de la vue, mais vous pouvez également utiliser la
point sur lequel l'utilisateur appuie pour que l'animation commence là où il la sélectionne. La
le quatrième paramètre est le rayon de départ du cercle de découpe.
Dans l'exemple précédent, le rayon initial est défini sur zéro afin que la vue affiché est masqué par le cercle. Le dernier paramètre est le rayon final du cercle. Lors de l'affichage d'une vue, le rayon final doit être supérieur à la valeur afin que la vue s'affiche entièrement avant la fin de l'animation.
Pour masquer une vue précédemment visible, procédez comme suit:
Kotlin
// A previously visible view. val myView: View = findViewById(R.id.my_view) // Check whether the runtime version is at least Android 5.0. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { // Get the center for the clipping circle. val cx = myView.width / 2 val cy = myView.height / 2 // Get the initial radius for the clipping circle. val initialRadius = Math.hypot(cx.toDouble(), cy.toDouble()).toFloat() // Create the animation. The final radius is 0. val anim = ViewAnimationUtils.createCircularReveal(myView, cx, cy, initialRadius, 0f) // Make the view invisible when the animation is done. anim.addListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator) { super.onAnimationEnd(animation) myView.visibility = View.INVISIBLE } }) // Start the animation. anim.start() } else { // Set the view to visible without a circular reveal animation below // Android 5.0. myView.visibility = View.VISIBLE }
Java
// A previously visible view. final View myView = findViewById(R.id.my_view); // Check whether the runtime version is at least Android 5.0. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { // Get the center for the clipping circle. int cx = myView.getWidth() / 2; int cy = myView.getHeight() / 2; // Get the initial radius for the clipping circle. float initialRadius = (float) Math.hypot(cx, cy); // Create the animation. The final radius is 0. Animator anim = ViewAnimationUtils.createCircularReveal(myView, cx, cy, initialRadius, 0f); // Make the view invisible when the animation is done. anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); myView.setVisibility(View.INVISIBLE); } }); // Start the animation. anim.start(); } else { // Set the view to visible without a circular reveal animation below Android // 5.0. myView.setVisibility(View.VISIBLE); }
Dans ce cas, le rayon initial du cercle de découpe est égal au
afin qu'elle soit visible avant le début de l'animation. Le dernier
le rayon est défini sur zéro afin que la vue soit masquée une fois l'animation terminée.
Ajoutez un écouteur à l'animation afin que la visibilité de la vue puisse être définie sur
INVISIBLE
lorsque l'animation
terminé.