Cách làm animation trong android

Trong Lập trình ứng dụng Android, Animation (các chuyển hoạt) như một thành phần cốt yếu để tăng thêm trải nghiệm cho người dùng trong quá trình sử dụng. Trong loạt bài tiếp theo, tôi sẽ hướng dẫn các bạn làm quen với các Animation API. Bài đầu tiên chúng ta sẽ làm quen với View Animation.

ViewAnimation được sử dụng rộng rãi trong hầu hết các phiên bản Android, tính tiện dụng cao cũng như dễ dàng khai báo. Nếu như các chuyển hoạt không quá phức tạp thì ViewAnimation nên là lựa chọn đầu tiên.

Trong ViewAnimation bao gồm các chuyển hoạt sau: scale (phóng to hoặc thu nhỏ), alpha (độ trong suốt), translate (thay đổi vị trí) và rotate (quay).

Tạo Project, trong thư mục res tạo thư mục anim, sau đó lần lượt tạo các tập tin sau:

Cách làm animation trong android

Khai báo cho từng tập tin tương ứng:

+  alpha_anim.xml

Cách làm animation trong android

+ rotate_anim.xml

Cách làm animation trong android

+ scale_anim.xml

Cách làm animation trong android

+ translate_anim.xml

Cách làm animation trong android

+ set_anim.xml

Cách làm animation trong android

Mở tập tin activity_main.xml, thiết kế giao diện với các điều khiển như sau:

Cách làm animation trong android

Vào trong tập tin MainActivity tiến hành khai báo và khởi tạo các thành phần trong giao diện và thiết lập Animation thông qua các lớp tương ứng. Viết phương thức setUpAnimation để xử lý chung cho các tất cả Animation.

Cách làm animation trong android

Xử lý và gọi phương thức trong hàm onCreate.

Cách làm animation trong android

Thực hiện cài ứng dụng lên thiết bị, bấm các nút Animation để xem hiệu ứng.

Trung tâm Tin học - Đại học Khoa học Tự nhiên TP.HCM

Tạo Animation (hiệu ứng chuyển động) trong Android.

Giới thiệu

Trong 1 ứng dụng web, desktop hay ứng dụng trên mobile, thực sự không thể thiếu những animation.

  • Vậy animation là gì?
  • Nó giúp được gì cho ứng dụng và sử dụ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ụ có 2 đối tượng là hình chữ nhật ở bên trái màn hình (vị trí A), muốn di chuyển nó đến bên phải màn hình (vị trí B), như vậy sẽ có 2 cách làm như sau:

  • Cách 1: không sử dụng animation: vẽ lại hình chữ nhật này, ở phía bên trái màn hình. Theo cách này hình chữ nhật bị xuất hiện 1 cách đột ngột.
  • Cách 2: sử dụng animation, dùng hiệu ứng trượt hình chữ nhật sang bên phải dần dần để đến vị trí B. Theo cách này sự di chuyển của hình chữ nhật sẽ mượt mà.

Có những cách nào để thực hiện Animation trong Android?

Trong Android có nhiều lớp và phương thức được dùng cho animation:

  • Những animation có từ API 1 thường được gọi với tên là System animations, gồm có những lớp: RotationAnimation, ScaleAnimation, TranslateAnimation, AlphaAnimation, AnimationSet. Tất cả những lớp này, đều kế thừa từ lớp Animation nằm trong package.
  • Những animation được giới thiệu ở Android 3.0 - API 11 thường được gọi với tên là Animator. Những lớp chính là ValueAnimator, ObjectAnimator, AnimatorSet, .... tất cả những lớp này đều kế thừa từ lớp Animator trong package android.animation.Animator.
  • Ngoài cách trên, để thực hiên animation còn có 1 lớp tên là ViewPropertyAnimator, giúp thực hiện hiệu ứng dễ dàng.

Animation hoạt động như thế nào?

Thực chất Animation trong Android chỉ là sự thay đổi những thuộc tính của View. Khi có sự thay đổi, Android sẽ tiến hành vẽ lại View (gọi lại phương thức onDraw của class View).

Animation là sự chuyển động của 1 đối tượng trong 1 khoảng thời gian t.

Ví dụ 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 tác động sẽ làm thay đổi thuộc tính x của View. Nếu tăng x lên thì View sẽ di chuyển 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ả sử là 10ms sẽ cập nhật frame và tăng x lên 10 đơn vị, sau 4 lần cập nhật thì hình chữ nhật sẽ nằm phía bên phải màn hình.

Cách làm animation trong android

Để làm việc với animation, cần xác định được những tham số sau đây:

  • Đố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 muốn thực hiện hiệu ứng.

Sử dụng ViewPropertyAnimator để tạo hiệu ứng cho View trong Android

  • Bước 1: lấy đối tượng ViewPropertyAnimator
  • Bước 2: xác định thuộc tính của View cần tạo hiệu ứng và sử dụng các phương thức tương ứng.
  • Bước 3. đặt các sự kiện cho animation.
  • Bước 4: đặt thời gian chạy (duration) cho animation, đặt bộ tính toán nội suy cho animation và chạy animation.

Bước 1: lấy đố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ách làm animation trong android

Cách 2: sử dụng lớp ViewCompat với phương thức tĩnh animate(View) để lấy về ViewPropertyAnimator.

Cách làm animation trong android

Bước 2: xác định thuộc tính của View cần tạo hiệu ứng và sử dụng các phương thức tương ứng

Sau khi có được đối tượng viewPropertyAnimator thì 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 1 đoạn giá trị đơn vị theo trục x (tính bằng pixel).
  • translationY(float value): Di chuyển View 1 đoạn giá trị đơ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 là 1.
  • scaleY(float value): scale View theo chiều y, mặc định View sẽ có giá trị scale là 1.
  • alpha(float value): thay đổi giá trị alpha của view, mặc định View sẽ có giá trị alpha là 1.
  • rotation(float value): Xoay View theo 1 góc value.

Ngoài ra, còn có thêm 1 số phương thức như: translationXBy(), translationYBy(), alphaBy(), scaleXBy(), scaleYBy() nên tìm hiểu thêm.

Bước 3: đặt các sự kiện cho animation

ViewPropertyAnimator cung cấp 1 số sự kiện khi thực hiện animation:

public interface ViewPropertyAnimatorListener {
    /**
     *

Notifies the start of the animation.


     *
     * @param view The view associated with the ViewPropertyAnimator
     */
  void onAnimationStart(View view);
    /**
     *

Notifies the end of the animation. This callback is not invoked
     * for animations with repeat count set to INFINITE.


     *
     * @param view The view associated with the ViewPropertyAnimator
     */
  void onAnimationEnd(View view);
    /**
     *

Notifies the cancellation of the animation. This callback is not invoked
     * for animations with repeat count set to INFINITE.


     *
     * @param view The view associated with the ViewPropertyAnimator
     */
    void onAnimationCancel(View view);
}

onAnimationStart()

onAnimationStart() được gọi khi animation bắt đầu chạy.

onAnimationEnd()

onAnimationEnd() được gọi khi animation kết thúc.

onAnimationCancel()

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ư nhấn nút HOME, ...

Và để đặt sự kiện cho ViewPropertyAnimator, sử dụng phương thức setListenner():

public interface ViewPropertyAnimatorUpdateListener {
    /**
     *

Notifies the occurrence of another frame of the animation.


     *
     * @param view The view associated with the ViewPropertyAnimatorCompat
     */
  void onAnimationUpdate(View view);
}

onAnimationUpdate()

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.

Để đặt sự kiện này phải sử dụng phương thức setUpdateListener().

Bước 4: đặt thời gian chạy (duration) cho animation, đặt bộ tính toán nội suy cho animation và chạy animation.

  • setDuration(long): đặt thời gian chạy animation.
  • setInterpolator(Interpolator): đặt bộ tính toán nội suy cho ViewPropertyAnimator.
  • setStartDelay(long): đặt 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à 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à 1 đườ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ị bằng x. 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 bấy nhiêu. Như vậy, y sẽ tăng rất đều theo x hoặc theo thời gian. Nếu áp dụng vào cách xử lý animation thì thấy rằng y di chuyển rất đều giữa các khoảng thời gian.

Cách làm animation trong android

Xét tiếp hàm số y = x^2, hàm số này là 1 parapol, y sẽ tăng nhanh hơn x. Áp dụng vào animation, thời gian càng tăng thì y tăng rất nhanh (có gia tốc). Hay lúc đầu, View di chuyển chậm theo trục y, sau đó tăng rất nhanh cho đến đích.

Vậy 2 hàm số ở trên chính là 2 cách hiện thực Interpolation trong animation, đó là LinearInterpolatorAccelerateInterpolator.

LinearInterpolator

Hàm số y = x

@HasNativeInterpolator
public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
  public LinearInterpolator() {
      // TODO something
    }

    public LinearInterpolator(Context context, AttributeSet attrs) {
     // TODO something
    }

    public float getInterpolation(float input) {
        return input;
    }

    /** @hide */
    @Override
    public long createNativeInterpolator() {
        return NativeInterpolatorFactoryHelper.createLinearInterpolator();
    }
}

Để ý phương thức getInterpolation(float), đây là hàm số y = x.

AccelerateInterpolator

@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 trong quá trình chạy hiệu ứng.

Áp dụng

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 thực hiện translationX()transtlationY() 1 khoảng 100 pixel, đồng thời scaleX 2 lần, scaleY 3 lần và xoay View 1 góc 45 độ. Với khoảng thời gian thực hiện là 3000 ms và 100 ms, thực hiện chạy animation sau khi gọi phương thức start().