Trong một ứng dụng web, desktop, hay ứng dụng trên mobile thực sự không thể thiếu đi những animation. Và animation là gì? Nó giúp được gì cho ứng dụng của chúng ta và sử dụng chúng khi nào? Animation là những chuyển động hay tập hợp những chuyển động trên các đối tượng giúp chúng chuyển động mượt mà hơn
Giới thiệu
Trong một ứng dụng web, desktop, hay ứng dụng trên mobile thực sự không thể thiếu đi những animation. Và animation là gì? Nó giúp được gì cho ứng dụng của chúng ta và sử dụng chúng khi nào? Animation là những chuyển động hay tập hợp những chuyển động trên các đối tượng giúp chúng chuyển động mượt mà hơn.
Ví dụ chúng ta có hai đối tượng là hình chữ nhật ở bên trái màn hình (vị trí A) và bây giờ tôi muốn di chuyển nó đến bên phải màn hình (vị trí B). Như vậy chúng ta có hai cách làm như sau:
Cách 1: Không sử dụng animation
Đơn giản chúng ta chỉ vẽ lại hình chữ nhật này ở phía bên trái màn hình. Cách này thì hình chữ nhật xuất hiện một cách đột ngột.
Cách 2: Sử dụng animation
Chúng ta sẽ trượt hình chữ nhật sang bên phải sau một khoảng thời gian để đến vị trí B. Theo cách này thì sự di chuyển của hình chữ nhật rất là mượt mà.
Trên đây là những giới thiệu cơ bản về Animation. Phần nội dung chính chúng ta sẽ nói kĩ hơn về Animation sử dụng ViewPropertyAnimator
Có những cách nào để chúng ta thực hiện Animation trong Android
Trong Android có khá nhiều cách để các bạn có thể thực hiện Animation. Dưới đây tôi sẽ liệt kê một số class, method thường được dùng cho Animation.
+ Những Animation có từ bản API 1 và thường được gọi với tên là System Animation. Gồm có những class: RotationAnimation, ScaleAnimtion, TranslateAnimation, AlphaAnimation, AnimationSet. Và tất cả những class này đều kế thừa từ class Animation nằm trong package
+ Những Animation được giới thiệu ở bản Android 3.0 (API 11) và thường được gọi với tên là Animator. Những class chính là ValueAnimator, ObjectAnimator, AnimatorSet… Tất cả những class này đều kế thừa từ lớp Animator trong package android.animation.Animator
+ Ngoài cách trên để chúng ta có thể thực hiên Animation còn có một class có tên là ViewPropertyAnimator giúp chúng ta có thể thực hiện Animate rất là dễ dàng.
Animation hoạt động như thế nào?
Thực chất thì Animation trong Android chỉ là sự thay đổi những thuộc tính của View. Và khi có những sự thay đổi thì Android sẽ tiến hành vẽ lại View (gọi lại phương thức onDraw của class View).
Hình dung bạn là một đối tượng đang đứng ở vị trí A và bạn muốn đến vị trí B trong khoảng thời gian t. Và trong khoảng thời gian t đó bạn có thể đi đều, chạy, trườn hay bất cứ cách nào bạn có thể đến được B. Thì Animation cũng vậy nó cũng là sự chuyển động của một đối tượng trong một khoảng thời gian t.
Hình dung lại ví dụ đầu bài. Tôi muốn di chuyển hình chữ nhật theo chiều ngang từ vị trí x = 0 đến vị trí x = 40 trong khoảng thời gian là 40ms (milisecond). Như vậy khi này chúng ta sẽ tác động làm thay đổi thuộc tính x của View. Nếu ta thay đổi tăng x thì view sẽ dời về bên phải màn hình, ngược lại sẽ lùi về bên trái màn hình. Trong ví dụ này giải sử 10ms chúng ta sẽ update frame và tăng x lên 10 đơn vị thì sau 4 lần update thì hình chữ nhật sẽ nằm phía bên phải màn hình.
Để làm việc với animation chúng ta cần xách định được những tham số sau đây:
- Xác định được đối tượng và thuộc tính của đối tượng cần animate
- Giá trị bắt đầu của thuộc tính
- Giá trị kết thúc của thuộc tính
- Khoảng thời gian mà chúng ta muốn animate
Sử dụng ViewPropertyAnimator để Animation View trong Android
Việc sử dụng ViewPropertyAnimator hoàn toàn rất dễ dàng. Và thông thường có những bước sau:
Bước 1: Lấy về đối tượng ViewPropertyAnimator
Bước 2: Xác định thuộc tính của view cần animate và sử dụng các phương thức tương ứng
Bước 3. Set các event cho animation
Bước 4: Set thời gian chạy (duration) cho animation, set phương tính toán nội suy cho animation, và chạy animation.
Chúng ta sẽ đi qua lần lược từng bước dưới đây:
Bước 1: Lấy về đối tượng ViewPropertyAnimator
Cách 1: Sử dụng phương thức animate() của View để lấy về đối tượng ViewPropertyAnimator
Cách2: Sử dụng lớp ViewCompat với phương thức tỉnh animate(View) để lấy về ViewPropertyAnimator
Bước 2: Xác định thuộc tính của view cần animate và sử dụng các phương thức tương ứng
Sau khi có được đối tượng viewPropertyAnimator thì chúng ta có thể sử dụng các phương thức để biến đối các thuộc tính của View muốn animate. Ví dụ
- translationX(float value): Di chuyển view một đoạn value đơn vị theo trục X (tính bằng pixel)
- translationY(float value): Di chuyển view một đoạn value đơn vị theo trục Y (tính bàng pixel)
- scaleX(float value): scale View theo chiều X, mặc đinh view sẽ có giá trị scale mặc định là 1
- scaleY(float value): scale view theo chiều Y, mặc định view sẽ có giá trị scale mặc định là 1
- alpha(float value): thay đôi giá trị alpha của view. Mặc định view có giá trị alpha là 1.
- rotation(float value): Xoay view theo một góc value.
Ngoài ra còn một số phương thức như x, XBy, y, YBy, translationXBy, translationYBy, alphaBy, scaleXBy, scaleYBy mà các bạn nên tìm hiểu thêm
Bước 3. Set các event cho animation
ViewPropertyAnimator có cung cấp cho chúng ta một số event khi thực hiện animation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
public interface ViewPropertyAnimatorListener { /** * <p>Notifies the start of the animation.</p> * * @param view The view associated with the ViewPropertyAnimator */ void onAnimationStart(View view); /** * <p>Notifies the end of the animation. This callback is not invoked * for animations with repeat count set to INFINITE.</p> * * @param view The view associated with the ViewPropertyAnimator */ void onAnimationEnd(View view); /** * <p>Notifies the cancellation of the animation. This callback is not invoked * for animations with repeat count set to INFINITE.</p> * * @param view The view associated with the ViewPropertyAnimator */ void onAnimationCancel(View view); } |
onAnimationStart
Được gọi khi animation bắt đầu chạy
onAnimationEnd
Được gọi khi animation kết thúc
onAnimationCancel
Được gọi khi animation chưa chạy xong mà lập tức phải kết thúc, ví dụ như home app, …
Và để set event này cho ViewPropertyAnimator chúng ta sử dụng phương thức setListenner
1 2 3 4 5 6 7 8 9 10 |
public interface ViewPropertyAnimatorUpdateListener { /** * <p>Notifies the occurrence of another frame of the animation.</p> * * @param view The view associated with the ViewPropertyAnimatorCompat */ void onAnimationUpdate(View view); } |
onAnimationUpdate
Được gọi trong khi chạy animation, cập nhật thuộc tính của view và vẽ lại View
Để set event này chúng ta sử dụng phương thức setUpdateListener
Bước 4: Set thời gian chạy (duration) cho animation, set phương tính toán nội suy cho animation, và chạy animation.
- setDuration(long value): set thời gian chạy animation
- setInterpolator(Interpolator value): set bộ tính toán nội suy cho ViewPropertyAnimator.
- setStartDelay(long value): set khoảng thời gian delay sau khi gọi phương thức start
- start(): chạy animation.
Bộ tính toán nội suy là gì? Bộ tính toán nội suy là cách tính toán giá trị thuộc tính của View cần animation dựa vào thời gian t.
Xét hàm số y = x, hàm số này là một đường thẳng đi qua trục toạ độ O(0, 0) và lệch gốc 45 so với trục 0x. Ứng với mỗi giá trị của x thì y có giá trị đúng bằng x, hay nói cách khác là x và y tăng đều nhau. Bây giờ hãy xem x là thời gian t và y là vị trí top của view. Ta có y = t. Nếu t tăng bao nhiêu thì y cũng tăng từng đó. Như vậy chúng ta thấy y tăng rất đều theo x hay theo thời gian. Nếu áp dụng cái này vào cách xử lý animation thì chúng ta đều thấy rằng y di chuyển rất đều giữa các khoảng thời gian.
Xét tiếp hàm số y = x^2. Chúng ta thấy hàm này là 1 parapol, y sẽ tăng nhanh hơn x. Và áp dụng vào animation chúng ta thấy rằng khi mà thời gian càng tăng thì y tăng rất nhanh. Hay lúc đầu chúng ta thấy view di chuyển chậm theo trục y, sau đó tăng rất nhanh cho đến đích
Hai hàm số tôi miêu tả ở trên chính là hai cách hiện thực Interpolation trong animation đó là LinearInterpolator và AccelerateInterpolator
LinearInterpolator
Hàm số y = x
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
@HasNativeInterpolator public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory { public LinearInterpolator() { } public LinearInterpolator(Context context, AttributeSet attrs) { } public float getInterpolation(float input) { return input; } /** @hide */ @Override public long createNativeInterpolator() { return NativeInterpolatorFactoryHelper.createLinearInterpolator(); } } |
Các bạn để ý tới phương thức getInterpolation(float). Đây chính là hàm số y = x
AccelerateInterpolator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
@HasNativeInterpolator public class AccelerateInterpolator extends BaseInterpolator implements NativeInterpolatorFactory { private final float mFactor; private final double mDoubleFactor; public AccelerateInterpolator() { mFactor = 1.0f; mDoubleFactor = 2.0; } /** * Constructor * * @param factor Degree to which the animation should be eased. Seting * factor to 1.0f produces a y=x^2 parabola. Increasing factor above * 1.0f exaggerates the ease-in effect (i.e., it starts even * slower and ends evens faster) */ public AccelerateInterpolator(float factor) { mFactor = factor; mDoubleFactor = 2 * mFactor; } public AccelerateInterpolator(Context context, AttributeSet attrs) { this(context.getResources(), context.getTheme(), attrs); } /** @hide */ public AccelerateInterpolator(Resources res, Theme theme, AttributeSet attrs) { TypedArray a; if (theme != null) { a = theme.obtainStyledAttributes(attrs, R.styleable.AccelerateInterpolator, 0, 0); } else { a = res.obtainAttributes(attrs, R.styleable.AccelerateInterpolator); } mFactor = a.getFloat(R.styleable.AccelerateInterpolator_factor, 1.0f); mDoubleFactor = 2 * mFactor; setChangingConfiguration(a.getChangingConfigurations()); a.recycle(); } public float getInterpolation(float input) { if (mFactor == 1.0f) { return input * input; } else { return (float)Math.pow(input, mDoubleFactor); } } /** @hide */ @Override public long createNativeInterpolator() { return NativeInterpolatorFactoryHelper.createAccelerateInterpolator(mFactor); } |
Và tương tự cho hàm số y = x^n.
Đó là tính toán nội suy trongn quá trình animation.
Áp dụng
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
ViewCompat.animate(imvAvatar) .translationY(100) .translationY(100) .rotation(45) .scaleX(2) .scaleY(3) .setUpdateListener(new ViewPropertyAnimatorUpdateListener() { @Override public void onAnimationUpdate(View view) { Log.e(TAG, "onAnimationUpdate: "); } }) .setListener(new ViewPropertyAnimatorListener() { @Override public void onAnimationStart(View view) { Log.e(TAG, "onAnimationStart: "); } @Override public void onAnimationEnd(View view) { Log.e(TAG, "onAnimationEnd: "); } @Override public void onAnimationCancel(View view) { Log.e(TAG, "onAnimationCancel: "); } }) .setInterpolator(new AccelerateInterpolator()) .setDuration(3000) .setStartDelay(100) .start(); |
Đoạn mã này sẽ thực hiện translationX và transtlationY một khoảng 100 pixel đồng thời scaleX 2 lần, scaleY 3 lần và xoay View một góc 45 độ. Với khoảng thời gian thực hiện là 3000 ms và 100ms thực hiện chạy animation sau khi gọi phương thức start().