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

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

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

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

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

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

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

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

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

لا تظهر شاشة البداية أبدًا خلال التشغيل السريع.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

الرسوم المتحركة على الشاشة البداية وتسلسل بدء التشغيل

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

يتم تضمين رسوم متحركة لشاشة البداية في مكونات تسلسل الإطلاق، كما هو موضح في الشكل 4.

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

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

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

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

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

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

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

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

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

موارد شاشات البداية

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

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

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

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

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

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

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

يمكنك تخصيص شاشة البداية في تطبيقك من خلال تنفيذ أحد الإجراءات التالية:

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

  • ننصحك بإبقاء الفيديو على الشاشة لمدة أطول.

  • خصِّص الصورة المتحركة لإغلاق شاشة البداية.

البدء

توفّر مكتبة SplashScreen الأساسية شاشة البداية Android 12 على جميع الأجهزة بدءًا من API 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 لتحديد ما إذا كان تطبيقك يعرض دائمًا الرمز على شاشة البداية في Android 13 والإصدارات الأحدث. القيمة التلقائية هي 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;
}

مراجع إضافية