Mentre l'app è in uso, sullo schermo e sulle vecchie informazioni vengono visualizzate nuove informazioni vengono rimosse. Puoi cambiare ciò che appare immediatamente sullo schermo fastidiosi e gli utenti possono sfuggire nuovi contenuti che appaiono all'improvviso. Animazioni lente le modifiche e attirare l'attenzione dell'utente con il movimento in modo che gli aggiornamenti più evidente.
Esistono tre animazioni comuni che puoi utilizzare per mostrare o nascondere una visualizzazione: rivela animazioni, dissolvenza incrociata e animazioni per capovolgimenti di carte.
Creare un'animazione di dissolvenza incrociata
Un'animazione di dissolvenza incrociata, nota anche come dissolvenza, svanisce gradualmente verso l'esterno
uno View
oppure
ViewGroup
mentre contemporaneamente
con la dissolvenza in un'altra. Questa animazione è utile nelle situazioni in cui vuoi
alternare contenuti o visualizzazioni nell'app. L'animazione di dissolvenza incrociata mostrata qui utilizza
ViewPropertyAnimator
,
disponibile per Android 3.1 (livello API 12) e versioni successive.
Ecco un esempio di dissolvenza incrociata da un indicatore di avanzamento a contenuti di testo:
Creare le viste
Crea le due viste a cui vuoi applicare la dissolvenza incrociata. L'esempio seguente crea un indicatore di avanzamento e una visualizzazione del testo scorrevole:
<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>
Configurare l'animazione di dissolvenza incrociata
Per impostare l'animazione di dissolvenza incrociata:
- Crea variabili dei membri per le viste a cui vuoi applicare una dissolvenza incrociata. Ti servono su questi riferimenti in un secondo momento, durante la modifica delle visualizzazioni durante l'animazione.
- Imposta la visibilità della vista in dissolvenza su
GONE
Questo impedisce la visualizzazione dall'utilizzo dello spazio di layout e lo omette dai calcoli di layout, velocizzando elaborazione - Memorizza nella cache
config_shortAnimTime
in una variabile membro. Questa proprietà definisce uno "short" standard durata dell'animazione. Questa durata è ideale per piccole animazioni o che si ripetono di frequente.config_longAnimTime
econfig_mediumAnimTime
.
Di seguito è riportato un esempio in cui viene utilizzato il layout dello snippet di codice precedente come visualizzazione contenuto attività:
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); } ... }
Dissolvenza incrociata delle visualizzazioni
Quando le viste sono impostate correttamente, esegui la dissolvenza incrociata procedendo nel seguente modo:
- Per la vista in dissolvenza, imposta il valore alpha su 0 e la visibilità
a
VISIBLE
dalla sua origine diGONE
. Ciò rende la visualizzazione visibile, ma trasparente. - Per la vista in dissolvenza, anima il valore alpha da 0 a 1. Per vista in dissolvenza, anima il valore alfa da 1 a 0.
- Utilizzo
onAnimationEnd()
in unAnimator.AnimatorListener
, imposta la visibilità della vista che sta per dissolversi inGONE
. Anche se Il valore alpha è 0. L'impostazione della visibilità della visualizzazione suGONE
ne impedisce la visualizzazione dall'utilizzo dello spazio di layout e lo omette dai calcoli di layout, velocizzando l'elaborazione dei dati.
Il seguente metodo mostra un esempio di come eseguire questa operazione:
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); } }); } }
Creare un'animazione di capovolgimento delle carte
La funzione di card flip consente di passare da una visualizzazione all'altra dei contenuti grazie a un'animazione che emula
una carta che gira. L'animazione di capovolgimento delle schede mostrata qui utilizza
FragmentTransaction
Ecco come funziona il lancio di una carta:
Creare oggetti animatori
Per creare l'animazione di capovolgimento delle schede, hai bisogno di quattro animatori. Due animatori sono per quando si anima la parte anteriore della scheda e a sinistra e quando da e verso sinistra. Gli altri due animatori servono quando il retro della scheda anima dentro e da destra e quando anima in uscita e a destra.
<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>
<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>
<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>
<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>
Creare le viste
Ogni lato della scheda è un layout separato che può includere qualsiasi contenuto ad esempio due visualizzazioni di testo, due immagini o qualsiasi combinazione di visualizzazioni da capovolgere tra di loro. Utilizza i due layout nei frammenti che animerai in seguito. La il seguente layout crea un lato di una scheda, che mostra il testo:
<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>
Il layout successivo crea l'altro lato della scheda, che mostra una
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" />
Crea i frammenti
Crea classi di frammenti per la parte anteriore e posteriore della scheda. Nel frammento
, restituiscono i layout che hai creato
onCreateView()
. Puoi quindi creare istanze di questo frammento nell'attività padre
in cui vuoi mostrare la scheda.
L'esempio seguente mostra le classi di frammenti nidificate all'interno dell'attività padre che li utilizza:
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); } } }
Anima il capovolgimento delle carte
Visualizza i frammenti all'interno di un'attività principale. A questo scopo, crea il layout
per la tua attività. L'esempio seguente crea un
FrameLayout
che puoi aggiungere
dai frammenti al runtime:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Nel codice dell'attività, imposta la visualizzazione dei contenuti in base al layout che crei. È buona norma mostrare un frammento predefinito al momento della creazione dell'attività. La la seguente attività di esempio mostra come mostrare la parte anteriore della carta valore predefinito:
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(); } } ... }
Mostrando il fronte della scheda, puoi mostrare il retro con il capovolgere l'animazione al momento opportuno. Crea un metodo per mostrare l'altro lato di la scheda che esegue le seguenti operazioni:
- Imposta le animazioni personalizzate che hai creato per le transizioni dei frammenti.
- Sostituisce il frammento visualizzato con un nuovo frammento e anima questo evento con le animazioni personalizzate che hai creato.
- Aggiunge il frammento visualizzato in precedenza al gruppo posteriore del frammento, in modo che quando l'utente tocca il pulsante Indietro e la scheda gira di nuovo.
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(); } }
Crea un'animazione di rivelazione circolare
Le animazioni di visualizzazione forniscono agli utenti continuità visiva quando mostri o nascondi un gruppo
di elementi UI. La
ViewAnimationUtils.createCircularReveal()
consente di animare un cerchio di ritaglio per rivelare o nascondere una visualizzazione. Questo
l'animazione è disponibile nel
ViewAnimationUtils
,
disponibile per Android 5.0 (livello API 21) e versioni successive.
Ecco un esempio che mostra come rivelare una vista precedentemente invisibile:
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'animazione ViewAnimationUtils.createCircularReveal()
accetta cinque parametri.
Il primo parametro è la visualizzazione che vuoi nascondere o mostrare sullo schermo. La
i due parametri successivi sono le coordinate X e Y del centro del ritaglio
cerchio. In genere, si tratta del centro della vista, ma puoi utilizzare anche
punto che l'utente tocca per avviare l'animazione nel punto in cui ha selezionato. La
il quarto parametro è il raggio iniziale del cerchio di ritaglio.
Nell'esempio precedente, il raggio iniziale è stato impostato su zero, in modo che la vista visualizzato è nascosto dal cerchio. L'ultimo parametro è il raggio finale del cerchio. Quando viene mostrata una vista, il raggio finale deve essere più grande del in modo che la vista possa essere completamente rivelata prima del termine dell'animazione.
Per nascondere una visualizzazione precedentemente visibile:
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); }
In questo caso, il raggio iniziale del cerchio di ritaglio è impostato su un valore pari a
affinché sia visibile prima dell'avvio dell'animazione. Il finale
è impostato su zero, in modo che la visualizzazione sia nascosta al termine dell'animazione.
Aggiungi un listener all'animazione in modo che sia possibile impostare la visibilità della vista su
INVISIBLE
quando l'animazione
vengono completate.
Risorse aggiuntive
- Animazione con Jetpack Compose.
- Gesti con Jetpack Compose.