限制手機螢幕的方向,而不限制大螢幕裝置的方向

您的應用程式在縱向模式作業出色,因此您已將應用程式設為僅限縱向顯示。然而您卻發現,在橫向的大螢幕上還能完成更多操作。

那麼,這兩者要如何兼顧呢?是否可以限制應用程式在小螢幕上以直向模式顯示,但在大螢幕上啟用橫向模式?

您可使用這份指南改善應用程式,直到能完整支援所有裝置設定為止。

管理應用程式方向

如要在大螢幕上啟用橫向模式,請將應用程式資訊清單設為預設處理螢幕方向變更。在執行階段中,決定應用程式視窗大小。如果應用程式視窗太小,請覆寫資訊清單方向設定,以限制應用程式的螢幕方向。

1. 指定應用程式資訊清單中的方向設定

您可以選擇避免宣告應用程式資訊清單的 screenOrientation 元素 (這種情況下,螢幕方向預設為 unspecified),或是將螢幕方向設為 fullUser。如果使用者尚未鎖定以感應器為基礎的旋轉方式,您的應用程式將支援所有的裝置螢幕方向。

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

unspecifiedfullUser 之間的差異雖然細微,但很重要。如果您未宣告 screenOrientation 值,系統會選擇螢幕方向,而系統用來定義螢幕方向的政策也會因裝置而異。另一方面,指定 fullUser 會更貼近使用者為裝置定義的行為:如果使用者已鎖定感應器旋轉功能,應用程式會遵循使用者偏好設定;否則,系統會允許使用四種可能的螢幕方向 (直向、橫向、反向直向或反向橫向)。請參閱「screenOrientation」。

2. 決定螢幕大小

在資訊清單中設定支援所有使用者允許的方向後,您就可以根據螢幕尺寸,以程式輔助的方式指定應用程式方向。

Jetpack WindowManager 程式庫新增至模組的 build.gradlebuild.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 物件的裝置螢幕大小。您可以將視窗指標與視窗大小類別進行比較,以決定限制方向的時機。

Windows 大小類別提供小螢幕與大螢幕之間的中斷點。

請使用 WindowWidthSizeClass#COMPACTWindowHeightSizeClass#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;
}
    注意:
  • 這些範例是以活動的方法導入;因此,活動在 computeMaximumWindowMetrics() 引數中會被解除參照為 this
  • 使用 computeMaximumWindowMetrics() 方法代替 computeCurrentWindowMetrics(),因為應用程式可以透過多視窗模式啟動,而忽略螢幕方向設定。除非應用程式視窗即為整個裝置畫面,否則您無法判定應用程式視窗大小及覆寫方向設定。

請參閱「WindowManager」的操作說明,瞭解如何宣告依附元件,以便在應用程式中提供 computeMaximumWindowMetrics() 方法。

3. 覆寫應用程式資訊清單設定

如果您確定裝置螢幕為小尺寸,可以呼叫 Activity#setRequestedOrientation() 以覆寫資訊清單的 screenOrientation 設定:

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() 方法中,即可在每次調整活動大小,或活動在螢幕間移動時 (例如裝置旋轉,或摺疊式裝置摺疊/展開後),取得最大視窗指標並覆寫螢幕方向設定。如要進一步瞭解發生設定變更的時間,以及導致活動重新建立的時間,請參閱「處理設定變更」。

重點

結果

現在即使裝置旋轉時,您的應用程式仍應在小螢幕上以直向顯示。在大螢幕上,應用程式應支援橫向和直向螢幕模式。

包含此指南的集合

本指南是精選的快速指南系列之一,涵蓋更廣泛的 Android 開發目標:

讓應用程式支援平板電腦、折疊式裝置和 ChromeOS 裝置的最佳使用者體驗。

有問題或意見回饋嗎?

請前往常見問題頁面,瞭解快速指南或與我們聯絡,分享您的想法。