Hiển thị hoặc ẩn chế độ xem bằng ảnh động

Thử cách Compose
Jetpack Compose là bộ công cụ giao diện người dùng được đề xuất cho Android. Tìm hiểu cách sử dụng Ảnh động trong Compose.

Trong khi ứng dụng của bạn đang được sử dụng, thông tin mới sẽ xuất hiện trên màn hình và thông tin cũ sẽ bị xoá. Việc thay đổi nội dung hiển thị trên màn hình ngay lập tức có thể gây khó chịu và người dùng có thể bỏ lỡ nội dung mới xuất hiện đột ngột. Ảnh động làm chậm các thay đổi và thu hút sự chú ý của người dùng bằng chuyển động để các nội dung cập nhật trở nên rõ ràng hơn.

Có 3 ảnh động phổ biến mà bạn có thể dùng để hiện hoặc ẩn một khung hiển thị: ảnh động mở ra, ảnh động chuyển đổi và ảnh động lật thẻ.

Tạo ảnh động chuyển cảnh

Ảnh động chuyển cảnh (còn gọi là hiệu ứng hoà tan) sẽ làm mờ dần một View hoặc ViewGroup trong khi đồng thời làm mờ dần một View hoặc ViewGroup khác. Ảnh động này rất hữu ích trong những trường hợp bạn muốn chuyển đổi nội dung hoặc khung hiển thị trong ứng dụng. Ảnh động làm mờ chéo xuất hiện ở đây sử dụng ViewPropertyAnimator, có sẵn cho Android 3.1 (cấp độ API 12) trở lên.

Sau đây là ví dụ về hiệu ứng làm mờ chéo từ chỉ báo tiến trình sang nội dung văn bản:

Hình 1. Ảnh động hoà tan.

Tạo các khung hiển thị

Tạo hai khung hiển thị mà bạn muốn chuyển cảnh. Ví dụ sau đây tạo một chỉ báo tiến trình và một view văn bản có thể cuộn:

<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>

Thiết lập ảnh động chuyển cảnh

Để thiết lập ảnh động làm mờ, hãy làm như sau:

  1. Tạo các biến thành phần cho những khung hiển thị mà bạn muốn làm mờ dần. Bạn sẽ cần những tham chiếu này sau khi sửa đổi các thành phần hiển thị trong quá trình tạo ảnh động.
  2. Đặt chế độ hiển thị của khung hiển thị đang được làm mờ thành GONE. Điều này ngăn khung hiển thị sử dụng khoảng trống bố cục và loại bỏ khung hiển thị đó khỏi các phép tính bố cục, giúp tăng tốc quá trình xử lý
  3. Lưu thuộc tính hệ thống config_shortAnimTime vào bộ nhớ đệm trong một biến thành phần. Thuộc tính này xác định thời lượng "ngắn" tiêu chuẩn cho ảnh động. Khoảng thời gian này lý tưởng cho các ảnh động tinh tế hoặc ảnh động xảy ra thường xuyên. config_longAnimTimeconfig_mediumAnimTime cũng có sẵn.

Sau đây là ví dụ sử dụng bố cục trong đoạn mã trước làm khung hiển thị nội dung hoạt động:

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);
    }
    ...
}

Hoà tan các khung hiển thị

Khi các khung hiển thị được thiết lập đúng cách, hãy làm mờ chúng bằng cách thực hiện như sau:

  1. Đối với khung hiển thị đang mờ dần, hãy đặt giá trị alpha thành 0 và chế độ hiển thị thành VISIBLE từ chế độ cài đặt ban đầu là GONE. Thao tác này giúp thành phần hiển thị xuất hiện nhưng trong suốt.
  2. Đối với khung hiển thị đang mờ dần, hãy tạo ảnh động cho giá trị alpha của khung hiển thị đó từ 0 đến 1. Đối với khung hiển thị đang mờ dần, hãy tạo ảnh động cho giá trị alpha từ 1 đến 0.
  3. Sử dụng onAnimationEnd() trong Animator.AnimatorListener, đặt khả năng hiển thị của khung hiển thị đang mờ dần thành GONE. Mặc dù giá trị alpha là 0, nhưng việc đặt chế độ hiển thị của khung hiển thị thành GONE sẽ ngăn khung hiển thị sử dụng không gian bố cục và loại bỏ khung hiển thị đó khỏi các phép tính bố cục, giúp tăng tốc quá trình xử lý.

Phương thức sau đây cho thấy ví dụ về cách thực hiện việc này:

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);
                    }
                });
    }
}

Tạo ảnh động lật thẻ

Thẻ lật chuyển đổi giữa các chế độ xem nội dung bằng cách hiển thị một ảnh động mô phỏng thẻ lật. Ảnh động lật thẻ xuất hiện ở đây sử dụng FragmentTransaction.

Sau đây là hình ảnh minh hoạ hiệu ứng lật thẻ:

Hình 2. Ảnh động lật thẻ.

Tạo các đối tượng trình tạo ảnh động

Để tạo ảnh động lật thẻ, bạn cần có 4 bộ tạo ảnh động. Hai đối tượng tạo hiệu ứng chuyển động là khi mặt trước của thẻ chuyển động ra ngoài và sang trái, cũng như khi thẻ chuyển động vào trong và từ bên trái. Hai bộ tạo ảnh động còn lại là khi mặt sau của thẻ tạo ảnh động từ bên phải và khi mặt sau tạo ảnh động ra bên phải.

card_flip_left_in.xml

<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>

card_flip_left_out.xml

<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>

card_flip_right_in.xml

<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>

card_flip_right_out.xml

<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>

Tạo các khung hiển thị

Mỗi mặt của thẻ là một bố cục riêng biệt có thể chứa bất kỳ nội dung nào bạn muốn, chẳng hạn như 2 khung hiển thị văn bản, 2 hình ảnh hoặc bất kỳ tổ hợp khung hiển thị nào để lật giữa các khung hiển thị. Sử dụng 2 bố cục trong các mảnh mà bạn sẽ tạo hiệu ứng động sau này. Bố cục sau đây tạo một mặt của thẻ, hiển thị văn bản:

<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>

Bố cục tiếp theo sẽ tạo mặt còn lại của thẻ, hiển thị một 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" />

Tạo các mảnh

Tạo các lớp mảnh cho mặt trước và mặt sau của thẻ. Trong các lớp mảnh, hãy trả về bố cục mà bạn đã tạo từ phương thức onCreateView(). Sau đó, bạn có thể tạo các thực thể của mảnh này trong hoạt động mẹ ở vị trí bạn muốn hiển thị thẻ.

Ví dụ sau đây cho thấy các lớp mảnh lồng nhau bên trong hoạt động mẹ sử dụng các lớp đó:

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);
    }
    }
}

Tạo ảnh động cho hiệu ứng lật thẻ

Hiển thị các mảnh bên trong một hoạt động gốc. Để làm việc này, hãy tạo bố cục cho hoạt động của bạn. Ví dụ sau đây tạo một FrameLayout mà bạn có thể thêm các mảnh vào trong thời gian chạy:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

Trong mã hoạt động, hãy đặt khung hiển thị nội dung thành bố cục mà bạn tạo. Bạn nên hiện một mảnh mặc định khi hoạt động được tạo. Hoạt động ví dụ sau đây cho thấy cách hiển thị mặt trước của thẻ theo mặc định:

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();
        }
    }
    ...
}

Khi mặt trước của thẻ đang hiển thị, bạn có thể cho thấy mặt sau của thẻ bằng hiệu ứng lật vào thời điểm thích hợp. Tạo một phương thức để hiện mặt còn lại của thẻ, phương thức này sẽ thực hiện những việc sau:

  • Đặt ảnh động tuỳ chỉnh mà bạn đã tạo cho hiệu ứng chuyển đổi mảnh.
  • Thay thế mảnh hiển thị bằng một mảnh mới và tạo ảnh động cho sự kiện này bằng ảnh động tuỳ chỉnh mà bạn đã tạo.
  • Thêm mảnh đã hiển thị trước đó vào ngăn xếp lui của mảnh, vì vậy khi người dùng nhấn vào nút Quay lại, thẻ sẽ lật lại.

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

Tạo ảnh động hiệu ứng lộ diện hình tròn

Ảnh động hiển thị mang đến cho người dùng sự liên tục về mặt hình ảnh khi bạn hiện hoặc ẩn một nhóm phần tử trên giao diện người dùng. Phương thức ViewAnimationUtils.createCircularReveal() cho phép bạn tạo hiệu ứng cho một vòng tròn cắt để hiển thị hoặc ẩn một khung hiển thị. Ảnh động này có trong lớp ViewAnimationUtils, có sẵn cho Android 5.0 (cấp độ API 21) trở lên.

Sau đây là ví dụ minh hoạ cách hiển thị một khung hiển thị không nhìn thấy trước đó:

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);
}

Ảnh động ViewAnimationUtils.createCircularReveal() có 5 tham số. Tham số đầu tiên là khung hiển thị mà bạn muốn ẩn hoặc hiện trên màn hình. Hai tham số tiếp theo là toạ độ X và Y cho tâm của vòng tròn cắt. Thông thường, đây là tâm của khung hiển thị, nhưng bạn cũng có thể dùng điểm mà người dùng nhấn để ảnh động bắt đầu tại vị trí họ chọn. Tham số thứ tư là bán kính bắt đầu của vòng tròn cắt.

Trong ví dụ trước, bán kính ban đầu được đặt thành 0 để khung hiển thị đang hiển thị bị vòng tròn che khuất. Tham số cuối cùng là bán kính cuối cùng của hình tròn. Khi hiển thị một khung hiển thị, hãy làm cho bán kính cuối cùng lớn hơn khung hiển thị để khung hiển thị có thể được hiển thị đầy đủ trước khi ảnh động kết thúc.

Để ẩn một khung hiển thị từng xuất hiện, hãy làm như sau:

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);
}

Trong trường hợp này, bán kính ban đầu của vòng tròn cắt được đặt lớn bằng khung hiển thị để khung hiển thị xuất hiện trước khi ảnh động bắt đầu. Bán kính cuối cùng được đặt thành 0 để khung hiển thị bị ẩn khi ảnh động kết thúc. Thêm một trình nghe vào ảnh động để bạn có thể đặt chế độ hiển thị của khung hiển thị thành INVISIBLE khi ảnh động hoàn tất.

Tài nguyên khác