หน้าจอแนะนำ

ตั้งแต่ Android 12 เป็นต้นไป SplashScreen API จะช่วยให้แอปเปิดขึ้นพร้อมภาพเคลื่อนไหวได้ ซึ่งรวมถึงการเคลื่อนไหวในแอปเมื่อเปิด หน้าจอแนะนำที่แสดงไอคอนแอป และการเปลี่ยนไปยังแอป SplashScreen เป็น Window และจึงครอบคลุม Activity

รูปที่ 1 หน้าจอแนะนำ

หน้าจอแนะนำจะแสดงองค์ประกอบการออกแบบมาตรฐานในการเปิดแอปทุกครั้ง แต่คุณก็ปรับแต่งหน้าจอแนะนำได้เพื่อให้แอปคงเอกลักษณ์ของแบรนด์ไว้

นอกจากการใช้ API แพลตฟอร์ม SplashScreen แล้ว คุณยังใช้ SplashScreen ไลบรารี compat ซึ่งรวม SplashScreen API ไว้ด้วยได้

วิธีการทำงานของหน้าจอแนะนำ

เมื่อผู้ใช้เปิดแอปขณะที่กระบวนการของแอปไม่ทำงาน (การเริ่มต้นแบบ Cold Start) หรือไม่ได้สร้าง Activity (การเริ่มต้นแบบ Warm Start) เหตุการณ์ต่อไปนี้จะเกิดขึ้น

  1. ระบบจะแสดงหน้าจอแนะนำโดยใช้ธีมและภาพเคลื่อนไหวที่คุณกำหนด

  2. เมื่อแอปพร้อมใช้งานแล้ว หน้าจอแนะนำจะปิดไปและแอปจะแสดง

หน้าจอแนะนำจะไม่แสดงขึ้นในระหว่างการเริ่มต้นแบบร้อน

องค์ประกอบและกลไกของหน้าจอแนะนำ

องค์ประกอบของหน้าจอแนะนำจะกำหนดโดยไฟล์ทรัพยากร XML ในไฟล์ Manifest ของ Android แต่ละองค์ประกอบมีเวอร์ชันโหมดสว่างและโหมดมืด

องค์ประกอบที่ปรับแต่งได้ของหน้าจอแนะนำประกอบด้วยไอคอนแอป พื้นหลังไอคอน และพื้นหลังหน้าต่าง ดังนี้

รูปภาพแสดงองค์ประกอบที่อยู่ในหน้าจอแนะนำ
รูปที่ 2 องค์ประกอบที่ปรับแต่งได้ของหน้าจอแนะนำ

พิจารณาองค์ประกอบต่อไปนี้ที่แสดงในรูปที่ 2

1 ไอคอนแอปต้องเป็น Vector Drawable โดยอาจเป็นภาพนิ่งหรือภาพเคลื่อนไหวก็ได้ แม้ว่าภาพเคลื่อนไหวจะมีระยะเวลาได้ไม่จำกัด แต่เราขอแนะนำให้ไม่เกิน 1,000 มิลลิวินาที ไอคอน Launcher เป็นค่าเริ่มต้น

2 พื้นหลังไอคอนเป็นตัวเลือกที่มีประโยชน์ในกรณีที่คุณต้องการเพิ่มความคมชัดระหว่างไอคอนกับพื้นหลังของหน้าต่าง หากคุณใช้ไอคอนแบบปรับเปลี่ยนได้ ระบบจะแสดงพื้นหลังของไอคอนหากมีคอนทราสต์เพียงพอกับพื้นหลังของหน้าต่าง

3 พื้นหน้า 1 ใน 3 จะถูกมาสก์เช่นเดียวกับไอคอนแบบปรับอัตโนมัติ

4 พื้นหลังของหน้าต่างประกอบด้วยสีทึบเพียงสีเดียว หากตั้งค่าพื้นหลังของหน้าต่างเป็นสีพื้น ระบบจะใช้สีนั้นโดยค่าเริ่มต้นหากไม่ได้ตั้งค่าแอตทริบิวต์

มิติข้อมูลของหน้าจอแนะนำ

ไอคอนหน้าจอแนะนำใช้ข้อมูลจำเพาะเดียวกับไอคอนแบบปรับอัตโนมัติ ดังนี้

  • รูปภาพที่มีแบรนด์: มีขนาด 200×80 dp
  • ไอคอนแอปที่มีพื้นหลังไอคอน: มีขนาด 240×240 dp และพอดีกับวงกลมที่มีเส้นผ่านศูนย์กลาง 160 dp
  • ไอคอนแอปที่ไม่มีพื้นหลังไอคอน: มีขนาด 288×288 dp และพอดีกับวงกลมที่มีเส้นผ่านศูนย์กลาง 192 dp

ตัวอย่างเช่น หากรูปภาพขนาดเต็มคือ 300×300 dp ไอคอนต้องพอดีกับวงกลมที่มีเส้นผ่านศูนย์กลาง 200 dp ทุกอย่างที่อยู่นอกวงกลมจะมองไม่เห็น (ถูกมาสก์)

รูปภาพที่แสดงขนาดไอคอนต่างๆ สำหรับพื้นหลังทึบและโปร่งใส
รูปที่ 3 ขนาดไอคอนหน้าจอแนะนำสำหรับพื้นหลังทึบและโปร่งใสตามลำดับ

ภาพเคลื่อนไหวหน้าจอแนะนำและลำดับการเปิดตัว

เวลาในการตอบสนองที่เพิ่มขึ้นมักเชื่อมโยงกับการเปิดแอปใน Cold Start การเพิ่มไอคอนเคลื่อนไหวลงในหน้าจอเริ่มต้นจะช่วยดึงดูดสายตาและมอบประสบการณ์การใช้งานที่พรีเมียมยิ่งขึ้น การวิจัยผู้ใช้แสดงให้เห็นว่าเวลาเริ่มต้นที่รับรู้จะลดลงเมื่อดูภาพเคลื่อนไหว

ภาพเคลื่อนไหวของหน้าจอแนะนำจะฝังอยู่ในคอมโพเนนต์ลําดับการเริ่มทํางาน ดังที่แสดงในรูปที่ 4

รูปภาพแสดงลำดับการเปิดตัวในเฟรมต่อเนื่องกัน 12 เฟรม โดยเริ่มจากการแตะไอคอน Launcher และขยายเต็มหน้าจอ
รูปที่ 4 ลำดับการเปิดตัว
  1. ภาพเคลื่อนไหวตอนเข้าสู่ระบบ: ประกอบด้วยมุมมองระบบไปยังหน้าจอแนะนำ โดยระบบจะควบคุมและปรับแต่งไม่ได้

  2. ภาพหน้าจอแนะนำ (แสดงในช่วง "รอ" ของลำดับ): คุณปรับแต่งภาพหน้าจอแนะนำได้ ซึ่งจะช่วยให้คุณใส่ภาพเคลื่อนไหวของโลโก้และการสร้างแบรนด์ของคุณเองได้ และต้องเป็นไปตามข้อกำหนดที่อธิบายไว้ในหน้านี้จึงจะทำงานได้อย่างถูกต้อง

  3. ภาพเคลื่อนไหวที่ออก: ประกอบด้วยภาพเคลื่อนไหวที่ซ่อนหน้าจอแนะนำ หากต้องการปรับแต่ง ให้ใช้ SplashScreenView และไอคอน คุณเรียกใช้ภาพเคลื่อนไหวใดก็ได้ในองค์ประกอบเหล่านี้ โดยมีการตั้งค่าสำหรับการเปลี่ยนรูปแบบ ความทึบแสง และสี ในกรณีนี้ ให้นำหน้าจอเริ่มต้นออกด้วยตนเองเมื่อภาพเคลื่อนไหวเสร็จแล้ว

เมื่อแสดงภาพเคลื่อนไหวของไอคอน การเปิดตัวแอปจะให้ตัวเลือกในการข้ามลำดับในกรณีที่แอปพร้อมใช้งานเร็วกว่านั้น แอปจะทริกเกอร์ onResume() หรือหน้าจอแนะนำจะหมดเวลาโดยอัตโนมัติ ดังนั้นโปรดตรวจสอบว่าผู้ใช้ข้ามภาพเคลื่อนไหวได้อย่างสะดวกสบาย หน้าจอแนะนำต้องปิดด้วย onResume() เท่านั้นเมื่อแอปทำงานได้อย่างเสถียรจากมุมมองภาพ จึงไม่จำเป็นต้องมีภาพสปินเนอร์เพิ่มเติม การเปิดตัวอินเทอร์เฟซที่ยังไม่สมบูรณ์อาจทำให้ผู้ใช้สับสนและอาจทำให้ผู้ใช้รู้สึกว่าคุณไม่แน่ใจหรือทำงานไม่เรียบร้อย

ข้อกำหนดสำหรับภาพเคลื่อนไหวหน้าจอแนะนำ

หน้าจอแนะนำต้องเป็นไปตามข้อกำหนดต่อไปนี้

  • ตั้งค่าสีพื้นหลังของหน้าต่างเดียวแบบไม่โปร่งใส ระบบรองรับโหมดกลางวันและกลางคืนด้วยSplashScreen compat library

  • ตรวจสอบว่าไอคอนเคลื่อนไหวเป็นไปตามข้อกำหนดต่อไปนี้

    • รูปแบบ: ไอคอนต้องเป็น AnimatedVectorDrawable (AVD) XML
    • ขนาด: ไอคอน AVD ต้องมีขนาดใหญ่กว่าไอคอนแบบปรับอัตโนมัติ 4 เท่า ดังนี้
      • พื้นที่ของไอคอนต้องเท่ากับ 432 dp หรือ 4 เท่าของพื้นที่ 108 dp ของไอคอนแบบปรับเปลี่ยนได้ซึ่งไม่ได้มาสก์
      • รูปภาพด้านใน 2 ใน 3 จะปรากฏในไอคอน Launcher และต้องมีขนาด 288 dp กล่าวคือ 4 เท่าของ 72 dp ที่ประกอบกันเป็นพื้นที่ด้านในที่มีมาสก์ของไอคอนแบบปรับอัตโนมัติ
    • ระยะเวลา: เราขอแนะนำให้ไม่เกิน 1,000 มิลลิวินาทีในโทรศัพท์ คุณใช้การเริ่มทำงานแบบเลื่อนเวลาได้ แต่ต้องไม่เกิน 166 มิลลิวินาที หากเวลาเริ่มต้นของแอปนานกว่า 1,000 มิลลิวินาที ให้พิจารณาใช้ภาพเคลื่อนไหวแบบวนซ้ำ
  • กำหนดเวลาที่เหมาะสมในการปิดหน้าจอแนะนำ ซึ่งจะเกิดขึ้นเมื่อแอปวาดเฟรมแรก คุณสามารถปรับแต่งเพิ่มเติมตามที่อธิบายไว้ในส่วนการแสดงหน้าจอแนะนำบนหน้าจอเป็นเวลานานขึ้น

ทรัพยากรหน้าจอแนะนำ

รูปที่ 5 ตัวอย่าง AVD

ดาวน์โหลดตัวอย่างชุดเริ่มต้นซึ่งสาธิตวิธีสร้าง จัดรูปแบบ และส่งออกภาพเคลื่อนไหวเป็น AVD ซึ่งรวมถึงสิ่งต่างๆ ต่อไปนี้

  • ไฟล์โปรเจ็กต์ Adobe After Effects ของภาพเคลื่อนไหว
  • ไฟล์ XML ของ AVD ที่ส่งออกเวอร์ชันสุดท้าย
  • ตัวอย่าง GIF ของภาพเคลื่อนไหว

การดาวน์โหลดไฟล์เหล่านี้หมายความว่าคุณยอมรับข้อกำหนดในการให้บริการของ Google

นโยบายความเป็นส่วนตัวของ Google อธิบายวิธีการจัดการข้อมูลในบริการนี้

ปรับแต่งหน้าจอแนะนำในแอป

โดยค่าเริ่มต้น SplashScreen จะใช้ windowBackground ของธีมหาก windowBackground เป็นสีเดียว หากต้องการปรับแต่งหน้าจอแนะนำ ให้เพิ่มแอตทริบิวต์ลงในธีมแอป

คุณปรับแต่งหน้าจอเริ่มต้นของแอปได้โดยทำตามวิธีใดวิธีหนึ่งต่อไปนี้

  • ตั้งค่าแอตทริบิวต์ธีมเพื่อเปลี่ยนลักษณะที่ปรากฏ

  • แสดงบนหน้าจอเป็นเวลานานขึ้น

  • ปรับแต่งภาพเคลื่อนไหวสำหรับการปิดหน้าจอแนะนำ

เริ่มต้นใช้งาน

ไลบรารี SplashScreen หลักจะนําหน้าจอแนะนำของ Android 12 ไปใช้กับอุปกรณ์ทั้งหมดจาก API 23 หากต้องการเพิ่มลงในโปรเจ็กต์ ให้เพิ่มข้อมูลโค้ดต่อไปนี้ลงในไฟล์ build.gradle

Groovy

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 เพื่อแทนที่ไอคอนตรงกลางของหน้าต่างเริ่มต้น

    สำหรับแอปที่กำหนดเป้าหมายเป็น Android 12 (API ระดับ 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 ก็ไม่จำเป็นต้องใช้ Listener ก่อนวาด

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

แหล่งข้อมูลเพิ่มเติม