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

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

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

هناك ثلاثة رسوم متحركة شائعة يمكنك استخدامها لإظهار عرض أو إخفائها: إظهار الرسوم المتحركة، والرسوم المتحركة المتداخل، والرسوم المتحركة بتنسيق 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. صورة متحركة لقلب البطاقة

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

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

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>

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

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

<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 عند اكتمال الصورة المتحركة.

مراجع إضافية