จำกัดการวางแนวของแอปในโทรศัพท์ แต่ไม่ได้จำกัดในอุปกรณ์ที่มีหน้าจอขนาดใหญ่

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

คุณจะทำอย่างไรหากต้องการจำกัดแอปให้แสดงในแนวนอนบนหน้าจอขนาดเล็ก แต่เปิดใช้แนวนอนบนหน้าจอขนาดใหญ่

คู่มือนี้เป็นมาตรการชั่วคราวจนกว่าคุณจะปรับปรุงแอปให้รองรับการกำหนดค่าอุปกรณ์ทั้งหมดได้อย่างเต็มรูปแบบ

ผลลัพธ์

แอปจะยังคงอยู่ในแนวตั้งบนหน้าจอขนาดเล็กไม่ว่าจะหมุนอุปกรณ์อย่างไรก็ตาม ในหน้าจอขนาดใหญ่ แอปจะรองรับการวางแนวแนวนอนและแนวตั้ง

จัดการการวางแนวของแอป

หากต้องการเปิดใช้การวางแนวแนวนอนบนหน้าจอขนาดใหญ่ ให้ตั้งค่าไฟล์ Manifest ของแอปให้ จัดการการเปลี่ยนแปลงการวางแนวโดยค่าเริ่มต้น กำหนดขนาดหน้าต่างแอป ที่รันไทม์ หากหน้าต่างแอปมีขนาดเล็ก ให้จำกัดการวางแนวของแอปโดยการลบล้าง การตั้งค่าการวางแนวในไฟล์ Manifest

1. ระบุการตั้งค่าการวางแนวในไฟล์ Manifest ของแอป

คุณสามารถหลีกเลี่ยงการประกาศองค์ประกอบ screenOrientation ของไฟล์ Manifest ของแอป (ในกรณีนี้ การวางแนวจะเป็นค่าเริ่มต้นเป็น unspecified) หรือตั้งค่าการวางแนวหน้าจอเป็น fullUser หากผู้ใช้ไม่ได้ล็อกการหมุนตามเซ็นเซอร์ แอปของคุณจะรองรับการวางแนวอุปกรณ์ทั้งหมด

<activity
    android:name=".MyActivity"
    android:screenOrientation="fullUser">

ความแตกต่างระหว่าง unspecified กับ fullUser อาจดูเล็กน้อยแต่มีความสำคัญ หากคุณไม่ประกาศค่า screenOrientation ระบบจะเลือกการวางแนว และนโยบายที่ระบบใช้เพื่อกำหนดการวางแนวอาจแตกต่างกันไปในแต่ละอุปกรณ์ ในทางกลับกัน การระบุ fullUser จะตรงกับลักษณะการทำงานที่ผู้ใช้กำหนดไว้สำหรับอุปกรณ์มากกว่า กล่าวคือ หากผู้ใช้ล็อกการหมุนตามเซ็นเซอร์ แอปจะทำตามค่ากำหนดของผู้ใช้ ไม่เช่นนั้น ระบบจะอนุญาตการวางแนวหน้าจอที่เป็นไปได้ทั้ง 4 แบบ (แนวตั้ง แนวนอน แนวตั้งกลับ หรือแนวนอนกลับ) ดู screenOrientation

2. กำหนดขนาดหน้าจอ

เมื่อตั้งค่าไฟล์ Manifest ให้รองรับการวางแนวทั้งหมดที่ผู้ใช้ได้รับอนุญาตแล้ว คุณจะ ระบุการวางแนวแอปแบบเป็นโปรแกรมตามขนาดหน้าจอได้

เพิ่มไลบรารี Jetpack WindowManager ลงในไฟล์ build.gradle หรือ build.gradle.kts ของโมดูล

Kotlin

implementation("androidx.window:window:version")
implementation("androidx.window:window-core:version")

Groovy

implementation 'androidx.window:window:version'
implementation 'androidx.window:window-core:version'

ใช้เมธอด Jetpack WindowManager WindowMetricsCalculator#computeMaximumWindowMetrics() เพื่อรับ ขนาดหน้าจออุปกรณ์เป็นออบเจ็กต์ WindowMetrics คุณสามารถ เปรียบเทียบเมตริกหน้าต่างกับคลาสขนาดหน้าต่างเพื่อตัดสินใจว่าจะจำกัดการวางแนวเมื่อใด

คลาสขนาดหน้าต่างจะระบุเบรกพอยต์ระหว่างหน้าจอขนาดเล็กและขนาดใหญ่

ใช้จุดพัก WindowWidthSizeClass#COMPACT และ WindowHeightSizeClass#COMPACT เพื่อกำหนดขนาดหน้าจอ

Kotlin

/** Determines whether the device has a compact screen. **/
fun compactScreen() : Boolean {
    val metrics = WindowMetricsCalculator.getOrCreate().computeMaximumWindowMetrics(this)
    val width = metrics.bounds.width()
    val height = metrics.bounds.height()
    val density = resources.displayMetrics.density
    val windowSizeClass = WindowSizeClass.compute(width/density, height/density)

    return windowSizeClass.windowWidthSizeClass == WindowWidthSizeClass.COMPACT ||
        windowSizeClass.windowHeightSizeClass == WindowHeightSizeClass.COMPACT
}

Java

/** Determines whether the device has a compact screen. **/
private boolean compactScreen() {
    WindowMetrics metrics = WindowMetricsCalculator.getOrCreate().computeMaximumWindowMetrics(this);
    int width = metrics.getBounds().width();
    int height = metrics.getBounds().height();
    float density = getResources().getDisplayMetrics().density;
    WindowSizeClass windowSizeClass = WindowSizeClass.compute(width/density, height/density);
    return windowSizeClass.getWindowWidthSizeClass() == WindowWidthSizeClass.COMPACT ||
                windowSizeClass.getWindowHeightSizeClass() == WindowHeightSizeClass.COMPACT;
}
    หมายเหตุ:
  • ตัวอย่างจะได้รับการติดตั้งใช้งานเป็นเมธอดของกิจกรรม ดังนั้นระบบจึงยกเลิกการอ้างอิงกิจกรรมเป็น this ในอาร์กิวเมนต์ของ computeMaximumWindowMetrics()
  • เราใช้วิธี computeMaximumWindowMetrics() แทน computeCurrentWindowMetrics() เนื่องจากแอปสามารถเปิดใช้ในโหมดหลายหน้าต่างได้ ซึ่งจะไม่สนใจการตั้งค่าการวางแนวหน้าจอ ไม่มีเหตุผลที่จะกำหนดขนาดหน้าต่างแอปและลบล้างการตั้งค่าการวางแนว เว้นแต่หน้าต่างแอปจะเป็นทั้งหน้าจอของอุปกรณ์

ดูWindowManager เพื่อดูวิธีการประกาศการอ้างอิงเพื่อให้เมธอด computeMaximumWindowMetrics() พร้อมใช้งานในแอป

3. ลบล้างการตั้งค่าไฟล์ Manifest ของแอป

เมื่อพิจารณาแล้วว่าอุปกรณ์มีขนาดหน้าจอแบบกะทัดรัด คุณสามารถเรียกใช้ Activity#setRequestedOrientation() เพื่อลบล้างการตั้งค่า screenOrientation ของไฟล์ Manifest ได้

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    requestedOrientation = if (compactScreen())
        ActivityInfo.SCREEN_ORIENTATION_PORTRAIT else
        ActivityInfo.SCREEN_ORIENTATION_FULL_USER
    ...
    // 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)
            requestedOrientation = if (compactScreen())
                ActivityInfo.SCREEN_ORIENTATION_PORTRAIT else
                ActivityInfo.SCREEN_ORIENTATION_FULL_USER
        }
    })
}

Java

@Override
protected void onCreate(Bundle savedInstance) {
    super.onCreate(savedInstanceState);
    if (compactScreen()) {
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
    } else {
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_USER);
    }
    ...
    // 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);
            if (compactScreen()) {
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
            } else {
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_USER);
            }
        }
    });
}

การเพิ่มตรรกะลงในเมธอด onCreate() และ View.onConfigurationChanged() จะช่วยให้คุณได้รับเมตริกหน้าต่างสูงสุดและลบล้างการตั้งค่า การวางแนวได้ทุกเมื่อที่กิจกรรมมีการปรับขนาดหรือย้ายระหว่างจอแสดงผล เช่น หลังจากหมุนอุปกรณ์ หรือเมื่อพับหรือกางอุปกรณ์พับได้ ดูข้อมูลเพิ่มเติมเกี่ยวกับเวลาที่การเปลี่ยนแปลงการกำหนดค่าเกิดขึ้นและเวลาที่การเปลี่ยนแปลงดังกล่าวทำให้เกิดการสร้างกิจกรรมใหม่ได้ที่จัดการการเปลี่ยนแปลงการกำหนดค่า

ข้อมูลสำคัญ

  • screenOrientation: การตั้งค่าไฟล์ Manifest ของแอปที่ช่วยให้คุณระบุได้ วิธีที่แอปตอบสนองต่อการเปลี่ยนแปลงการวางแนวอุปกรณ์
  • Jetpack WindowManager: ชุดไลบรารีที่ช่วยให้คุณกำหนดขนาดและสัดส่วนของหน้าต่างแอปได้ โดยมีความเข้ากันได้แบบย้อนหลังกับ API ระดับ 14
  • Activity#setRequestedOrientation(): วิธีที่คุณสามารถเปลี่ยน การวางแนวแอปในขณะรันไทม์

คอลเล็กชันที่มีคำแนะนำนี้

คู่มือนี้เป็นส่วนหนึ่งของคอลเล็กชันคู่มือฉบับย่อที่คัดสรรมาแล้ว ซึ่งครอบคลุมเป้าหมายการพัฒนา Android ในวงกว้าง

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

มีคำถามหรือความคิดเห็น

ไปที่หน้าคำถามที่พบบ่อยเพื่อดูคำแนะนำแบบรวดเร็ว หรือติดต่อเราเพื่อบอกความคิดเห็นของคุณ