ย้ายข้อมูล UI ไปยังเลย์เอาต์ที่ปรับเปลี่ยนตามอุปกรณ์

แอป Android ต้องรองรับระบบนิเวศของรูปแบบอุปกรณ์ที่ขยายตัวอย่างต่อเนื่อง UI ของแอปควรปรับเปลี่ยนให้เหมาะกับหน้าจอขนาดต่างๆ รวมถึงการวางแนวและสถานะอุปกรณ์ที่แตกต่างกัน

UI แบบปรับเปลี่ยนตามอุปกรณ์มุ่งเน้นที่หลักการของความยืดหยุ่นและความต่อเนื่อง

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

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

สิ่งที่ควรหลีกเลี่ยง

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

แอปอาจมีการปรับเปลี่ยนขนาดหน้าต่างเมื่อทำงานในโหมดหลายหน้าต่าง ภาพซ้อนภาพ หรือหน้าต่างรูปแบบอิสระ เช่น ChromeOS อุปกรณ์อาจมีหน้าจอจริงมากกว่า 1 หน้าจอ เช่น อุปกรณ์แบบพับได้หรืออุปกรณ์ที่มีจอแสดงผลหลายจอ ในทุกกรณีเหล่านี้ ขนาดหน้าจอจริงไม่เกี่ยวข้องกับการตัดสินใจเลือกวิธีแสดงเนื้อหา

อุปกรณ์หลายเครื่องที่แสดงหน้าต่างแอปขนาดต่างๆ
รูปที่ 1 ขนาดหน้าต่างอาจแตกต่างจากขนาดของอุปกรณ์จริงหรือขนาดจอแสดงผล

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

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

ใช้เบรกพอยต์และคลาสขนาดหน้าต่างแทนที่จะลองใช้กลยุทธ์ข้างต้น

จุดหยุดพักและคลาสขนาดหน้าต่าง

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

เมื่อออกแบบสำหรับรูปแบบอุปกรณ์หลายรูปแบบ ให้หาค่าเกณฑ์ที่การตัดสินใจระดับสูงเหล่านี้แยกออกเป็นหลายทิศทาง ด้วยเหตุนี้ ตารางกริดเลย์เอาต์ที่ปรับเปลี่ยนตามพื้นที่โฆษณาของ Material Design จึงระบุเบรกพอยต์สำหรับความกว้างและความสูง ซึ่งช่วยให้คุณจับคู่ขนาดดิบเป็นกลุ่มๆ ที่แยกกันตามมาตรฐานและเรียกว่า Window Size Classes เนื่องจากการเลื่อนแนวตั้งมีการใช้งานอย่างแพร่หลาย แอปส่วนใหญ่จึงให้ความสำคัญกับคลาสขนาดความกว้างเป็นหลัก แอปส่วนใหญ่จึงได้รับการเพิ่มประสิทธิภาพสำหรับหน้าจอทุกขนาดได้โดยจัดการจุดหยุดพักเพียงไม่กี่จุด (ดูข้อมูลเพิ่มเติมเกี่ยวกับคลาสขนาดหน้าต่างได้ที่ใช้คลาสขนาดหน้าต่าง)

องค์ประกอบ UI ถาวร

หลักเกณฑ์เลย์เอาต์ของ Material Design จะกำหนดพื้นที่สำหรับแถบแอป การไปยังส่วนต่างๆ และเนื้อหา โดยทั่วไปแล้ว 2 รายการแรกจะเป็นองค์ประกอบ UI ถาวรที่ (หรือใกล้กับ) รูทของลําดับชั้นมุมมอง โปรดทราบว่า "คงที่" ไม่ได้หมายความว่ามุมมองจะปรากฏอยู่เสมอ แต่หมายความว่ามุมมองจะยังคงอยู่ในตำแหน่งเดิมขณะที่มุมมองเนื้อหาอื่นๆ อาจย้ายหรือเปลี่ยนแปลง เช่น องค์ประกอบการนําทางอาจอยู่ในลิ้นชักแบบเลื่อนที่อยู่นอกหน้าจอ แต่ลิ้นชักจะปรากฏอยู่เสมอ

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

<!-- res/layout/main_activity.xml -->

<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- content view(s) -->

    <com.google.android.material.bottomappbar.BottomAppBar
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        ... />
</androidx.constraintlayout.widget.ConstraintLayout>


<!-- res/layout-w600dp/main_activity.xml -->
<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        ... />

    <!-- content view(s) -->
</androidx.constraintlayout.widget.ConstraintLayout>

เนื้อหา

เมื่อวางองค์ประกอบ UI ถาวรแล้ว ให้ใช้พื้นที่ที่เหลือสำหรับเนื้อหา เช่น การใช้ NavHostFragment กับกราฟการนําทางของแอป ดูข้อควรพิจารณาเพิ่มเติมได้จากการนําทางสําหรับ UI แบบตอบสนอง

ตรวจสอบว่าข้อมูลทั้งหมดพร้อมใช้งานสำหรับขนาดต่างๆ

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

เมื่อใช้เลย์เอาต์ที่ปรับขนาดได้ คุณอาจต้องการใช้โมเดลข้อมูลอื่นตามขนาดปัจจุบัน อย่างไรก็ตาม วิธีนี้ขัดต่อหลักการของการรับส่งข้อมูลแบบทิศทางเดียว ข้อมูลควรไหลลงไปยังมุมมอง และเหตุการณ์ต่างๆ เช่น การโต้ตอบของผู้ใช้ควรไหลขึ้น การสร้างการพึ่งพาในอีกทิศทางหนึ่ง ซึ่งโมเดลข้อมูลขึ้นอยู่กับการกำหนดค่าของเลเยอร์ UI จะทําให้กระบวนการนี้ซับซ้อนขึ้นอย่างมาก เมื่อแอปเปลี่ยนขนาด คุณต้องพิจารณาการแปลงจากรูปแบบข้อมูลหนึ่งเป็นรูปแบบอื่น

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

ขยายเนื้อหา

เลย์เอาต์ตามรูปแบบบัญญัติ: ฟีด

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

ทำให้คอลเล็กชันมีขนาดใหญ่ขึ้น แอปจำนวนมากแสดงคอลเล็กชันรายการต่างๆ ในคอนเทนเนอร์แบบเลื่อน เช่น RecyclerView หรือ ScrollView การเปิดใช้คอนเทนเนอร์ให้มีขนาดโตขึ้นโดยอัตโนมัติจะทำให้แสดงเนื้อหาได้มากขึ้น อย่างไรก็ตาม โปรดระวังอย่าให้เนื้อหาภายในคอนเทนเนอร์ยืดหรือบิดเบี้ยวมากเกินไป เช่น หากใช้ RecyclerView ให้พิจารณาใช้เครื่องมือจัดการเลย์เอาต์อื่น เช่น GridLayoutManager, StaggeredGridLayoutManager หรือ FlexboxLayout เมื่อความกว้างไม่กะทัดรัด

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

รายการแต่ละรายการยังใช้ขนาดหรือรูปร่างที่แตกต่างกันเพื่อแสดงเนื้อหาได้มากขึ้นและแยกขอบเขตของรายการได้ง่ายขึ้น

เน้นองค์ประกอบหลัก หากเลย์เอาต์มีจุดโฟกัสที่เฉพาะเจาะจง เช่น รูปภาพหรือวิดีโอ ให้ขยายเลย์เอาต์เมื่อหน้าต่างแอปขยายขึ้นเพื่อรักษาความสนใจของผู้ใช้ องค์ประกอบสนับสนุนอื่นๆ สามารถจัดเรียงใหม่รอบๆ หรือใต้มุมมองฮีโร่ได้

การสร้างเลย์เอาต์ดังกล่าวมีหลายวิธี แต่ ConstraintLayout เหมาะอย่างยิ่งสําหรับวัตถุประสงค์นี้เนื่องจากมีวิธีจํานวนมากในการจํากัดขนาดของมุมมองย่อย ซึ่งรวมถึงการจำกัดด้วยเปอร์เซ็นต์หรือการบังคับใช้สัดส่วนการแสดงผล และเพื่อจัดตําแหน่งมุมมองย่อยตามความสัมพันธ์กับมุมมองย่อยอื่นๆ หรือกับตัวมุมมองย่อยเอง ดูข้อมูลเพิ่มเติมเกี่ยวกับความสามารถทั้งหมดเหล่านี้ได้ในหัวข้อสร้าง UI ที่ปรับเปลี่ยนตามอุปกรณ์ด้วย ConstraintLayout

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

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

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

โทรศัพท์มาตรฐานที่แสดงกล่องโต้ตอบแบบเต็มหน้าจอ และโทรศัพท์แบบพับได้แบบกางออกที่แสดงกล่องโต้ตอบเดียวกันเป็นหน้าต่างลอย
รูปที่ 3 กล่องโต้ตอบแบบเต็มหน้าจอเปลี่ยนเป็นกล่องโต้ตอบมาตรฐานที่มีขนาดกลางและขยาย

เพิ่มเนื้อหา

เลย์เอาต์ตามรูปแบบบัญญัติ: แผงสนับสนุน มุมมองรายการแบบละเอียด

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

สิ่งที่ควรพิจารณาที่สำคัญคือตําแหน่งที่จะวางเนื้อหานี้เมื่อมีพื้นที่ไม่เพียงพอที่จะแสดงแผง ตัวอย่างทางเลือกอื่นๆ มีดังนี้

  • ลิ้นชักด้านข้างที่ขอบท้ายโดยใช้ DrawerLayout
  • ลิ้นชักด้านล่างที่ใช้ BottomSheetBehavior
  • เมนูหรือหน้าต่างป๊อปอัปที่เข้าถึงได้ด้วยการแตะไอคอนเมนู
รูปที่ 4 วิธีอื่นๆ ในการแสดงเนื้อหาเพิ่มเติมในแผงสนับสนุน

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

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

SlidingPaneLayout ที่แสดงทั้ง 2 แผงของเลย์เอาต์รายละเอียดรายการในอุปกรณ์ที่มีจอแสดงผลแบบกว้าง
รูปที่ 5 SlidingPaneLayout ที่แสดงแผง 2 แผงในความกว้างแบบขยายและแผง 1 แผงในความกว้างแบบกะทัดรัด

สร้างเลย์เอาต์แบบ 2 แผงมีรายละเอียดเพิ่มเติมเกี่ยวกับการใช้ SlidingPaneLayout นอกจากนี้ โปรดทราบว่ารูปแบบนี้อาจส่งผลต่อโครงสร้างกราฟการนําทาง (ดูการนําทางสําหรับ UI ที่ปรับเปลี่ยนตามอุปกรณ์)

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