إظهار العرض أو إخفاؤه باستخدام الصور المتحركة

تجربة طريقة ComposeAllowed
Jetpack Compose هي مجموعة أدوات واجهة المستخدم التي ننصح بها لنظام التشغيل Android. تعرَّف على كيفية استخدام "الصور المتحركة" في Compose.

أثناء استخدام تطبيقك، تظهر معلومات جديدة على الشاشة وتتم إزالة المعلومات القديمة. قد يكون تغيير ما يظهر على الشاشة فورًا أمرًا مزعجًا، وقد يفوت المستخدمون محتوى جديد يظهر فجأة. تعمل الرسوم المتحركة على إبطاء التغييرات وتجذب عين المستخدم بالحركة بحيث تكون التحديثات أكثر وضوحًا.

هناك ثلاث رسوم متحركة شائعة يمكنك استخدامها لإظهار طريقة عرض أو إخفائها: إظهار الرسوم المتحركة، والرسوم المتحركة المتشابكة، والرسوم المتحركة في Cardflip.

إنشاء رسوم متحركة متشابكة

إنّ الصور المتحركة ذات التأثير المتداخل، تُعرف أيضًا باسم التلاشي، تتلاشى تدريجيًا بأحد العناصر View أو ViewGroup بينما تتلاشى في الوقت نفسه في أخرى. تفيد هذه الصورة المتحركة في الحالات التي تريد فيها تبديل المحتوى أو طرق العرض في تطبيقك. تستخدم صورة متحركة متقاطعة كما هو موضح هنا ViewPropertyAnimator، المتاح في Android 3.1 (المستوى 12 لواجهة برمجة التطبيقات) والإصدارات الأحدث.

في ما يلي مثال على تلاشٍ متقاطع من مؤشر التقدم إلى محتوى نصي:

الشكل 1. صورة متحركة لتأثير التلاشي المتقاطع

إنشاء طرق العرض

أنشئ طريقتَي العرض اللتين تريد تطبيقهما على الرسائل الإلكترونية التي تريد تطبيق التغييرات عليها. ينشئ المثال التالي مؤشر تقدم وعرض نص قابل للتمرير:

<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. صورة متحركة لقلب البطاقة

إنشاء كائنات الرسوم المتحركة

لإنشاء رسم متحرك بقلب البطاقة، تحتاج إلى أربعة مؤثرات حركية. يوجد اثنان من الرسوم المتحركة عندما تتحرك واجهة البطاقة إلى الخارج وإلى اليسار وعندما تتحرك من وإلى اليسار. الرسوم المتحركة الأخرى عندما يتحرك الجزء الخلفي من البطاقة من اليمين وإلى اليمين وعندما يتحرك للخارج وإلى اليمين.

بطاقة_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>

بطاقة_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>

بطاقة_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>

بطاقة_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>

إنشاء طرق العرض

كل جانب من البطاقة عبارة عن تصميم منفصل يمكن أن يحتوي على أي محتوى تريده، مثل عرضي نص أو صورتين أو أي مجموعة من طرق العرض للتبديل بينهما. استخدِم التنسيقَين في الأجزاء التي تريد تحريكها لاحقًا. ينشئ التخطيط التالي جانبًا واحدًا من البطاقة يعرض النص:

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

إنشاء الأجزاء

إنشاء فئات مجزّأة للواجهة الأمامية والخلفية من البطاقة في فئات الأجزاء، اعرض التنسيقات التي أنشأتها باستخدام الطريقة onCreateView(). يمكنك بعد ذلك إنشاء مثيلات لهذا الجزء في النشاط الرئيسي حيث تريد عرض البطاقة.

يعرض المثال التالي فئات تجزئة متداخلة داخل النشاط الرئيسي التي تستخدمها:

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

تحريك قلب البطاقة

عرض الأجزاء داخل نشاط رئيسي. للقيام بذلك، قم بإنشاء التخطيط لنشاطك. ينشئ المثال التالي رمز FrameLayout يمكنك إضافة أجزاء إليه في وقت التشغيل:

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

في رمز النشاط، عيِّن عرض المحتوى ليكون التنسيق الذي تنشئه. من الممارسات الجيدة عرض جزء افتراضي عند إنشاء النشاط. يوضّح مثال النشاط التالي كيفية عرض واجهة البطاقة بشكل تلقائي:

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

مع ظهور الجزء الأمامي من البطاقة، يمكنك إظهار الجزء الخلفي من البطاقة مع الرسوم المتحركة للقلب في الوقت المناسب. أنشئ طريقة لإظهار الجانب الآخر من البطاقة الذي يقوم بالأشياء التالية:

  • لضبط الصور المتحركة المخصّصة التي أنشأتها لانتقالات الأجزاء.
  • يستبدل الجزء المعروض بجزء جديد ويحرّك هذا الحدث بالرسوم المتحركة المخصصة التي أنشأتها.
  • إضافة الجزء المعروض سابقًا إلى الحزمة الخلفية للجزء، لذلك عندما ينقر المستخدم على الزر "رجوع"، يتم قلب البطاقة مرة أخرى.

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

إنشاء صورة متحركة دائرية للاكتشاف

توفر الرسوم المتحركة الكشفية للمستخدمين الاستمرارية المرئية عند إظهار أو إخفاء مجموعة من عناصر واجهة المستخدم. تتيح لك طريقة ViewAnimationUtils.createCircularReveal() تحريك دائرة اقتصاص لإظهار أو إخفاء طريقة عرض. تتوفر هذه الرسوم المتحركة في فئة ViewAnimationUtils، المتوفرة لنظام Android 5.0 (المستوى 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() خمس معلمات. المعلمة الأولى هي العرض الذي تريد إخفاؤه أو إظهاره على الشاشة. المعلمتان التاليتان هما الإحداثيتان X وY لمركز دائرة الاقتصاص. عادةً ما يكون هذا هو مركز العرض، ولكن يمكنك أيضًا استخدام النقطة التي ينقر عليها المستخدم بحيث تبدأ الرسوم المتحركة من حيث يحدد. المعلمة الرابعة هي نصف قطر البدء لدائرة القطع.

في المثال السابق، يتم تعيين نصف القطر الأولي إلى صفر بحيث تكون طريقة العرض المعروضة مخفية بواسطة الدائرة. المعلمة الأخيرة هي نصف القطر النهائي للدائرة. عند عرض طريقة عرض، اجعل نصف القطر النهائي أكبر من العرض حتى يمكن إظهار العرض بالكامل قبل انتهاء الرسم المتحرك.

لإخفاء طريقة عرض كانت مرئية من قبل، يمكنك اتباع الخطوات التالية:

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

وفي هذه الحالة، يتم تعيين نصف القطر الأولي لدائرة الاقتصاص على حجم العرض بحيث يكون العرض مرئيًا قبل بدء الرسم المتحرك. يتم تعيين نصف القطر النهائي إلى صفر بحيث يتم إخفاء العرض عند انتهاء الرسم المتحرك. يمكنك إضافة أداة استماع إلى الصورة المتحركة حتى يمكن ضبط مستوى رؤية العرض على INVISIBLE عند اكتمال الصورة المتحركة.

مصادر إضافية