page.title=Định nghĩa Hoạt hình Tùy chỉnh @jd:body

Bài học này hướng dẫn bạn cách

  1. Tùy chỉnh Phản hồi Chạm
  2. Sử dụng Hiệu ứng Lộ ra
  3. Tùy chỉnh Chuyển tiếp Hoạt động
  4. Tạo Hiệu ứng Hoạt hình Thay đổi Trạng thái Xem
  5. Tạo Hiệu ứng Hoạt hình Nội dung vẽ được Véc-tơ

Bạn cũng nên đọc

Hoạt hình theo phong cách material design phản hồi hành động của người dùng và cung cấp tính liên tục trực quan khi người dùng tương tác với ứng dụng của bạn. Giao diện material cung cấp một số hoạt hình mặc định cho các nút và chuyển tiếp hoạt động, và Android 5.0 (API mức 21) và cao hơn cho phép bạn tùy chỉnh những hoạt hình này và tạo các hoạt hình mới:

Tùy chỉnh Phản hồi Chạm

Phản hồi chạm trong Material Design đưa ra một xác nhận trực quan tức thời tại điểm tiếp xúc khi người dùng tương tác với các phần tử UI. Hoạt hình phản hồi chạm mặc định cho nút sẽ sử dụng lớp {@link android.graphics.drawable.RippleDrawable} mới để chuyển tiếp giữa các trạng thái khác nhau bằng hiệu ứng gợn sóng.

Trong hầu hết trường hợp, bạn nên áp dụng tính năng này trong tệp XML dạng xem của mình bằng cách chỉ định nền dạng xem là:

Lưu ý: selectableItemBackgroundBorderless là một thuộc tính mới được giới thiệu trong API mức 21.

Hoặc, bạn có thể định nghĩa {@link android.graphics.drawable.RippleDrawable} làm tài nguyên XML bằng cách sử dụng phần tử ripple.

Bạn có thể gán một màu cho các đối tượng {@link android.graphics.drawable.RippleDrawable}. Để thay đổi màu phản hồi chạm mặc định, hãy sử dụng thuộc tính android:colorControlHighlight của chủ đề.

Để biết thêm thông tin, hãy xem tài liệu tham khảo API cho lớp {@link android.graphics.drawable.RippleDrawable}.

Sử dụng Hiệu ứng Lộ ra

Hoạt hình lộ ra đảm bảo tính liên tục trực quan cho người dùng khi bạn hiện hoặc ẩn một nhóm phần tử UI. Phương thức {@link android.view.ViewAnimationUtils#createCircularReveal ViewAnimationUtils.createCircularReveal()} cho phép bạn tạo hiệu ứng hoạt hình một vòng tròn cắt hình để lộ ra hoặc ẩn một dạng xem.

Để lộ ra một dạng xem ẩn trước đó bằng hiệu ứng này:

// previously invisible view
View myView = findViewById(R.id.my_view);

// get the center for the clipping circle
int cx = (myView.getLeft() + myView.getRight()) / 2;
int cy = (myView.getTop() + myView.getBottom()) / 2;

// get the final radius for the clipping circle
int finalRadius = Math.max(myView.getWidth(), myView.getHeight());

// create the animator for this view (the start radius is zero)
Animator anim =
    ViewAnimationUtils.createCircularReveal(myView, cx, cy, 0, finalRadius);

// make the view visible and start the animation
myView.setVisibility(View.VISIBLE);
anim.start();

Để ẩn một dạng xem hiển thị trước đó bằng hiệu ứng này:

// previously visible view
final View myView = findViewById(R.id.my_view);

// get the center for the clipping circle
int cx = (myView.getLeft() + myView.getRight()) / 2;
int cy = (myView.getTop() + myView.getBottom()) / 2;

// get the initial radius for the clipping circle
int initialRadius = myView.getWidth();

// create the animation (the final radius is zero)
Animator anim =
    ViewAnimationUtils.createCircularReveal(myView, cx, cy, initialRadius, 0);

// 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();

Tùy chỉnh Chuyển tiếp Hoạt động

Hình 1 - Chuyển tiếp với những phần tử chung.

Để phát lại phim, nhấp vào màn hình thiết bị

Chuyển tiếp hoạt động trong các ứng dụng theo phong cách material design cung cấp kết nối trực quan giữa các trạng thái khác nhau thông qua chuyển động và chuyển đổi giữa những phần tử hay dùng. Bạn có thể quy định hoạt hình tùy chỉnh cho các chuyển tiếp ra vào và chuyển tiếp phần tử chung giữa các hoạt động.

Android 5.0 (API mức 21) hỗ trợ những chuyển tiếp ra vào sau:

Bất cứ chuyển tiếp nào mở rộng lớp {@link android.transition.Visibility} đều được hỗ trợ như một chuyển tiếp vào hoặc ra. Để biết thêm thông tin, hãy xem tài liệu tham khảo API cho lớp {@link android.transition.Transition}.

Android 5.0 (API mức 21) cũng hỗ trợ những chuyển tiếp phần tử chung này:

Khi bạn cho phép chuyển tiếp hoạt động trong ứng dụng của mình, chuyển tiếp mờ dần chéo cross-fading mặc định sẽ được kích hoạt giữa các hoạt động ra vào.

  Hình 2 - Chuyển tiếp cảnh với một phần tử chung.

Quy định chuyển tiếp tùy chỉnh

Trước tiên, cho phép chuyển tiếp nội dung cửa sổ bằng thuộc tính android:windowContentTransitions khi bạn định nghĩa một kiểu kế thừa từ chủ đề material. Bạn cũng có thể quy định chuyển tiếp ra, vào và phần tử chung trong định nghĩa kiểu của mình:

<style name="BaseAppTheme" parent="android:Theme.Material">
  <!-- enable window content transitions -->
  <item name="android:windowContentTransitions">true</item>

  <!-- specify enter and exit transitions -->
  <item name="android:windowEnterTransition">@transition/explode</item>
  <item name="android:windowExitTransition">@transition/explode</item>

  <!-- specify shared element transitions -->
  <item name="android:windowSharedElementEnterTransition">
    @transition/change_image_transform</item>
  <item name="android:windowSharedElementExitTransition">
    @transition/change_image_transform</item>
</style>

Chuyển tiếp change_image_transform trong ví dụ này được định nghĩa như sau:

<!-- res/transition/change_image_transform.xml -->
<!-- (see also Shared Transitions below) -->
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
  <changeImageTransform/>
</transitionSet>

Phần tử changeImageTransform tương ứng với lớp {@link android.transition.ChangeImageTransform}. Để biết thêm thông tin, hãy xem tài liệu tham khảo API cho {@link android.transition.Transition}.

Thay vào đó, để cho phép chuyển tiếp nội dung cửa sổ trong mã của bạn, hãy gọi phương thức {@link android.view.Window#requestFeature Window.requestFeature()}:

// inside your activity (if you did not enable transitions in your theme)
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);

// set an exit transition
getWindow().setExitTransition(new Explode());

Để quy định chuyển tiếp trong mã của bạn, hãy gọi những phương thức này bằng đối tượng {@link android.transition.Transition}:

Phương thức {@link android.view.Window#setExitTransition setExitTransition()} và {@link android.view.Window#setSharedElementExitTransition setSharedElementExitTransition()} định nghĩa chuyển tiếp ra cho hoạt động gọi. Phương thức {@link android.view.Window#setEnterTransition setEnterTransition()} và {@link android.view.Window#setSharedElementEnterTransition setSharedElementEnterTransition()} định nghĩa chuyển tiếp vào cho hoạt động được gọi.

Để có đầy đủ hiệu ứng của một chuyển tiếp, bạn phải cho phép chuyển tiếp nội dung cửa sổ trên cả hoạt động gọi và được gọi. Nếu không, hoạt động gọi sẽ bắt đầu chuyển tiếp ra, nhưng khi đó bạn sẽ thấy chuyển tiếp cửa sổ (như co giãn và mờ dần).

Để bắt đầu một chuyển tiếp vào ngay khi có thể, hãy sử dụng phương thức {@link android.view.Window#setAllowEnterTransitionOverlap Window.setAllowEnterTransitionOverlap()} trên hoạt động được gọi. Nó cho phép bạn có chuyển tiếp vào ấn tượng hơn.

Bắt đầu một hoạt động bằng chuyển tiếp

Nếu bạn cho phép chuyển tiếp và đặt chuyển tiếp ra cho một hoạt động, chuyển tiếp sẽ được kích hoạt khi bạn khởi chạy một hoạt động khác như sau:

startActivity(intent,
              ActivityOptions.makeSceneTransitionAnimation(this).toBundle());

Nếu bạn đặt một chuyển tiếp vào cho hoạt động thứ hai, chuyển tiếp này cũng được kích hoạt khi hoạt động bắt đầu. Để vô hiệu hoá chuyển tiếp khi bạn bắt đầu một hoạt động khác, hãy cung cấp một nhóm tùy chọn null.

Bắt đầu một hoạt động bằng một phần tử chung

Để tạo một hoạt hình chuyển tiếp màn hình giữa hai hoạt động có một phần tử chung:

  1. Cho phép chuyển tiếp nội dung cửa sổ trong chủ đề của bạn.
  2. Quy định một chuyển tiếp phần tử chung trong kiểu của bạn.
  3. Định nghĩa chuyển tiếp của bạn dưới dạng một tài nguyên XML.
  4. Gán một tên chung cho các phần tử chung ở cả hai bố trí bằng thuộc tính android:transitionName.
  5. Sử dụng phương thức {@link android.app.ActivityOptions#makeSceneTransitionAnimation ActivityOptions.makeSceneTransitionAnimation()}.
// get the element that receives the click event
final View imgContainerView = findViewById(R.id.img_container);

// get the common element for the transition in this activity
final View androidRobotView = findViewById(R.id.image_small);

// define a click listener
imgContainerView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        Intent intent = new Intent(this, Activity2.class);
        // create the transition animation - the images in the layouts
        // of both activities are defined with android:transitionName="robot"
        ActivityOptions options = ActivityOptions
            .makeSceneTransitionAnimation(this, androidRobotView, "robot");
        // start the new activity
        startActivity(intent, options.toBundle());
    }
});

Đối với các dạng xem động dùng chung mà bạn khởi tạo trong mã của mình, hãy sử dụng phương thức {@link android.view.View#setTransitionName View.setTransitionName()} để quy định một tên phần tử chung trong cả hai hoạt động.

Để đảo ngược hoạt hình chuyển tiếp cảnh khi bạn kết thúc hoạt động thứ hai, hãy gọi phương thức {@link android.app.Activity#finishAfterTransition Activity.finishAfterTransition()} thay vì {@link android.app.Activity#finish Activity.finish()}.

Bắt đầu một hoạt động bằng nhiều phần tử chung

Để tạo một hoạt hình chuyển tiếp cảnh giữa hai hoạt động có nhiều hơn một phần tử chung, hãy định nghĩa các phần tử chung trong cả hai bố trí bằng thuộc tính android:transitionName (hoặc sử dụng phương thức {@link android.view.View#setTransitionName View.setTransitionName()} trong cả hai hoạt động), và tạo một đối tượng {@link android.app.ActivityOptions} như sau:

ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this,
        Pair.create(view1, "agreedName1"),
        Pair.create(view2, "agreedName2"));

Sử dụng Chuyển động Cong

Hoạt hình theo phong cách material design phụ thuộc vào đường cong làm mẫu hình nội suy thời gian và chuyển động không gian. Với Android 5.0 (API mức 21) trở lên, bạn có thể định nghĩa đường cong định thời tùy chỉnh và mẫu hình chuyển động cong cho hoạt hình.

Lớp {@link android.view.animation.PathInterpolator} là một hàm nội suy mới dựa trên đường cong Bézier hoặc đối tượng {@link android.graphics.Path}. Hàm nội suy này quy định một đường cong chuyển động trong một hình vuông 1x1, với các điểm neo tại (0,0) và (1,1) cùng các điểm kiểm soát được quy định bằng cách sử dụng các tham đối của hàm dựng. Bạn cũng có thể định nghĩa một hàm nội suy đường dẫn dưới dạng tài nguyên XML:

<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
    android:controlX1="0.4"
    android:controlY1="0"
    android:controlX2="1"
    android:controlY2="1"/>

Hệ thống cung cấp tài nguyên XML cho ba đường cong cơ bản trong đặc tả material design:

Bạn có thể chuyển một đối tượng {@link android.view.animation.PathInterpolator} tới phương thức {@link android.animation.Animator#setInterpolator Animator.setInterpolator()}.

Lớp {@link android.animation.ObjectAnimator} có các hàm dựng mới cho phép bạn tạo hiệu ứng hoạt hình cho các tọa độ dọc theo một đường dẫn bằng hai hoặc nhiều thuộc tính đồng thời. Ví dụ, trình tạo hoạt hình sau sử dụng một đối tượng {@link android.graphics.Path} để tạo hiệu ứng hoạt hình cho thuộc tính X và Y của một dạng xem:

ObjectAnimator mAnimator;
mAnimator = ObjectAnimator.ofFloat(view, View.X, View.Y, path);
...
mAnimator.start();

Tạo Hiệu ứng Hoạt hình Thay đổi Trạng thái Xem

Lớp {@link android.animation.StateListAnimator} cho phép bạn định nghĩa trình tạo hoạt hình để chạy khi trạng thái của dạng xem thay đổi. Ví dụ sau cho biết cách định nghĩa một {@link android.animation.StateListAnimator} dưới dạng tài nguyên XML:

<!-- animate the translationZ property of a view when pressed -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:state_pressed="true">
    <set>
      <objectAnimator android:propertyName="translationZ"
        android:duration="@android:integer/config_shortAnimTime"
        android:valueTo="2dp"
        android:valueType="floatType"/>
        <!-- you could have other objectAnimator elements
             here for "x" and "y", or other properties -->
    </set>
  </item>
  <item android:state_enabled="true"
    android:state_pressed="false"
    android:state_focused="true">
    <set>
      <objectAnimator android:propertyName="translationZ"
        android:duration="100"
        android:valueTo="0"
        android:valueType="floatType"/>
    </set>
  </item>
</selector>

Để gắn kèm hoạt hình trạng thái dạng xem tùy chỉnh vào một dạng xem, hãy định nghĩa một trình tạo hoạt hình bằng cách sử dụng phần tử selector trong một tệp tài nguyên XML như trong ví dụ này, và gán nó cho dạng xem của bạn bằng thuộc tính android:stateListAnimator. Để gán một trình tạo hoạt hình danh sách trạng thái cho một dạng xem trong mã của bạn, hãy sử dụng phương thức {@link android.animation.AnimatorInflater#loadStateListAnimator AnimationInflater.loadStateListAnimator()} và gán trình tạo hoạt hình cho dạng xem của bạn bằng phương thức {@link android.view.View#setStateListAnimator View.setStateListAnimator()}.

Khi chủ đề của bạn mở rộng ra chủ đề material, các nút sẽ có hoạt hình Z theo mặc định. Để tránh hành vi này trong nút của bạn, hãy đặt thuộc tính android:stateListAnimator thành @null.

Lớp {@link android.graphics.drawable.AnimatedStateListDrawable} cho phép bạn tạo các nội dung vẽ được để hiển thị hoạt hình giữa các thay đổi trạng thái của dạng xem được liên kết. Một số widget hệ thống trong Android 5.0 sử dụng những hoạt hình này theo mặc định. Ví dụ sau cho biết cách cách định nghĩa {@link android.graphics.drawable.AnimatedStateListDrawable} dưới dạng tài nguyên XML:

<!-- res/drawable/myanimstatedrawable.xml -->
<animated-selector
    xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- provide a different drawable for each state-->
    <item android:id="@+id/pressed" android:drawable="@drawable/drawableP"
        android:state_pressed="true"/>
    <item android:id="@+id/focused" android:drawable="@drawable/drawableF"
        android:state_focused="true"/>
    <item android:id="@id/default"
        android:drawable="@drawable/drawableD"/>

    <!-- specify a transition -->
    <transition android:fromId="@+id/default" android:toId="@+id/pressed">
        <animation-list>
            <item android:duration="15" android:drawable="@drawable/dt1"/>
            <item android:duration="15" android:drawable="@drawable/dt2"/>
            ...
        </animation-list>
    </transition>
    ...
</animated-selector>

Tạo Hiệu ứng Hoạt hình Nội dung vẽ được Véc-tơ

Nội dung vẽ được Véc-tơ sẽ co giãn được mà không làm mất độ sắc nét. Lớp {@link android.graphics.drawable.AnimatedVectorDrawable} cho phép bạn tạo hiệu ứng hoạt hình các thuộc tính của nội dung vẽ được véc-tơ.

Thường thì bạn định nghĩa nội dung vẽ được véc-tơ hoạt hình theo ba tệp XML:

Nội dung vẽ được véc-tơ hoạt hình có thể tạo hiệu ứng hoạt hình các thuộc tính của phần tử <group><path>. Phần tử <group> định nghĩa một bộ đường dẫn hoặc nhóm phụ và phần tử <path> định nghĩa các đường dẫn sẽ được vẽ.

Khi định nghĩa một nội dung vẽ được véc-tơ mà bạn muốn tạo hiệu ứng hoạt hình, hãy sử dụng thuộc tính android:name để gán một tên duy nhất cho các nhóm và đường dẫn, sao cho bạn có thể tham chiếu tới chúng từ các định nghĩa trình tạo hoạt hình của mình. Ví dụ:

<!-- res/drawable/vectordrawable.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:height="64dp"
    android:width="64dp"
    android:viewportHeight="600"
    android:viewportWidth="600">
    <group
        android:name="rotationGroup"
        android:pivotX="300.0"
        android:pivotY="300.0"
        android:rotation="45.0" >
        <path
            android:name="v"
            android:fillColor="#000000"
            android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" />
    </group>
</vector>

Định nghĩa nội dung vẽ được véc-tơ hoạt hình sẽ tham chiếu tới các nhóm và đường dẫn trong nội dung vẽ được véc-tơ theo tên của chúng:

<!-- res/drawable/animvectordrawable.xml -->
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
  android:drawable="@drawable/vectordrawable" >
    <target
        android:name="rotationGroup"
        android:animation="@anim/rotation" />
    <target
        android:name="v"
        android:animation="@anim/path_morph" />
</animated-vector>

Định nghĩa hoạt hình biểu diễn các đối tượng {@link android.animation.ObjectAnimator} hoặc {@link android.animation.AnimatorSet}. Trình tạo hoạt hình đầu tiên trong ví dụ này sẽ xoay nhóm đối tượng 360 độ:

<!-- res/anim/rotation.xml -->
<objectAnimator
    android:duration="6000"
    android:propertyName="rotation"
    android:valueFrom="0"
    android:valueTo="360" />

Trình tạo hoạt hình thứ hai trong ví dụ này sẽ đổi dạng đường dẫn của nội dung vẽ được véc-tơ từ hình này sang hình khác. Cả hai đường dẫn đều phải tương thích với việc đổi dạng: chúng phải có cùng số lệnh và cùng số lượng tham số cho từng lệnh.

<!-- res/anim/path_morph.xml -->
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <objectAnimator
        android:duration="3000"
        android:propertyName="pathData"
        android:valueFrom="M300,70 l 0,-70 70,70 0,0   -70,70z"
        android:valueTo="M300,70 l 0,-70 70,0  0,140 -70,0 z"
        android:valueType="pathType" />
</set>

Để biết thêm thông tin, hãy xem tài liệu tham khảo API cho {@link android.graphics.drawable.AnimatedVectorDrawable}.