Ένας οδηγός για αρχάριους για την υλοποίηση του Android Animations - Μέρος 1 (2 μέρη σειράς)

Παραδέχετέ το, πάντα θέλατε να δημιουργήσετε εφαρμογές οπτικά ελκυστικές. Αλλά λόγω της λειτουργικότητας της πρώτης προσέγγισης, τα κινούμενα σχέδια ήταν πάντα χρονοβόρα. Οχι πια.

Λίγα βασικά στοιχεία σχετικά με τα κινούμενα σχέδια:

Υπάρχουν 3 τύποι κινούμενων εικόνων:

  1. Ακίνητα Animations - Χρησιμοποιούνται για την αλλαγή ιδιοκτησίας αντικειμένων (Προβολές ή αντικείμενα που δεν βλέπουν). Ορίζουμε ορισμένες ιδιότητες (όπως translateX, TextScaleX) των αντικειμένων που πρέπει να αλλάξουν. Τα διάφορα χαρακτηριστικά του κινούμενου animation είναι η διάρκεια animation, το αν θα το αντιστρέψουμε και το πόσες φορές θέλουμε να επαναλάβουμε το animation κλπ. Εισήχθησαν στο Android 3.0 (επίπεδο 11 του API).
  2. Προβολή κινήσεων - Χρησιμοποιούνται για να κάνουν απλά κινούμενα σχέδια, όπως αλλαγή μεγέθους, θέσης, περιστροφής, διαφάνεια ελέγχου. Είναι εύκολο να οικοδομηθούν και είναι πολύ γρήγορα αλλά έχουν τους δικούς τους περιορισμούς. Για παράδειγμα - Οι κρατικές αλλαγές αλλά η ιδιοκτησία τους δεν αλλάζει. Οι προβολές κινούμενων εικόνων θα καλυφθούν στο μέρος 2.
  3. Σχετικές κινούμενες εικόνες - Χρησιμοποιείται για να κάνετε κινούμενα σχέδια χρησιμοποιώντας συρραπτικά. Δημιουργείται ένα αρχείο XML που καθορίζει διάφορους καταλόγους συρραπτικών τα οποία εκτελούνται μία προς μία ακριβώς όπως ένα ρολό μιας ταινίας. Αυτό δεν χρησιμοποιείται πολύ, γι 'αυτό δεν θα το καλύψω.
Το Android 5.0 εισήγαγε διάφορα άλλα κινούμενα σχέδια - Reveal Effect, μεταβάσεις δραστηριότητας / θραύσματος, μεταβάσεις Shared Element κλπ. Κάντε κλικ εδώ για να μάθετε περισσότερα σχετικά με αυτό.
Σημείωση - Στο Μέρος 1 θα συζητηθούν μόνο οι Animation Animations.

Πότε να χρησιμοποιήσετε τον τύπο του Animation

  1. Αν θέλετε απλά να κάνετε απλά κινούμενα σχέδια στις προβολές χωρίς να χρειάζεται να χειριστείτε άλλες λεπτομέρειες, όπως αγγίξτε ή κάντε κλικ, χρησιμοποιήστε το στοιχείο Προβολή κινήσεων. Το πρόβλημα με την προβολή των κινούμενων εικόνων είναι ότι, αν και η κατάσταση προβολής αλλάζει, η ιδιότητά της παραμένει στην αρχική θέση. Αυτό σημαίνει ότι, εάν μετατοπιστεί ένα ImageButton από 0 σε 100 pixel προς τα δεξιά, αν και θα ζωντανεύει προς τα δεξιά, η αφή (ιδιότητα) του κουμπιού εικόνας θα είναι ακόμα στην 0η θέση.
  2. Οι προβολές κίνησης μπορούν να χρησιμοποιηθούν στις οθόνες Splash. Όταν χρησιμοποιείτε το Animation View, χρησιμοποιήστε XML αντί να το κάνετε προγραμματιστικά. Χρησιμοποιώντας αρχεία XML, είναι πιο ευανάγνωστο και μπορεί να μοιραστεί με άλλες προβολές.
  3. Αν θέλετε να χειριστείτε την επαφή, κάντε κλικ μετά την κίνηση, πηγαίνετε για το Property Animation καθώς αλλάζουν η κατάσταση καθώς και η συμπεριφορά.

Concepts Animation Property

Στο εσωτερικό του animation ιδιοκτησίας. Ευγενική προσφορά της Google.

Η πραγματική κίνηση πραγματοποιείται από το Value Animator. Αυτή η κλάση παρακολουθεί τη διάρκεια κινούμενης εικόνας και την τρέχουσα τιμή της ιδιότητας που κινεί. Το TimeInterpolater παρακολουθεί το χρόνο (ταχύτητα) της κινούμενης κίνησης όπως το αν είναι με σταθερή ταχύτητα στη δεδομένη χρονική στιγμή ή επιταχύνει και στη συνέχεια επιβραδύνει τη δεδομένη στιγμή. Το TypeEvaluator χρησιμοποιείται για τον υπολογισμό των κλάσεων με βάση τον τύπο TypeEvalutor που χρησιμοποιείται για παράδειγμα, int, float, rgb κλπ. Μπορούμε να χρησιμοποιήσουμε έναν προσαρμοσμένο TypeEvaluator επίσης αν καμία δεν ταιριάζει με τις ανάγκες μας.

Animations Χρησιμοποιώντας το ValueAnimator

Η κλάση ValueAnimator σάς δίνει τη δυνατότητα να ζωντανέψετε αξίες κάποιου τύπου για τη διάρκεια ενός κινούμενου animation, καθορίζοντας ένα σύνολο int, float ή color που θέλετε να ζωντανέψετε. Μπορείτε να αποκτήσετε ένα ValueAnimator καλώντας μία από τις εργοστασιακές μεθόδους του: ofInt (), ofFloat (), orObject (). Για παράδειγμα:

τελικό TextView animateTextView = (TextView) findViewById (R.id.tv_animate);

ValueAnimator valueAnimator = ValueAnimator.ofFloat (0f, 500f);
τιμήAnimator.setInterpolator (νέα AccelerateDecelerateInterpolator ()); // αυξήστε πρώτα την ταχύτητα και στη συνέχεια μειώστε
valueAnimator.setDuration (2000);
valueAnimator.addUpdateListener (νέο ValueAnimator.AnimatorUpdateListener () {
    @Καταπατώ
    δημόσιο κενό στοAnimationUpdate (animation ValueAnimator) {
        πρόοδος float = (float) animation.getAnimatedValue ();
        animateTextView.setTranslationY (πρόοδος);
        // δεν χρειάζεται να χρησιμοποιήσετε invalidate (), όπως ήδη υπάρχει // στην προβολή κειμένου.
    }}
});
τιμήAnimator.start ();
Ευγενική προσφορά του Giphy

Το ίδιο πράγμα μπορεί να επιτευχθεί χρησιμοποιώντας τον κώδικα XML ως εξής:

                   /res/animator/value_animator_ex.xml

                     ---- Κωδικός δραστηριότητας ----
Τιμή ValueAnimatorAnimator = (ValueAnimator) AnimatorInflater.loadAnimator (
        αυτό, R.animator.value_animator_ex).

valueAnimator.addUpdateListener (νέο ValueAnimator.AnimatorUpdateListener () {
    @Καταπατώ
    δημόσιο κενό στοAnimationUpdate (animation ValueAnimator) {
        πρόοδος float = (float) animation.getAnimatedValue ();
        animateTextView.setTranslationY (πρόοδος);
    }}
});

τιμήAnimator.start ();

Animations χρησιμοποιώντας το ObjectAnimator

Το ObjectAnimator είναι μια υποκατηγορία του ValueAnimator και συνδυάζει τη μηχανή χρονισμού και τον υπολογισμό της αξίας του ValueAnimator με τη δυνατότητα να ζωντανεύει μια ονομαστική ιδιότητα ενός αντικειμένου στόχου. Αυτό κάνει την κίνηση κάθε αντικειμένου πολύ πιο εύκολη, καθώς δεν χρειάζεται πλέον να εφαρμόσετε το ValueAnimator.AnimatorUpdateListener, επειδή οι κινούμενες ιδιότητες ενημερώνονται αυτόματα. Στις περισσότερες περιπτώσεις, θα πρέπει να το χρησιμοποιήσουμε.

Για την ίδια κινούμενη εικόνα παραπάνω, μπορούμε να γράψουμε τον κώδικα για το ObjectAnimator ως:

TextView animateTextView = (TextView) findViewById (R.id.tv_animate);

ObjectAnimator textViewAnimator = ObjectAnimator.ofFloat (animateTextView, "translationY", 0f, 500f);
textViewAnimator.setDuration (2000);
textViewAnimator.setInterpolator (νέα AccelerateDecelerateInterpolator ());
textViewAnimator.start ();

Όπως μπορούμε να δούμε, δεν έπρεπε να χρησιμοποιήσουμε τον ακροατή για να ενημερώσουμε τη θέση της προβολής κειμένου, καθώς αυτό γίνεται από το ίδιο το ObjectAnimator. Το κύριο πράγμα εδώ για να δείτε είναι "translationY", το οποίο είναι το ακίνητο που θέλουμε να εκτελέσουμε κινούμενα σχέδια. Αυτό θα πρέπει να είναι μια καθορισμένη ιδιότητα στο android ή εάν είναι η δική μας ιδιότητα, τότε πρέπει να καθορίσουμε τις μεθόδους πρόσβασης, δηλαδή την μέθοδο getter και setter.

Το ίδιο πράγμα μπορεί να υλοποιηθεί με τη χρήση XML ως:

                /res/animator/object_animator_ex.xml

                        ---- Κωδικός δραστηριότητας ----

TextView animateTextView = (TextView) findViewById (R.id.tv_animate);

ObjectAnimator κειμένουViewAnimator = (ObjectAnimator) AnimatorInflater.loadAnimator (AnimationActivity.this, R.animator.object_animator_ex);
textViewAnimator.setTarget (animateTextView);
textViewAnimator.start ();

Κάνοντας πολλαπλές κινήσεις κάθε φορά

Μπορούμε να έχουμε πολλαπλούς ObjectAnimators να ξεκινούν ταυτόχρονα και για την ίδια διάρκεια να κάνουν πολλαπλά κινούμενα σχέδια, αλλά δεν είναι αποτελεσματικά καθώς καμία άποψη δεν γνωρίζει κάποια άλλη προβολή. Για να κάνουμε το ίδιο μπορούμε να χρησιμοποιήσουμε την κλάση AnimatorSet.

Στο τρέχον έργο μου, έχω κάνει το εξής animation:

(Θα ενημερωθεί σύντομα. Λυπούμαστε για την ενόχληση.)

Όπως μπορούμε να δούμε, υπάρχουν πολλαπλά κινούμενα σχέδια που τρέχουν ταυτόχρονα. Υπάρχουν 4 ταυτόχρονες κινούμενες εικόνες. Όταν κάνετε κλικ στο εικονίδιο αναζήτησης, πρώτα το εικονίδιο αναζήτησης μετακινείται προς τα αριστερά, το λογότυπο ξεθωριάζει, το κουμπί ακύρωσης παρακωλύει και το κείμενο επεξεργασίας εξαφανίζεται. Όταν πατήσετε το κουμπί ακύρωσης, παίζεται το ίδιο κινούμενο σχέδιο αλλά το αντίστροφο.

Ο κώδικας για να γίνει αυτό είναι:

   --------- εκτέλεση κινούμενων εικόνων στο εικονίδιο αναζήτησης κλικ ----------
// προς την αριστερή θέση
DisplayMetrics εμφάνισηMetrics = getResources (). GetDisplayMetrics ();
int modifierX = - (displayMetrics.widthPixels - v.getWidth ());
ιδιωτική στατική τελική αναζήτηση int = SEARCH_ANIMATION_DURATION = 1000; // 1 δευτερόλεπτο
Αναζήτηση αντικειμένουAnimatorIconLeftAnimation = ObjectAnimator.ofFloat (v, "translationX", τροποποιητήςX);
αναζήτησηIconLeftAnimation.setDuration (SEARCH_ANIMATION_DURATION);

ObjectAnimator logoFadeOutAnimator = ObjectAnimator.ofFloat (mAppLogo, "άλφα", 1f, 0f);
logoFadeOutAnimator.setDuration (SEARCH_ANIMATION_DURATION).

ObjectAnimator cancelImageFadeInAnimator = ObjectAnimator.ofFloat (mIvCancelSearch, "alpha", 0f, 1f).
cancelImageFadeInAnimator.setDuration (SEARCH_ANIMATION_DURATION);

Αναζήτηση αντικειμένουAnimatorEditTextAnimator = ObjectAnimator.ofFloat (mEtSearch, "alpha", 0f, 1f);
αναζήτησηEditTextAnimator.setDuration (SEARCH_ANIMATION_DURATION);

AnimatorSet animatorSet = νέο AnimatorSet ();
animatorSet.play (αναζήτησηIconLeftAnimation) .with (logoFadeOutAnimator);
animatorSet.play (αναζήτησηIconLeftAnimation) .with (cancelImageFadeInAnimator);
animatorSet.play (αναζήτησηIconLeftAnimation). με (searchEditTextAnimator);

animatorSet.start ();
   --------- αντιστροφή όλων των κινούμενων εικόνων στην ακύρωση κλικ ----------
Αναζήτηση ObjectAnimatorIconRightAnimation = ObjectAnimator.ofFloat (mIvSearch, "translationX", 0);
αναζήτησηIconRightAnimation.setDuration (SEARCH_ANIMATION_DURATION);

ObjectAnimator logoFadeInAnimator = ObjectAnimator.ofFloat (mAppLogo, "άλφα", 0f, 1f);
logoFadeInAnimator.setDuration (SEARCH_ANIMATION_DURATION)

ObjectAnimator cancelImageFadeOutAnimator = ObjectAnimator.ofFloat (mIvCancelSearch, "alpha", 1f, 0f);
cancelImageFadeOutAnimator.setDuration (SEARCH_ANIMATION_DURATION);

Αναζήτηση αντικειμένουAnimatorEditTextFadeInAnimator = ObjectAnimator.ofFloat (mEtSearch, "alpha", 1f, 0f);
αναζήτησηEditTextFadeInAnimator.setDuration (SEARCH_ANIMATION_DURATION);

AnimatorSet animatorSet = νέο AnimatorSet ();
animatorSet.play (αναζήτησηIconRightAnimation) .with (logoFadeInAnimator);
animatorSet.play (αναζήτησηIconRightAnimation) .with (cancelImageFadeOutAnimator);
animatorSet.play (αναζήτησηIconRightAnimation). με (searchEditTextFadeInAnimator);

animatorSet.start ();

Εδώ έχουμε δημιουργήσει πολλαπλούς Object Animators σε διαφορετικές προβολές και τους παίξαμε μαζί χρησιμοποιώντας το AnimatorSet. Μέθοδοι όπως το play () και το () συμβάλλουν στην επίτευξη αυτού του στόχου.

Μπορούμε επίσης να χρησιμοποιήσουμε τους ακροατές για να καθορίσουμε την κατάσταση της κινούμενης εικόνας. Για παράδειγμα:

animatorSet.addListener (νέο Animator.AnimatorListener () {
    @Καταπατώ
    δημόσιο κενό στο AnimationStart (Animator animation) {
        // κάντε κάτι πριν ξεκινήσει η κίνηση
    }}

    @Καταπατώ
    δημόσιο κενό στοAnimationEnd (Animator animation) {
       // κάνει άλλα πράγματα μετά την λήξη της κινούμενης εικόνας
    }}

    @Καταπατώ
    δημόσιο κενό στοAnimationCancel (Animator animation) {
      // κάνει κάτι όταν η κινούμενη εικόνα ακυρώνεται (από χρήστη / προγραμματιστή)
    }}

    @Καταπατώ
    δημόσιο κενό στοAnimationRepeat (Animator animation) {
       // κάνει κάτι όταν η κινούμενη εικόνα επαναλαμβάνεται
    }}
});

Κατά την εκτέλεση πολλαπλών κινούμενων εικόνων σε μια ενιαία προβολή

Μέχρι τώρα, έχουμε δει κινούμενα σχέδια σε διαφορετικά αντικείμενα θέασης. Μπορούμε να εκτελέσουμε πολλαπλά κινούμενα σχέδια σε μια ενιαία προβολή χρησιμοποιώντας και τις παραπάνω προσεγγίσεις (χρησιμοποιώντας το κιτ animator), αλλά είναι μια γενική απόδοση δεδομένου ότι υπάρχει η γενική επεξεργασία της εγκατάστασης του AnimatorSet και η εκτέλεση δύο Animator παράλληλα. Μια καλύτερη προσέγγιση είναι να χρησιμοποιήσετε το ViewPropertyAnimator. Χρησιμοποιώντας αυτό, ο κώδικας είναι πιο εύκολος στην ανάγνωση. Για παράδειγμα:

animationTextView.animate () περιστροφή (360f) .y (500f) .setDuration (2000);
     ---------------------------- VS --------------------- --------
ObjectAnimator περιστροφήAnimator = ObjectAnimator.ofFloat (animateTextView, "περιστροφή", 360f);
rotationAnimator.setDuration (2000);
ObjectAnimator μεταφράστεAnimator = ObjectAnimator.ofFloat (animateTextView, "translationY", 500f);
translateAnimator.setDuration (2000);
Το AnimatorSet set = νέο AnimatorSet ();
set.playTogether (rotationAnimator, μετάφρασηAnimator);
set.start ();

Μήπως η κινούμενη εικόνα κάνει την εφαρμογή μου αργή ή θα ξεπεράσει το χρόνο παράδοσης παραθύρου των 16ms; Υπάρχει κάποια επιβάρυνση για την απόδοση;

Οι κινούμενοι καλλιτέχνες που ενημερώνουν το UI προκαλούν επιπλέον απόδοση σε κάθε καρέ στο οποίο τρέχει η κινούμενη εικόνα. Για το λόγο αυτό, η χρήση κινούμενων εικόνων υψηλής έντασης μπορεί να επηρεάσει αρνητικά την απόδοση της εφαρμογής σας.

Οι εργασίες που απαιτούνται για την κίνηση του περιβάλλοντος εργασίας σας προστίθενται στο στάδιο κινούμενης εικόνας του αγωγού απόδοσης. Μπορείτε να μάθετε εάν τα κινούμενα σχέδια επηρεάζουν την απόδοση της εφαρμογής σας, επιτρέποντας την προβολή GPU προφίλ και παρακολουθώντας το στάδιο της κινούμενης εικόνας.

Σκεφτείτε τη χρήση και εφαρμόστε τον κατάλληλο τρόπο.

Ευχαριστώ που διαβάσατε το άρθρο. Προτάσεις / Διορθώσεις / Σχόλια είναι πάντα ευπρόσδεκτα. Αν σας αρέσει, πατήστε το κουμπί παρόμοιο και μοιραστείτε το άρθρο με την κοινότητα του Android. Ας μοιραστούμε τη γνώση όσο μπορούμε.

Σημείωση - Το μέρος 2 για το ViewAnimations έρχεται πολύ σύντομα.

Επίσης, Ας γίνουμε φίλοι στο About.me, Twitter, LinkedIn, Github και Facebook.