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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

مراجع عن شاشات البداية

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

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

  • ملف مشروع Adobe After Effects للرسوم المتحركة.
  • ملف AVD XML النهائي الذي تم تصديره.
  • مثال على 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 لتحديد ما إذا كان تطبيقك يعرض دائمًا الرمز على شاشة البداية في 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;
}

مصادر إضافية