เลย์เอาต์ที่ปรับเปลี่ยนตามอุปกรณ์/แบบปรับขนาดได้มอบประสบการณ์การใช้งานที่เหมาะสมที่สุดแก่ผู้ใช้ไม่ว่าหน้าจอจะมีขนาดเท่าใด ใช้เลย์เอาต์ที่ปรับเปลี่ยนตามอุปกรณ์/แบบปรับขนาดได้เพื่อให้แอปที่อิงตามมุมมองรองรับขนาด การวางแนว และการกำหนดค่าการแสดงผลทั้งหมด รวมถึงการกำหนดค่าที่ปรับขนาดได้ เช่น โหมดหลายหน้าต่าง
การออกแบบที่ปรับเปลี่ยนตามอุปกรณ์
ขั้นตอนแรกในการรองรับรูปแบบของอุปกรณ์ที่หลากหลายคือการสร้างเลย์เอาต์ที่ปรับเปลี่ยนตามพื้นที่แสดงผลที่แอปใช้ได้
ConstraintLayout
วิธีที่ดีที่สุดในการสร้างเลย์เอาต์ที่ปรับเปลี่ยนตามอุปกรณ์คือการใช้
ConstraintLayout
เป็นเลย์เอาต์พื้นฐานสำหรับ UI ConstraintLayout ช่วยให้คุณระบุตำแหน่งและขนาดของแต่ละมุมมองตามความสัมพันธ์เชิงพื้นที่กับมุมมองอื่นๆ ในเลย์เอาต์ได้ จากนั้นมุมมองทั้งหมดจะเคลื่อนที่และปรับขนาดไปพร้อมกันเมื่อพื้นที่แสดงผลเปลี่ยนแปลง
วิธีที่ง่ายที่สุดในการสร้างเลย์เอาต์ด้วย ConstraintLayout คือการใช้ Layout Editor ใน Android Studio เครื่องมือสร้างเลย์เอาต์ช่วยให้คุณลากมุมมองใหม่ไปยังเลย์เอาต์ ใช้ข้อจำกัดที่เกี่ยวข้องกับมุมมองระดับบนและระดับเดียวกัน และตั้งค่าพร็อพเพอร์ตี้ของมุมมองได้โดยไม่ต้องแก้ไข XML ด้วยตนเอง
ConstraintLayout.
ดูข้อมูลเพิ่มเติมได้ที่สร้าง UI ที่ปรับเปลี่ยนตามอุปกรณ์ด้วย ConstraintLayout
ความกว้างและความสูงที่ปรับเปลี่ยนตามอุปกรณ์
หากต้องการให้เลย์เอาต์ปรับเปลี่ยนตามขนาดการแสดงผลต่างๆ ให้ใช้ wrap_content, match_parent หรือ 0dp (match constraint) สำหรับความกว้างและความสูงของคอมโพเนนต์มุมมองแทนค่าที่ฮาร์ดโค้ดไว้
wrap_content: มุมมองจะตั้งค่าขนาดให้พอดีกับเนื้อหาที่มุมมองนั้นมีmatch_parent: มุมมองจะขยายให้มากที่สุดเท่าที่จะทำได้ภายในมุมมองระดับบน0dp (match constraint): ในConstraintLayoutจะคล้ายกับmatch_parentมุมมองจะใช้พื้นที่ทั้งหมดที่ใช้ได้ภายในข้อจำกัดของมุมมอง
เช่น
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/lorem_ipsum" />
รูปที่ 4 แสดงวิธีที่ความกว้างและความสูงของ TextView ปรับเปลี่ยนเมื่อความกว้างของการแสดงผลเปลี่ยนแปลงตามการวางแนวของอุปกรณ์
TextView ที่ปรับเปลี่ยนตามอุปกรณ์
TextView จะตั้งค่าความกว้างให้เต็มพื้นที่ทั้งหมดที่ใช้ได้ (match_parent) และตั้งค่าความสูงให้เท่ากับพื้นที่ที่ข้อความที่อยู่ใน TextView ต้องการ (wrap_content) ซึ่งช่วยให้มุมมองปรับให้เข้ากับขนาดการแสดงผลและปริมาณข้อความต่างๆ ได้
หากใช้ LinearLayout คุณ
ยังขยายมุมมองย่อยตาม น้ำหนัก
ของเลย์เอาต์ ได้เพื่อให้มุมมองเติมพื้นที่ที่ใช้ได้ตามสัดส่วน อย่างไรก็ตาม การใช้น้ำหนักใน LinearLayout ที่ซ้อนกันกำหนดให้ระบบต้องทำการส่งผ่านเลย์เอาต์หลายครั้งเพื่อกำหนดขนาดของแต่ละมุมมอง ซึ่งจะทำให้ประสิทธิภาพของ UI ช้าลง
ConstraintLayout สามารถสร้างเลย์เอาต์เกือบทั้งหมดที่
LinearLayout สร้างได้โดยไม่ส่งผลต่อประสิทธิภาพ ดังนั้น ให้แปลง
LinearLayout ที่ซ้อนกันเป็น
ConstraintLayout จากนั้นคุณ
จะ กำหนดเลย์เอาต์แบบถ่วงน้ำน้ำหนักด้วย Constraint
Chain ได้
การออกแบบแบบปรับขนาดได้
เลย์เอาต์ของแอปควรปรับเปลี่ยนตามขนาดการแสดงผลต่างๆ เสมอ อย่างไรก็ตาม แม้แต่เลย์เอาต์ที่ปรับเปลี่ยนตามอุปกรณ์ก็ไม่สามารถมอบประสบการณ์การใช้งานที่ดีที่สุดในอุปกรณ์ทุกเครื่องหรือการแสดงผลโหมดหลายหน้าต่าง เช่น UI ที่คุณออกแบบสำหรับโทรศัพท์อาจไม่มอบประสบการณ์การใช้งานที่เหมาะสมที่สุดในแท็บเล็ต การออกแบบแบบปรับขนาดได้มีเลย์เอาต์ทางเลือกที่ปรับให้เหมาะกับขนาดการแสดงผลต่างๆ
SlidingPaneLayout สำหรับ UI แบบรายละเอียดรายการ
โดยทั่วไปแล้ว UI แบบรายละเอียดรายการจะมอบประสบการณ์การใช้งานที่แตกต่างกันในหน้าจอขนาดต่างๆ ในหน้าจอขนาดใหญ่ บานหน้าต่างรายการและรายละเอียดมักจะอยู่ข้างกัน เมื่อมีการเลือกรายการในรายการ ข้อมูลรายการจะแสดงในบานหน้าต่างรายละเอียดโดยไม่เปลี่ยนแปลง UI ซึ่งบานหน้าต่างทั้งสองจะยังคงอยู่ข้างกัน อย่างไรก็ตาม ในหน้าจอขนาดเล็ก บานหน้าต่างทั้งสองจะแสดงแยกกัน โดยแต่ละบานหน้าต่างจะใช้พื้นที่แสดงผลทั้งหมด เมื่อมีการเลือกรายการในบานหน้าต่างรายการ บานหน้าต่างรายละเอียด (ที่มีข้อมูลของรายการที่เลือก) จะแทนที่บานหน้าต่างรายการ การนำทางย้อนกลับจะแทนที่บานหน้าต่างรายละเอียดด้วยรายการ
SlidingPaneLayout
จะจัดการตรรกะสำหรับการกำหนดว่าประสบการณ์การใช้งาน 2 แบบใดเหมาะสมกับขนาดหน้าต่างปัจจุบัน
<?xml version="1.0" encoding="utf-8"?>
<androidx.slidingpanelayout.widget.SlidingPaneLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="280dp"
android:layout_height="match_parent"
android:layout_gravity="start" />
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="300dp"
android:layout_height="match_parent"
android:layout_weight="1"
app:defaultNavHost="true"
app:navGraph="@navigation/item_navigation" />
</androidx.slidingpanelayout.widget.SlidingPaneLayout>
แอตทริบิวต์ layout_width และ layout_weight ของมุมมอง 2 รายการที่อยู่ใน SlidingPaneLayout จะกำหนดลักษณะการทำงานของ SlidingPaneLayout ในตัวอย่างนี้ หากหน้าต่างมีขนาดใหญ่พอ (กว้างอย่างน้อย 580dp) ที่จะแสดงมุมมองทั้งสอง บานหน้าต่างจะแสดงอยู่ข้างกัน แต่หากความกว้างของหน้าต่างน้อยกว่า 580dp บานหน้าต่างจะเลื่อนทับกันเพื่อใช้พื้นที่หน้าต่างแอปทั้งหมด
หากความกว้างของหน้าต่างมากกว่าความกว้างขั้นต่ำทั้งหมดที่ระบุ (580dp)
layout_weight คุณจะใช้น้ำหนักของเลย์เอาต์เพื่อปรับขนาดบานหน้าต่างทั้งสองตามสัดส่วนได้ ในตัวอย่างนี้ บานหน้าต่างรายการจะกว้าง 280dp เสมอเนื่องจากไม่มีน้ำหนัก
อย่างไรก็ตาม บานหน้าต่างรายละเอียดจะเติมพื้นที่แนวนอนที่มากกว่า 580dp เสมอเนื่องจากการตั้งค่า layout_weight ของมุมมอง
ทรัพยากรเลย์เอาต์ทางเลือก
คุณสามารถระบุเลย์เอาต์แบบปรับขนาดได้และเลย์เอาต์เฉพาะหน้าจอได้โดยการสร้างไดเรกทอรี res/layout/ เพิ่มเติมในซอร์สโค้ดของแอป สร้างไดเรกทอรีสำหรับการกำหนดค่าหน้าจอแต่ละรายการที่ต้องใช้เลย์เอาต์ที่แตกต่างกัน จากนั้นต่อท้ายตัวระบุการกำหนดค่าหน้าจอลงในชื่อไดเรกทอรี layout (เช่น
layout-w600dp สำหรับหน้าจอที่มีความกว้างที่ใช้ได้ 600dp)
ตัวระบุการกำหนดค่าแสดงถึงพื้นที่แสดงผลที่มองเห็นได้ซึ่ง UI ของแอปใช้ได้ ระบบจะพิจารณาการตกแต่งระบบ (เช่น แถบการนำทาง) และการเปลี่ยนแปลงการกำหนดค่าหน้าต่าง (เช่น โหมดหลายหน้าต่าง) เมื่อเลือกเลย์เอาต์สำหรับแอป
หากต้องการสร้างเลย์เอาต์ทางเลือกใน Android Studio โปรดดู ใช้เลย์เอาต์ที่แตกต่างกันเพื่อ เพิ่มประสิทธิภาพสำหรับหน้าจอต่างๆ ใน พัฒนา UI ด้วยมุมมอง
ตัวระบุความกว้างที่เล็กที่สุด
ตัวระบุขนาดหน้าจอ ความกว้างที่เล็กที่สุด ช่วยให้คุณระบุเลย์เอาต์ทางเลือก สำหรับการแสดงผลที่มีความกว้างขั้นต่ำที่วัดเป็น พิกเซลอิสระต่อความหนาแน่น (dp)
การอธิบายขนาดหน้าจอเป็นหน่วย dp ช่วยให้ Android สร้างเลย์เอาต์ที่ออกแบบมาสำหรับขนาดการแสดงผลที่เฉพาะเจาะจงได้โดยไม่ต้องกังวลเรื่องความหนาแน่นของพิกเซลที่แตกต่างกัน
ตัวอย่างเช่น คุณสามารถสร้างเลย์เอาต์ชื่อ main_activity ที่ปรับให้เหมาะกับโทรศัพท์และแท็บเล็ตได้โดยการสร้างไฟล์เวอร์ชันต่างๆ ในไดเรกทอรีต่างๆ ดังนี้
res/layout/main_activity.xml # For phones (smaller than 600dp smallest width) res/layout-sw600dp/main_activity.xml # For 7" tablets (600dp wide or wider)
ตัวระบุความกว้างที่เล็กที่สุดจะระบุด้านที่เล็กที่สุดของด้านทั้งสองด้านของการแสดงผล ไม่ว่าการวางแนวปัจจุบันของอุปกรณ์จะเป็นอย่างไร ดังนั้นจึงเป็นวิธีระบุขนาดการแสดงผลโดยรวมที่เลย์เอาต์ใช้ได้
ค่าความกว้างที่เล็กที่สุดอื่นๆ จะสอดคล้องกับขนาดหน้าจอทั่วไปดังนี้
- 320dp: หน้าจอโทรศัพท์ขนาดเล็ก (240x320 ldpi, 320x480 mdpi, 480x800 hdpi ฯลฯ)
- 480dp: หน้าจอโทรศัพท์ขนาดใหญ่ ~5" (480x800 mdpi)
- 600dp: แท็บเล็ต 7" (600x1024 mdpi)
- 720dp: แท็บเล็ต 10" (720x1280 mdpi, 800x1280 mdpi ฯลฯ)
รูปต่อไปนี้แสดงรายละเอียดเพิ่มเติมเกี่ยวกับความกว้าง dp ของหน้าจอต่างๆ ที่สอดคล้องกับขนาดและการวางแนวหน้าจอต่างๆ
ค่าสำหรับตัวระบุ ความกว้างที่เล็กที่สุด คือ dp เนื่องจากสิ่งที่สำคัญคือพื้นที่แสดงผลที่ใช้ได้หลังจากที่ระบบพิจารณาความหนาแน่นของพิกเซลแล้ว (ไม่ใช่ความละเอียดของพิกเซลดิบ)
ขนาดที่คุณระบุโดยใช้ตัวระบุทรัพยากร เช่น ความกว้างที่เล็กที่สุด ไม่ใช่ขนาดหน้าจอจริง แต่ขนาดจะระบุความกว้างหรือความสูงเป็นหน่วย dp ที่ หน้าต่างของแอปใช้ได้ ระบบ Android อาจใช้หน้าจอบางส่วนสำหรับ UI ของระบบ (เช่น แถบระบบที่ด้านล่างของหน้าจอหรือแถบสถานะที่ด้านบน) ดังนั้นหน้าจอบางส่วนอาจใช้ไม่ได้กับเลย์เอาต์ หากใช้แอปในโหมดหลายหน้าต่าง แอปจะมีสิทธิ์เข้าถึงเฉพาะขนาดของหน้าต่างที่มีแอปอยู่เท่านั้น เมื่อมีการปรับขนาดหน้าต่าง ระบบจะทริกเกอร์การเปลี่ยนแปลงการกำหนดค่าด้วยขนาดหน้าต่างใหม่ ซึ่งช่วยให้ระบบเลือกไฟล์เลย์เอาต์ที่เหมาะสมได้ ดังนั้นขนาดตัวระบุทรัพยากรที่คุณประกาศควรระบุเฉพาะพื้นที่ที่แอปต้องการเท่านั้น ระบบจะพิจารณาพื้นที่ที่ UI ของระบบใช้เมื่อจัดสรรพื้นที่สำหรับเลย์เอาต์
ตัวระบุความกว้างที่ใช้ได้
คุณอาจต้องการเปลี่ยนเลย์เอาต์ตามความกว้างหรือความสูงที่ใช้ได้แทนที่จะเปลี่ยนเลย์เอาต์ตามความกว้างที่เล็กที่สุดของการแสดงผล เช่น คุณอาจต้องการใช้เลย์เอาต์ 2 บานหน้าต่างเมื่อใดก็ตามที่หน้าจอมีความกว้างอย่างน้อย 600dp ซึ่งอาจเปลี่ยนแปลงไปตามการวางแนวของอุปกรณ์ว่าเป็นแนวนอนหรือแนวตั้ง ในกรณีดังกล่าว คุณควรใช้ตัวระบุ ความกว้างที่ใช้ได้ ดังนี้
res/layout/main_activity.xml # For phones (smaller than 600dp available width)
res/layout-w600dp/main_activity.xml # For 7" tablets or any screen with 600dp available width
# (possibly landscape phones)
หากความสูงที่ใช้ได้เป็นสิ่งที่แอปของคุณกังวล คุณสามารถใช้ตัวระบุ ความสูงที่ใช้ได้ ได้ เช่น layout-h600dp สำหรับหน้าจอที่มีความสูงอย่างน้อย 600dp
ตัวระบุการวางแนว
แม้ว่าคุณจะรองรับขนาดต่างๆ ได้โดยใช้ตัวระบุ ความกว้างที่เล็กที่สุด และ ความกว้างที่ใช้ได้ ร่วมกันเท่านั้น แต่คุณอาจต้องการเปลี่ยนประสบการณ์การใช้งานเมื่อผู้ใช้สลับระหว่างการวางแนวแนวตั้งและแนวนอน
คุณสามารถเพิ่มตัวระบุ port หรือ land ลงในชื่อไดเรกทอรีเลย์เอาต์ได้ เพียงตรวจสอบว่าตัวระบุการวางแนวอยู่หลังตัวระบุขนาด
เช่น
res/layout/main_activity.xml # For phones res/layout-land/main_activity.xml # For phones in landscape res/layout-sw600dp/main_activity.xml # For 7" tablets res/layout-sw600dp-land/main_activity.xml # For 7" tablets in landscape
ดูข้อมูลเพิ่มเติมเกี่ยวกับตัวระบุการกำหนดค่าหน้าจอทั้งหมดได้ที่ ภาพรวมของทรัพยากรแอป
คลาสขนาดหน้าต่าง
คลาสขนาดหน้าต่างคือเบรกพอยท์วิวพอร์ตที่ช่วยคุณสร้างเลย์เอาต์แบบปรับขนาดได้ เบรกพอยท์จะระบุพื้นที่แสดงผลที่แอปใช้ได้เป็น กะทัดรัด ปานกลาง หรือ ขยาย ความกว้างและความสูงจะระบุแยกกัน ดังนั้นแอปของคุณจะมีคลาสขนาดหน้าต่างสำหรับความกว้างและคลาสขนาดหน้าต่างสำหรับความสูงเสมอ
หากต้องการใช้เลย์เอาต์แบบปรับขนาดได้โดยทางโปรแกรม ให้ทำดังนี้
- สร้างทรัพยากรเลย์เอาต์ตามเบรกพอยท์คลาสขนาดหน้าต่าง
- คำนวณคลาสขนาดหน้าต่างความกว้างและความสูงของแอปโดยใช้
WindowSizeClass#compute()ฟังก์ชันจากไลบรารีJetpack WindowManager - ขยายทรัพยากรเลย์เอาต์สำหรับคลาสขนาดหน้าต่างปัจจุบัน
ดูข้อมูลเพิ่มเติมได้ที่ คลาส ขนาดหน้าต่าง
คอมโพเนนต์ UI แบบแยกส่วนโดยใช้ Fragment
เมื่อออกแบบแอปสำหรับขนาดการแสดงผลหลายขนาด ให้ใช้ Fragment เพื่อแยกตรรกะ UI ออกเป็นคอมโพเนนต์ที่แยกกัน เพื่อให้แน่ใจว่าคุณจะไม่ทำซ้ำลักษณะการทำงานของ UI ในกิจกรรมต่างๆ โดยไม่จำเป็น จากนั้นคุณจะรวม Fragment เพื่อสร้างเลย์เอาต์หลายบานหน้าต่างในหน้าจอขนาดใหญ่ หรือวาง Fragment ในกิจกรรมที่แยกกันในหน้าจอขนาดเล็กก็ได้
ตัวอย่างเช่น รูปแบบรายการ-รายละเอียด (ดู SlidingPaneLayout ด้านบน) สามารถใช้ Fragment หนึ่งรายการที่มีรายการและอีก Fragment หนึ่งที่มีรายละเอียดรายการ ได้ ในหน้าจอขนาดใหญ่ Fragment จะแสดงอยู่ข้างกัน ส่วนในหน้าจอขนาดเล็กจะแสดงแยกกันโดยเติมเต็มหน้าจอ
ดูข้อมูลเพิ่มเติมได้ที่ภาพรวมของ Fragment
การฝังกิจกรรม
หากแอปของคุณประกอบด้วยกิจกรรมหลายรายการ การฝังกิจกรรมจะช่วยให้คุณสร้าง UI แบบปรับขนาดได้ง่ายๆ
การฝังกิจกรรมจะแสดงกิจกรรมหลายรายการหรือกิจกรรมเดียวกันหลายอินสแตนซ์พร้อมกันในหน้าต่างงานของแอปพลิเคชัน ในหน้าจอขนาดใหญ่ กิจกรรมจะแสดงอยู่ข้างกัน ส่วนในหน้าจอขนาดเล็กจะซ้อนกัน
คุณกำหนดวิธีที่แอปแสดงกิจกรรมโดยการสร้างไฟล์การกำหนดค่า XML ซึ่งระบบจะใช้เพื่อกำหนดการนำเสนอที่เหมาะสมตามขนาดการแสดงผล หรือจะเรียกใช้ Jetpack WindowManager API ก็ได้
การฝังกิจกรรมรองรับการเปลี่ยนแปลงการวางแนวของอุปกรณ์และอุปกรณ์พับได้ โดยจะซ้อนและยกเลิกการซ้อนกิจกรรมเมื่ออุปกรณ์หมุนหรือพับและกางออก
ดูข้อมูลเพิ่มเติมได้ที่การฝังกิจกรรม
ขนาดหน้าจอและสัดส่วนภาพ
ทดสอบแอปในหน้าจอขนาดและสัดส่วนภาพต่างๆ เพื่อให้แน่ใจว่า UI จะปรับขนาดอย่างถูกต้อง
Android 10 (ระดับ API 29) ขึ้นไปรองรับสัดส่วนภาพที่หลากหลาย รูปแบบของอุปกรณ์พับได้อาจแตกต่างกันไปตั้งแต่หน้าจอสูงและแคบ เช่น 21:9 เมื่อพับ ไปจนถึงสัดส่วนภาพจัตุรัส 1:1 เมื่อกางออก
ทดสอบแอปกับสัดส่วนภาพหน้าจอต่อไปนี้ให้มากที่สุดเท่าที่จะทำได้เพื่อให้แน่ใจว่าแอปจะเข้ากันได้กับอุปกรณ์ต่างๆ มากที่สุด
หากคุณไม่มีสิทธิ์เข้าถึงอุปกรณ์สำหรับหน้าจอขนาดต่างๆ ที่ต้องการ ทดสอบ คุณสามารถใช้ โปรแกรมจำลองของ Android เพื่อจำลอง หน้าจอเกือบทุกขนาดได้
หากต้องการทดสอบในอุปกรณ์จริงแต่ไม่มีอุปกรณ์ คุณสามารถใช้ Firebase Test Lab เพื่อเข้าถึง อุปกรณ์ในศูนย์ข้อมูล Google ได้
แหล่งข้อมูลเพิ่มเติม
- Material Design - ทำความเข้าใจเลย์เอาต์