เปิดเผยหรือซ่อนมุมมองโดยใช้ภาพเคลื่อนไหว

ลองใช้วิธีแบบ Compose
Jetpack Compose เป็นชุดเครื่องมือ UI ที่แนะนำสำหรับ Android ดูวิธีใช้ภาพเคลื่อนไหวใน Compose

ขณะที่ผู้ใช้ใช้แอป ข้อมูลใหม่จะปรากฏบนหน้าจอและข้อมูลเก่าจะถูกนำออก การเปลี่ยนสิ่งที่แสดงบนหน้าจอทันทีอาจทำให้ผู้ใช้รู้สึกขัดตา และพลาดเนื้อหาใหม่ที่ปรากฏขึ้นอย่างกะทันหัน ภาพเคลื่อนไหวจะชะลอการเปลี่ยนแปลงและดึงดูดสายตาผู้ใช้ด้วยการเคลื่อนไหวเพื่อให้การอัปเดตชัดเจนยิ่งขึ้น

ภาพเคลื่อนไหวทั่วไป 3 แบบที่คุณใช้เพื่อแสดงหรือซ่อนมุมมองได้ ได้แก่ ภาพเคลื่อนไหวแบบเปิดเผย ภาพเคลื่อนไหวแบบจางซ้อน และภาพเคลื่อนไหวแบบพลิกการ์ด

สร้างภาพเคลื่อนไหวแบบจางซ้อน

ภาพเคลื่อนไหวแบบจางซ้อน หรือที่เรียกว่า การละลาย จะค่อยๆ จาง View หรือ ViewGroup หนึ่งรายการออกไปพร้อมกับค่อยๆ จางอีกรายการเข้ามา ภาพเคลื่อนไหวนี้มีประโยชน์ในสถานการณ์ที่คุณต้องการ เปลี่ยนเนื้อหาหรือมุมมองในแอป ภาพเคลื่อนไหวแบบจางซ้อนที่แสดงที่นี่ใช้ ViewPropertyAnimator, ซึ่งพร้อมใช้งานสำหรับ Android 3.1 (API ระดับ 12) ขึ้นไป

ตัวอย่างภาพเคลื่อนไหวแบบจางซ้อนจากตัวบ่งชี้ความคืบหน้าไปยังเนื้อหาข้อความ

รูปที่ 1 ภาพเคลื่อนไหวแบบจางซ้อน

สร้างมุมมอง

สร้างมุมมอง 2 รายการที่ต้องการจางซ้อน ตัวอย่างต่อไปนี้สร้างตัวบ่งชี้ความคืบหน้าและมุมมองข้อความที่เลื่อนได้

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

ตั้งค่าภาพเคลื่อนไหวแบบจางซ้อน

หากต้องการตั้งค่าภาพเคลื่อนไหวแบบจางซ้อน ให้ทำดังนี้

  1. สร้างตัวแปรสมาชิกสำหรับมุมมองที่ต้องการจางซ้อน คุณจะต้องใช้ข้อมูลอ้างอิงเหล่านี้ในภายหลังเมื่อแก้ไขมุมมองระหว่างภาพเคลื่อนไหว
  2. ตั้งค่าระดับการมองเห็นของมุมมองที่กำลังจางเข้ามาเป็น GONE ซึ่งจะป้องกันไม่ให้มุมมองใช้พื้นที่เลย์เอาต์และไม่รวมมุมมองจากการคำนวณเลย์เอาต์ ซึ่งจะช่วยเพิ่มความเร็วในการประมวลผล
  3. แคชพร็อพเพอร์ตี้ระบบ config_shortAnimTime ในตัวแปรสมาชิก พร็อพเพอร์ตี้นี้กำหนดระยะเวลา "สั้น" มาตรฐานสำหรับภาพเคลื่อนไหว ระยะเวลานี้เหมาะสำหรับภาพเคลื่อนไหวที่ละเอียดอ่อนหรือภาพเคลื่อนไหวที่เกิดขึ้นบ่อยๆ config_longAnimTime และ config_mediumAnimTime ให้ใช้งานด้วย

ตัวอย่างการใช้เลย์เอาต์จากข้อมูลโค้ดก่อนหน้าเป็นมุมมองเนื้อหาของกิจกรรม

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

จางซ้อนมุมมอง

เมื่อตั้งค่ามุมมองอย่างถูกต้องแล้ว ให้จางซ้อนมุมมองโดยทำดังนี้

  1. สำหรับมุมมองที่กำลังจางเข้ามา ให้ตั้งค่าอัลฟาเป็น 0 และระดับการมองเห็น เป็น VISIBLE จากการตั้งค่าเริ่มต้น เป็น GONE ซึ่งจะทำให้มุมมองมองเห็นได้แต่โปร่งใส
  2. สำหรับมุมมองที่กำลังจางเข้ามา ให้ทำให้ค่าอัลฟาเคลื่อนไหวจาก 0 เป็น 1 สำหรับมุมมองที่กำลังจางออก ให้ทำให้ค่าอัลฟาเคลื่อนไหวจาก 1 เป็น 0
  3. ใช้ onAnimationEnd() ใน Animator.AnimatorListenerเพื่อตั้งค่าระดับการมองเห็นของมุมมองที่กำลังจางออกเป็น GONE แม้ว่าค่าอัลฟาจะเป็น 0 แต่การตั้งค่าระดับการมองเห็นของมุมมองเป็น GONE จะป้องกันไม่ให้มุมมองใช้พื้นที่เลย์เอาต์และไม่รวมมุมมองจากการคำนวณเลย์เอาต์ ซึ่งจะช่วยเพิ่มความเร็วในการประมวลผล

เมธอดต่อไปนี้แสดงตัวอย่างวิธีดำเนินการ

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

สร้างภาพเคลื่อนไหวแบบพลิกการ์ด

การพลิกการ์ดจะสลับระหว่างมุมมองเนื้อหาโดยแสดงภาพเคลื่อนไหวที่จำลองการพลิกการ์ด ภาพเคลื่อนไหวแบบพลิกการ์ดที่แสดงที่นี่ใช้ FragmentTransaction

ภาพเคลื่อนไหวแบบพลิกการ์ดมีลักษณะดังนี้

รูปที่ 2 ภาพเคลื่อนไหวแบบพลิกการ์ด

สร้างออบเจ็กต์ Animator

หากต้องการสร้างภาพเคลื่อนไหวแบบพลิกการ์ด คุณต้องมี Animator 4 รายการ Animator 2 รายการใช้สำหรับเมื่อด้านหน้าของการ์ดเคลื่อนไหวออกไปทางซ้ายและเมื่อเคลื่อนไหวเข้ามาจากทางซ้าย Animator อีก 2 รายการใช้สำหรับเมื่อด้านหลังของการ์ดเคลื่อนไหวเข้ามาจากทางขวาและเมื่อเคลื่อนไหวออกไปทางขวา

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>

สร้างมุมมอง

การ์ดแต่ละด้านเป็นเลย์เอาต์แยกกันซึ่งมีเนื้อหาใดก็ได้ที่คุณต้องการ เช่น มุมมองข้อความ 2 รายการ รูปภาพ 2 รายการ หรือการผสมผสานมุมมองต่างๆ เพื่อสลับไปมา ใช้เลย์เอาต์ 2 รายการใน Fragment ที่คุณทำให้เคลื่อนไหวในภายหลัง เลย์เอาต์ต่อไปนี้สร้างการ์ดด้านหนึ่งซึ่งแสดงข้อความ

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

และเลย์เอาต์ถัดไปจะสร้างการ์ดอีกด้านหนึ่งซึ่งแสดง 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" />

สร้าง Fragment

สร้างคลาส Fragment สำหรับด้านหน้าและด้านหลังของการ์ด ในคลาส Fragment ให้ส่งคืนเลย์เอาต์ที่คุณสร้างจาก onCreateView() เมธอด จากนั้นคุณจะสร้างอินสแตนซ์ของ Fragment นี้ในกิจกรรมหลักที่คุณต้องการแสดงการ์ดได้

ตัวอย่างต่อไปนี้แสดงคลาส Fragment ที่ซ้อนกันภายในกิจกรรมหลักที่ใช้คลาสเหล่านั้น

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

ทำให้การ์ดพลิกเคลื่อนไหว

แสดง Fragment ภายในกิจกรรมหลัก หากต้องการทำเช่นนี้ ให้สร้างเลย์เอาต์สำหรับกิจกรรม ตัวอย่างต่อไปนี้สร้าง FrameLayoutที่คุณเพิ่ม Fragment ได้ในรันไทม์:

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

ในโค้ดกิจกรรม ให้ตั้งค่ามุมมองเนื้อหาเป็นเลย์เอาต์ที่คุณสร้าง แนวทางปฏิบัติแนะนำคือการแสดง Fragment เริ่มต้นเมื่อสร้างกิจกรรม กิจกรรมตัวอย่างต่อไปนี้แสดงวิธีแสดงด้านหน้าของการ์ดโดยค่าเริ่มต้น

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

เมื่อแสดงด้านหน้าของการ์ดแล้ว คุณจะแสดงด้านหลังของการ์ดด้วยภาพเคลื่อนไหวแบบพลิกในเวลาที่เหมาะสมได้ สร้างเมธอดเพื่อแสดงการ์ดอีกด้านหนึ่งซึ่งทำสิ่งต่อไปนี้

  • ตั้งค่าภาพเคลื่อนไหวที่กำหนดเองที่คุณสร้างขึ้นสำหรับการเปลี่ยน Fragment
  • แทนที่ Fragment ที่แสดงด้วย Fragment ใหม่และทำให้เหตุการณ์นี้เคลื่อนไหวด้วยภาพเคลื่อนไหวที่กำหนดเองที่คุณสร้างขึ้น
  • เพิ่ม Fragment ที่แสดงก่อนหน้านี้ลงใน Back Stack ของ Fragment เพื่อให้การ์ดพลิกกลับเมื่อผู้ใช้แตะปุ่มย้อนกลับ

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

สร้างภาพเคลื่อนไหวแบบเปิดเผยวงกลม

ภาพเคลื่อนไหวแบบเปิดเผยช่วยให้ผู้ใช้เห็นความต่อเนื่องของภาพเมื่อคุณแสดงหรือซ่อนกลุ่มองค์ประกอบ UI เมธอด ViewAnimationUtils.createCircularReveal() ช่วยให้คุณทำให้วงกลมการตัดเคลื่อนไหวเพื่อเปิดเผยหรือซ่อนมุมมอง ภาพเคลื่อนไหวนี้มีให้ใช้งานในคลาส ViewAnimationUtils ซึ่งพร้อมใช้งานสำหรับ Android 5.0 (API ระดับ 21) ขึ้นไป

ตัวอย่างต่อไปนี้แสดงวิธีเปิดเผยมุมมองที่มองไม่เห็นก่อนหน้านี้

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

ภาพเคลื่อนไหว ViewAnimationUtils.createCircularReveal() ใช้พารามิเตอร์ 5 รายการ พารามิเตอร์แรกคือมุมมองที่ต้องการซ่อนหรือแสดงบนหน้าจอ พารามิเตอร์ 2 รายการถัดไปคือพิกัด X และ Y สำหรับจุดกึ่งกลางของวงกลมการตัด โดยปกติแล้วจะเป็นจุดกึ่งกลางของมุมมอง แต่คุณยังใช้จุดที่ผู้ใช้แตะเพื่อให้ภาพเคลื่อนไหวเริ่มต้นในตำแหน่งที่ผู้ใช้เลือกได้ด้วย พารามิเตอร์ที่ 4 คือรัศมีเริ่มต้นของวงกลมการตัด

ในตัวอย่างก่อนหน้า รัศมีเริ่มต้นถูกตั้งค่าเป็น 0 เพื่อให้วงกลมซ่อนมุมมองที่แสดงอยู่ พารามิเตอร์สุดท้ายคือรัศมีสุดท้ายของวงกลม เมื่อแสดงมุมมอง ให้กำหนดรัศมีสุดท้ายให้ใหญ่กว่ามุมมองเพื่อให้มุมมองแสดงได้อย่างสมบูรณ์ก่อนที่ภาพเคลื่อนไหวจะสิ้นสุด

หากต้องการซ่อนมุมมองที่มองเห็นได้ก่อนหน้านี้ ให้ทำดังนี้

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

ในกรณีนี้ รัศมีเริ่มต้นของวงกลมการตัดจะถูกตั้งค่าให้มีขนาดใหญ่เท่ากับมุมมองเพื่อให้มุมมองมองเห็นได้ก่อนที่ภาพเคลื่อนไหวจะเริ่มต้น รัศมีสุดท้ายถูกตั้งค่าเป็น 0 เพื่อให้มุมมองถูกซ่อนเมื่อภาพเคลื่อนไหวสิ้นสุด เพิ่ม Listener ลงในภาพเคลื่อนไหวเพื่อให้ตั้งค่าระดับการมองเห็นของมุมมองเป็น INVISIBLE ได้เมื่อภาพเคลื่อนไหว เสร็จสมบูรณ์

แหล่งข้อมูลเพิ่มเติม