ใช้คลาสขนาดหน้าต่าง

ลองใช้วิธีเขียน
Jetpack Compose เป็นชุดเครื่องมือ UI ที่แนะนําสําหรับ Android ดูวิธีใช้คลาสขนาดหน้าต่างใน Compose

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

คลาสขนาดหน้าต่างจะจัดหมวดหมู่พื้นที่แสดงผลที่แอปของคุณใช้ได้เป็น กะทัดรัด ปานกลาง ขยาย ใหญ่ หรือใหญ่พิเศษ ความกว้างและความสูงที่ใช้ได้จะได้รับการจัดประเภทแยกกัน ดังนั้นในทุกช่วงเวลา แอปจะมี Window Size Class อยู่ 2 รายการ ได้แก่ รายการหนึ่งสำหรับความกว้างและอีกรายการหนึ่งสำหรับความสูง โดยปกติแล้ว ความกว้างที่ใช้ได้จะมีความสำคัญมากกว่าความสูงที่ใช้ได้เนื่องจากการเลื่อนแนวตั้งมีอยู่ทุกหนทุกแห่ง ดังนั้นคลาสขนาดหน้าต่างความกว้างจึงน่าจะเกี่ยวข้องกับ UI ของแอปมากกว่า

รูปที่ 1 การแสดงคลาสขนาดหน้าต่างตามความกว้าง
รูปที่ 2 การแสดงคลาสขนาดหน้าต่างตามความสูง

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

คลาสขนาด เบรกพอยท์ การแสดงอุปกรณ์
ความกว้างแบบกะทัดรัด width < 600dp 99.96% ของโทรศัพท์ในแนวตั้ง
ความกว้างปานกลาง 600dp ≤ ความกว้าง < 840dp 93.73% ของแท็บเล็ตในโหมดแนวตั้ง

จอแสดงผลด้านในขนาดใหญ่ส่วนใหญ่ในโหมดแนวตั้ง

ความกว้างที่ขยายออก 840dp ≤ ความกว้าง < 1200dp 97.22% ของแท็บเล็ตในแนวนอน

หน้าจอด้านในขนาดใหญ่ส่วนใหญ่ที่กางออกในแนวนอนจะมี ความกว้างที่ขยายออกอย่างน้อย

ความกว้างมาก 1200dp ≤ ความกว้าง < 1600dp จอแสดงผลของแท็บเล็ตขนาดใหญ่
ความกว้างใหญ่พิเศษ width ≥ 1600dp โฆษณาบนเดสก์ท็อป
ความสูงแบบกะทัดรัด height < 480dp 99.78% ของโทรศัพท์อยู่ในแนวนอน
ความสูงปานกลาง 480dp ≤ ความสูง < 900dp 96.56% ของแท็บเล็ตในแนวนอน

97.59% ของโทรศัพท์ในแนวตั้ง

ความสูงที่ขยายออก height ≥ 900dp 94.25% ของแท็บเล็ตในโหมดแนวตั้ง

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

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

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

Window Size Classes จะแมปกับเบรกพอยท์แบบกะทัดรัด ปานกลาง และขยายใน คำแนะนำเกี่ยวกับเลย์เอาต์ของ Material Design ใช้คลาสขนาดหน้าต่างเพื่อทำการตัดสินใจเกี่ยวกับเลย์เอาต์แอปพลิเคชันระดับสูง เช่น การตัดสินใจว่าจะใช้เลย์เอาต์ Canonical ที่เฉพาะเจาะจงเพื่อใช้ประโยชน์จาก พื้นที่หน้าจอเพิ่มเติมหรือไม่

คุณสามารถคำนวณ WindowSizeClass โดยใช้ WindowSizeClass#compute() ของ Jetpack ไลบรารี WindowManager ตัวอย่างต่อไปนี้ แสดงวิธีคำนวณคลาสขนาดหน้าต่างและรับการอัปเดตเมื่อใดก็ตามที่ การเปลี่ยนแปลงคลาสขนาดหน้าต่าง:

Kotlin

class MainActivity : Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // ...

        // Replace with a known container that you can safely add a
        // view to where the view won't affect the layout and the view
        // won't be replaced.
        val container: ViewGroup = binding.container

        // Add a utility view to the container to hook into
        // View.onConfigurationChanged(). This is required for all
        // activities, even those that don't handle configuration
        // changes. You can't use Activity.onConfigurationChanged(),
        // since there are situations where that won't be called when
        // the configuration changes. View.onConfigurationChanged() is
        // called in those scenarios.
        container.addView(object : View(this) {
            override fun onConfigurationChanged(newConfig: Configuration?) {
                super.onConfigurationChanged(newConfig)
                computeWindowSizeClasses()
            }
        })

        computeWindowSizeClasses()
    }

    private fun computeWindowSizeClasses() {
        val metrics = WindowMetricsCalculator.getOrCreate().computeCurrentWindowMetrics(this)
        val width = metrics.bounds.width()
        val height = metrics.bounds.height()
        val density = resources.displayMetrics.density
        val windowSizeClass = WindowSizeClass.compute(width/density, height/density)
        // COMPACT, MEDIUM, or EXPANDED
        val widthWindowSizeClass = windowSizeClass.windowWidthSizeClass
        // COMPACT, MEDIUM, or EXPANDED
        val heightWindowSizeClass = windowSizeClass.windowHeightSizeClass

        // Use widthWindowSizeClass and heightWindowSizeClass.
    }
}

Java

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // ...

        // Replace with a known container that you can safely add a
        // view to where the view won't affect the layout and the view
        // won't be replaced.
        ViewGroup container = binding.container;

        // Add a utility view to the container to hook into
        // View.onConfigurationChanged(). This is required for all
        // activities, even those that don't handle configuration
        // changes. You can't use Activity.onConfigurationChanged(),
        // since there are situations where that won't be called when
        // the configuration changes. View.onConfigurationChanged() is
        // called in those scenarios.
        container.addView(new View(this) {
            @Override
            protected void onConfigurationChanged(Configuration newConfig) {
                super.onConfigurationChanged(newConfig);
                computeWindowSizeClasses();
            }
        });

        computeWindowSizeClasses();
    }

    private void computeWindowSizeClasses() {
        WindowMetrics metrics = WindowMetricsCalculator.getOrCreate()
                .computeCurrentWindowMetrics(this);

        int width = metrics.getBounds().width
        int height = metrics.getBounds().height()
        float density = getResources().getDisplayMetrics().density;
        WindowSizeClass windowSizeClass = WindowSizeClass.compute(width/density, height/density)
        // COMPACT, MEDIUM, or EXPANDED
        WindowWidthSizeClass widthWindowSizeClass = windowSizeClass.getWindowWidthSizeClass()
        // COMPACT, MEDIUM, or EXPANDED
        WindowHeightSizeClass heightWindowSizeClass = windowSizeClass.getWindowHeightSizeClass()

        // Use widthWindowSizeClass and heightWindowSizeClass.
    }
}

ทดสอบคลาสขนาดหน้าต่าง

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

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

ขั้นตอนถัดไป

ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีใช้คลาสขนาดหน้าต่างเพื่อสร้างเลย์เอาต์ที่ปรับเปลี่ยนตามพื้นที่โฆษณา/ปรับตาม ได้ที่หัวข้อต่อไปนี้

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