شاشات البداية

اعتبارًا من الإصدار Android 12، تتيح واجهة برمجة التطبيقات SplashScreen للتطبيقات بدء التشغيل باستخدام مؤثرات حركية، بما في ذلك مؤثرات خاصة عند بدء تشغيل التطبيق وكذلك عند الانتقال إلى التطبيق، بالإضافة إلى شاشة بداية تعرض رمز التطبيق. ‫SplashScreen هو Window، وبالتالي يغطي Activity.

الشكل 1: شاشة بداية

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

بالإضافة إلى استخدام واجهة برمجة التطبيقات لمنصة SplashScreen، يمكنك أيضًا استخدام مكتبة التوافق SplashScreen التي تتضمّن واجهة برمجة تطبيقات SplashScreen.

طريقة عمل شاشة البداية

عندما يشغّل المستخدم تطبيقًا أثناء عدم تشغيل عملية التطبيق (تشغيل على البارد) أو عدم إنشاء Activity (إعادة تشغيل بطيء)، تقع الأحداث التالية:

  1. يعرض النظام شاشة البداية باستخدام المظاهر وأي صور متحركة تحددها.

  2. عندما يصبح التطبيق جاهزًا، يتم إغلاق شاشة البداية ويظهر التطبيق.

لا تظهر شاشة البداية مطلقًا أثناء التشغيل السريع.

عناصر شاشة البداية وآلياتها

يتم تحديد عناصر شاشة البداية من خلال ملفات موارد XML في ملف بيان Android. هناك إصدارات للوضع الفاتح والداكن لكل عنصر.

تتكوّن العناصر القابلة للتخصيص في شاشة البداية من رمز التطبيق وخلفية الرمز وخلفية النافذة:

صورة تعرض العناصر المضمّنة في شاشة البداية
الشكل 2. العناصر القابلة للتخصيص في شاشة البداية

ضع في اعتبارك العناصر التالية، الموضحة في الشكل 2:

‫1 يجب أن يكون رمز التطبيق متّجهًا قابلاً للرسم. ويمكن أن يكون ثابتًا أو متحركًا. على الرغم من أنّ الصور المتحركة يمكن أن تكون مدتها غير محدودة، ننصح بألا تتجاوز 1,000 ملي ثانية. رمز مشغّل التطبيقات هو الرمز التلقائي.

‫2 خلفية الرمز اختيارية ومفيدة إذا كنت بحاجة إلى مزيد من التباين بين الرمز وخلفية النافذة. إذا كنت تستخدم رمزًا تكيُّفيًا، فسيتم عرض خلفيته إذا كان هناك تباين كافٍ مع خلفية النافذة.

3 كما هو الحال مع الرموز التكيُّفية، يتم حجب ثلث المقدمة.

‫4 تتكوّن خلفية النافذة من لون واحد معتم. إذا تم ضبط خلفية النافذة وكانت بلون واحد، يتم استخدامها تلقائيًا في حال عدم ضبط السمة.

أبعاد شاشة البداية

يستخدم رمز شاشة البداية المواصفات نفسها التي تستخدمها الرموز التكيُّفية، على النحو التالي:

  • صورة تحمل علامة تجارية: يجب أن تكون بمقاس 200×80 بكسل غير مرتبط بالكثافة.
  • رمز التطبيق مع خلفية الرمز: يجب أن يكون مقاسه 240×240 بكسل مستقل الكثافة وأن يتناسب مع دائرة قطرها 160 بكسل مستقل الكثافة.
  • رمز التطبيق بدون خلفية: يجب أن يكون حجمه ‎288×288 بكسل مستقل الكثافة وأن يتناسب مع دائرة قطرها 192 بكسل مستقل الكثافة.

على سبيل المثال، إذا كان الحجم الكامل للصورة هو 300×300 بكسل مستقل الكثافة، يجب أن يتناسب الرمز مع دائرة قطرها 200 بكسل مستقل الكثافة. يصبح كل شيء خارج الدائرة غير مرئي (مقنع).

صورة تعرض أبعادًا مختلفة للرمز على خلفية بلون واحد وخلفية شفافة
الشكل 3. أبعاد رمز شاشة البداية للخلفيات الصلبة والشفافة على التوالي.

الصور المتحركة لشاشة البداية وتسلسل التشغيل

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

يتم تضمين مؤثرات حركية لشاشة البداية ضمن مكوّنات تسلسل التشغيل، كما هو موضّح في الشكل 4.

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

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

  3. نمط الحركة عند الخروج: يتكوّن من الحركة التي تخفي شاشة البداية. إذا أردت تخصيصها، استخدِم SplashScreenView ورمزها. يمكنك تشغيل أي تأثير متحرك عليها، مع إعدادات للتحويل، والشفافية، واللون. في هذه الحالة، عليك إزالة شاشة البداية يدويًا عند انتهاء الصور المتحركة.

عند تشغيل الحركة الخاصة بالرمز، يتيح لك تشغيل التطبيق خيار تخطّي التسلسل في الحالات التي يكون فيها التطبيق جاهزًا في وقت مبكر. يُشغّل التطبيق onResume() أو تنتهي مهلة شاشة البداية تلقائيًا، لذا تأكَّد من إمكانية تخطّي الحركة بسهولة. يجب إغلاق شاشة البداية باستخدام onResume() فقط عندما يكون التطبيق مستقرًا من الناحية المرئية، وبالتالي لا حاجة إلى استخدام مؤشرات تحميل إضافية. إنّ تقديم واجهة غير مكتملة قد يكون مزعجًا للمستخدمين وقد يعطي انطباعًا بعدم القدرة على التنبؤ أو عدم الدقة.

متطلبات الصور المتحركة لشاشة البداية

يجب أن تلتزم شاشة البداية بالمواصفات التالية:

  • اضبط لون خلفية نافذة واحدة بدون شفافية. يتوفّر الوضعان "النهاري" و"الليلي" في مكتبة التوافق SplashScreen.

  • تأكَّد من أنّ الرمز المتحرّك يستوفي المواصفات التالية:

    • التنسيق: يجب أن يكون الرمز بتنسيق AnimatedVectorDrawable (AVD) XML.
    • الأبعاد: يجب أن يكون حجم رمز AVD أكبر بأربع مرات من حجم الرمز التكيّفي، على النحو التالي:
      • يجب أن تكون مساحة الرمز 432 بكسل مستقل الكثافة، أي أربعة أضعاف مساحة الرمز التكيّفي غير المقنَّع التي تبلغ 108 بكسل مستقل الكثافة.
      • يظهر الثلثان الداخليان من الصورة على رمز مشغّل التطبيقات، ويجب أن يكونا بدقة 288 بكسل مستقل الكثافة، أي أربعة أضعاف دقة 72 بكسل مستقل الكثافة التي تتكوّن منها المنطقة الداخلية المحجوبة من الرمز التكيّفي.
    • المدة: ننصح بألا تتجاوز المدة 1,000 ملي ثانية على الهواتف. يمكنك استخدام بدء متأخر، ولكن لا يمكن أن يكون هذا أطول من 166 مللي ثانية. إذا كان وقت بدء تشغيل التطبيق أطول من 1000 مللي ثانية، ففكر في تكرار الرسوم المتحركة.
  • حدِّد وقتًا مناسبًا لإغلاق شاشة البداية، ويحدث ذلك عندما يرسم تطبيقك الإطار الأول. يمكنك تخصيص ذلك بشكل أكبر كما هو موضّح في القسم المتعلّق بإبقاء شاشة البداية على الشاشة لفترات أطول.

مراجع حول شاشة البداية

الشكل 5. مثال على متوسط مدة المشاهدة

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

  • ملف مشروع Adobe After Effects للصورة المتحركة
  • ملف XML النهائي الذي تم تصديره من AVD
  • مثال على صورة GIF متحركة

يشير تنزيل هذه الملفات إلى موافقتك على بنود خدمة Google.

وتوضّح سياسة خصوصية Google كيفية معالجة البيانات في هذه الخدمة.

تخصيص شاشة البداية في تطبيقك

يستخدم SplashScreen تلقائيًا windowBackground المظهر إذا كان windowBackground لونًا واحدًا. لتخصيص شاشة البداية، أضِف سمات إلى مظهر التطبيق.

يمكنك تخصيص شاشة البداية في تطبيقك من خلال تنفيذ أيّ مما يلي:

  • اضبط سمات المظهر لتغيير شكله.

  • أبقِها على الشاشة لفترة أطول.

  • تخصيص الحركة لإغلاق شاشة البداية

البدء

توفّر مكتبة SplashScreen الأساسية شاشة البداية في Android 12 لجميع الأجهزة التي تعمل بالمستوى 23 من واجهة برمجة التطبيقات. لإضافتها إلى مشروعك، أضِف المقتطف التالي إلى ملف build.gradle:

أنيق

dependencies {
    implementation "androidx.core:core-splashscreen:1.0.0"
}

Kotlin

dependencies {
    implementation("androidx.core:core-splashscreen:1.0.0")
}

ضبط مظهر شاشة البداية لتغيير شكلها

يمكنك تحديد السمات التالية في مظهر Activity لتخصيص شاشة البداية لتطبيقك. إذا كان لديك تنفيذ قديم لشاشة البداية يستخدم سمات مثل android:windowBackground، ننصحك بتوفير ملف موارد بديل لنظام التشغيل Android 12 والإصدارات الأحدث.

  1. استخدِم windowSplashScreenBackground لملء الخلفية بلون واحد محدّد:

    <item name="android:windowSplashScreenBackground">@color/...</item>
    
  2. استخدِم windowSplashScreenAnimatedIcon لاستبدال الرمز في وسط نافذة البدء.

    بالنسبة إلى التطبيقات التي تستهدف الإصدار 12 من نظام التشغيل Android (المستوى 32 لواجهة برمجة التطبيقات) فقط، اتّبِع الخطوات التالية:

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

    <item name="android:windowSplashScreenAnimatedIcon">@drawable/...</item>
    
  3. استخدِم windowSplashScreenAnimationDuration للإشارة إلى مدة حركة رمز شاشة البداية. لا يؤثر ضبط هذه السمة في الوقت الفعلي الذي تظهر فيه شاشة البداية، ولكن يمكنك استردادها عند تخصيص تأثيرات الخروج من شاشة البداية باستخدام SplashScreenView.getIconAnimationDuration. لمزيد من التفاصيل، يُرجى الاطّلاع على القسم التالي حول إبقاء شاشة البداية على الشاشة لفترات أطول.

    <item name="android:windowSplashScreenAnimationDuration">1000</item>
    
  4. استخدِم windowSplashScreenIconBackgroundColor لضبط خلفية وراء رمز شاشة البداية. ويكون ذلك مفيدًا إذا لم يكن هناك تباين كافٍ بين خلفية النافذة والرمز.

    <item name="android:windowSplashScreenIconBackgroundColor">@color/...</item>
    
  5. يمكنك استخدام windowSplashScreenBrandingImage لضبط صورة يتم عرضها في أسفل شاشة البداية. ومع ذلك، توصي إرشادات التصميم بعدم استخدام صورة العلامة التجارية.

    <item name="android:windowSplashScreenBrandingImage">@drawable/...</item>
    
  6. يمكنك استخدام windowSplashScreenBehavior لتحديد ما إذا كان تطبيقك يعرض دائمًا الرمز على شاشة البداية في الإصدار 13 من نظام التشغيل Android والإصدارات الأحدث. القيمة التلقائية هي 0، ما يؤدي إلى عرض الرمز على شاشة البداية إذا ضبط نشاط التشغيل السمة splashScreenStyle على SPLASH_SCREEN_STYLE_ICON، أو يتّبع سلوك النظام إذا لم يحدّد نشاط التشغيل نمطًا. إذا كنت تفضّل عدم عرض شاشة بداية فارغة مطلقًا وتريد دائمًا عرض الرمز المتحرّك، اضبط هذه القيمة على icon_preferred.

    <item name="android:windowSplashScreenBehavior">icon_preferred</item>
    

إبقاء شاشة البداية على الشاشة لفترات أطول

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

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

Kotlin

// Create a new event for the activity.
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    // Set the layout for the content view.
    setContentView(R.layout.main_activity)

    // Set up an OnPreDrawListener to the root view.
    val content: View = findViewById(android.R.id.content)
    content.viewTreeObserver.addOnPreDrawListener(
        object : ViewTreeObserver.OnPreDrawListener {
            override fun onPreDraw(): Boolean {
                // Check whether the initial data is ready.
                return if (viewModel.isReady) {
                    // The content is ready. Start drawing.
                    content.viewTreeObserver.removeOnPreDrawListener(this)
                    true
                } else {
                    // The content isn't ready. Suspend.
                    false
                }
            }
        }
    )
}

Java

// Create a new event for the activity.
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // Set the layout for the content view.
    setContentView(R.layout.main_activity);

    // Set up an OnPreDrawListener to the root view.
    final View content = findViewById(android.R.id.content);
    content.getViewTreeObserver().addOnPreDrawListener(
            new ViewTreeObserver.OnPreDrawListener() {
                @Override
                public boolean onPreDraw() {
                    // Check whether the initial data is ready.
                    if (mViewModel.isReady()) {
                        // The content is ready. Start drawing.
                        content.getViewTreeObserver().removeOnPreDrawListener(this);
                        return true;
                    } else {
                        // The content isn't ready. Suspend.
                        return false;
                    }
                }
            });
}

تخصيص الرسوم المتحركة لإغلاق شاشة البداية

يمكنك تخصيص حركة شاشة البداية بشكل أكبر من خلال Activity.getSplashScreen().

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    // ...

    // Add a callback that's called when the splash screen is animating to the
    // app content.
    splashScreen.setOnExitAnimationListener { splashScreenView ->
        // Create your custom animation.
        val slideUp = ObjectAnimator.ofFloat(
            splashScreenView,
            View.TRANSLATION_Y,
            0f,
            -splashScreenView.height.toFloat()
        )
        slideUp.interpolator = AnticipateInterpolator()
        slideUp.duration = 200L

        // Call SplashScreenView.remove at the end of your custom animation.
        slideUp.doOnEnd { splashScreenView.remove() }

        // Run your animation.
        slideUp.start()
    }
}

Java

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // ...

    // Add a callback that's called when the splash screen is animating to the
    // app content.
    getSplashScreen().setOnExitAnimationListener(splashScreenView -> {
        final ObjectAnimator slideUp = ObjectAnimator.ofFloat(
                splashScreenView,
                View.TRANSLATION_Y,
                0f,
                -splashScreenView.getHeight()
        );
        slideUp.setInterpolator(new AnticipateInterpolator());
        slideUp.setDuration(200L);

        // Call SplashScreenView.remove at the end of your custom animation.
        slideUp.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                splashScreenView.remove();
            }
        });

        // Run your animation.
        slideUp.start();
    });
}

عند بدء عملية الاستدعاء هذه، يبدأ تشغيل المتّجه المتحرّك القابل للرسم على شاشة البداية. استنادًا إلى مدة تشغيل التطبيق، قد يكون العنصر القابل للرسم في منتصف حركته. استخدِم SplashScreenView.getIconAnimationStart لمعرفة وقت بدء الصورة المتحركة. يمكنك حساب المدة المتبقية من الرسوم المتحركة للأيقونة على النحو التالي:

Kotlin

// Get the duration of the animated vector drawable.
val animationDuration = splashScreenView.iconAnimationDuration
// Get the start time of the animation.
val animationStart = splashScreenView.iconAnimationStart
// Calculate the remaining duration of the animation.
val remainingDuration = if (animationDuration != null && animationStart != null) {
    (animationDuration - Duration.between(animationStart, Instant.now()))
        .toMillis()
        .coerceAtLeast(0L)
} else {
    0L
}

Java

// Get the duration of the animated vector drawable.
Duration animationDuration = splashScreenView.getIconAnimationDuration();
// Get the start time of the animation.
Instant animationStart = splashScreenView.getIconAnimationStart();
// Calculate the remaining duration of the animation.
long remainingDuration;
if (animationDuration != null && animationStart != null) {
    remainingDuration = animationDuration.minus(
            Duration.between(animationStart, Instant.now())
    ).toMillis();
    remainingDuration = Math.max(remainingDuration, 0L);
} else {
    remainingDuration = 0L;
}

مراجع إضافية