2023 Android folding screen adaptation details, it's time to light up new skills

Since Samsung released the first (not counting Royole) Galaxy Z Fold in 2019, Android manufacturers have followed up their foldable solutions one after another. After that, the folding screen mobile phone market has maintained rapid growth. For example, in the first half of 2023, the overall The sales volume was 2.27 million units, a year-on-year increase of 102.0%.

Although compared with the overall mobile phone shipments of 130 million units in the first half of the year, it can only be regarded as a fraction, but it is undeniable that the probability of developers’ apps encountering foldable mobile phones is not low, especially these users are likely to be “high-value” users .

So starting from 2023, folding screen adaptation will gradually become one of Android's mainstream KPIs, so what happens if it doesn't match? If it is adapted, by what means ? This article will take you in-depth understanding of this topic.

⚠️This article is super long and can be saved for emergencies.

Letterboxing mode

First of all, if it is not suitable, your application will most likely ( not necessarily ) be displayed in Letterboxing mode, and you may see the App exist as shown in the figure below, that is, when the aspect ratio of the application and the screen The app may open in Letterbox mode when the scale is not compatible .

Generally, the App locks the rotation direction and adopts the non-resizable size.

Of course, whether to enter the Letterboxing mode is related to the TargetSDK version, App configuration and screen resolution , and the presentation of the Letterboxing mode on different OS versions may also be different, for example:

  • Android 12 (API 31) began to introduce Letterboxing enhancements, which can be configured and supported by mobile phone manufacturers:

    • Rounded corners: Windows support rounded corners
    • System bar transparency: The status bar and navigation bar covering the app support translucency
    • Configurable aspect ratio: The aspect ratio of the app can be adjusted to improve the appearance of the app
  • 12L (API 32) added:

    • Configurable position: On large screens, device manufacturers can place apps on the left or right side of the display.
    • Restart button: Device manufacturers can give a new look to the restart button in size compatibility mode. (The size compatibility mode can make the width or height of the App fill the screen as much as possible)

    When the system determines that the display of Letterboxing can be improved by rescaling the application to fill the display window, Android will put the App in size compatibility mode, at this time the system will display a restart control, and will recreate the App process, recreate the Activity and redraw after confirmation Adapt.

  • Android 13 (API 33) adds a user-guided prompt dialog:

So when do you go into letterboxing mode? Generally, it can be simply understood as:

  • android:resizeableActivity=false When the aspect ratio declared by the application below is not compatible with the container (for example, the screen width exceeds android:maxAspectRatio).
  • setIgnoreOrientationRequest(true)After lowering the system settings to ignore the screen orientation, open the forced portrait interface in landscape orientation.

The core point here is actually that resizeableActivityit is used to declare whether the system can adjust the size of the App to adapt to screens of different sizes. In fact, strictly speaking resizeableActivity, it does not necessarily cause the application to enter the Letterboxing mode , which is also related to the API version:

  • Split screen mode configuration was introduced in Android 7.0 (API 24) resizeableActivity.
  • On Android 11 (API 30) and lower versions, it is used to configure whether the App supports multi-window mode. If false, it does not support it and enters Letterboxing mode.
  • On Android 12 (API 31) and higher versions, no matter resizeableActivitywhat is set, the App will support multi-window mode on large screens (sw >= 600dp), so it is only used to specify whether the App supports small screens (sw < 600dp) multi-window mode.

sw >= 600dpIt can be simply understood that the absolute width of your screen is greater than 600dp

Then some people said, what if I use it on Android 12 android:resizeableActivity=false and nothing fits? I can only say, "There is a certain probability" that it will crash directly as shown in the figure below .

Does that mean that if I don't use a higher version of TargetSDK, then I don't need to work on it?

ActivityNot quite, at least you need to do some simple configuration on your App or , because as early as Android 7.0 (API 24), resizeableActivitythe default value of is changed to true .

So if you don't want to adapt to the large-screen mode UI, but want to enter the Letterboxing mode, you still need to manually configure in the AndroidManifest applicationor the corresponding configuration .Activityandroid:resizeableActivity="false"

In addition, the display mode of Letterboxing mode is maxAspectRatio also related to . When the screen ratio exceeds , maxAspectRatioit will be filled with black borders. Generally, the official recommendation is to set maxAspectRatio to 2.4 (12 : 5), and the configuration method is also related to API Level:

  • Android 8.0 and above can be android:maxAspectRatioconfigured by

    <activity android:name=".MainActivity"
              android:maxAspectRatio="2.4" /> 
    
  • Android 8.0 and below can be meta-data android.max_aspectconfigured by

    <meta-data android:name="android.max_aspect" android:value="2.4" /> 
    

PS: If resizeableActivityit is true, maxAspectRatioit will not take effect.

As shown in the picture, the restart button of Android 12L (API 32) mentioned earlier can make the App end adapt to the screen as much as possible and reduce the black border.

Another point is that when the folding screen is unfolded and closed, the system may destroy and recreate the entire Activityandroid:configChanges screen when the screen changes , so we need to configure to prevent restarting :

android:configChanges="screenLayout|smallestScreenSize|screenSize"

Finallysupports_size_changes , it should be noted that if you do not want to support multi-window mode, but you may be forced to enter multi-window mode due to the system, and then you do not want to be restarted every time, you can configure supports_size_changesto ensure the continuity of operation.

<meta-data
    android:name="android.supports_size_changes" android:value="true" />

So here is a brief summary:

  • When the aspect ratio of the app is not compatible with its screen ratio, the App will enter Letterboxing mode when the rotation direction and size are locked

  • resizeableActivityThe effect mainly depends on the TargetSDK version, Android 12 (API 31) and higher versions may still enter the split-screen mode

  • maxAspectRatioThe role mainly depends onresizeableActivity

  • Configure android:configChangesand supports_size_changesprevent restarts Activityto ensure continuity

Official adaptation support

The next step is to introduce the adaptation scheme. First, let’s look at this picture. In fact, the official has defined usage suggestions for us according to the usage scenarios. The key information is:

  • Compose
  • Activity Embedding
  • SlidingPaneLayout

In addition, the window size level specification is set in the official screen size matching , for example:

  • Compact : common mobile devices, width < 600dp
  • Medium : Vertical screen for folding screen or tablet, 600dp < width < 840dp
  • Expanded : Expanded screen, tablet or tablet etc., width > 840dp

Of course, there are judgments based on height, but most apps can build responsive UI by only considering the width window size category ,

Compose

In fact, Compose does not need to say much. Responsive layout itself has inherent advantages in adapting to folding screens. With the current screen parameters provided by Jetpack WindowManager API, it can flexibly achieve different UI effects.

For example, Compose can use material3-window-size-classthe library, and then use to calculateWindowSizeClass()calculate the current window'sWindowSizeClass , thereby changing the layout of the UI:

import androidx.activity.compose.setContent
import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass

class MyActivity : ComponentActivity() {
    
    
    override fun onCreate(savedInstanceState: Bundle?) {
    
    
        super.onCreate(savedInstanceState)
        setContent {
    
    
            // Calculate the window size class for the activity's current window. If the window
            // size changes, for example when the device is rotated, the value returned by
            // calculateSizeClass will also change.
            val windowSizeClass = calculateWindowSizeClass(this)
            // Perform logic on the window size class to decide whether to use a nav rail.
            val useNavRail = windowSizeClass.widthSizeClass > WindowWidthSizeClass.Compact

            // MyScreen knows nothing about window size classes, and performs logic based on a
            // Boolean flag.
            MyScreen(useNavRail = useNavRail)
        }
    }
}

It can also be adapted via com.google.accompanist:accompanist-adaptivethe TwoPane .

TwoPaneTwo fixed slots are provided, and the default position of the two slots is TwoPaneStrategydriven by , which can decide to arrange the two slots horizontally or vertically, and configure the interval between them.

More can be found at: https://github.com/google/accompanist/tree/3810fe1182cf52c6660787ae3226dfb7f5ad372a/sample/src/main/java/com/google/accompanist/sample/adaptive

Compose can also use FlowLayout to adapt to folding changes in different scenarios . FlowLayout contains FlowRowand FlowColumn. When a row (or a column) cannot fit the content inside, it will automatically wrap. This is also very useful in the folding screen expansion and contraction scenarios.

You can also refer to the Demo of Compose adapting to the folding screen: https://github.com/android/compose-samples/tree/main/JetNews

Activity Embedding

Activity Embedding optimizes support for large screens by splitting windows between two Activities or two instances of the same Activity.

In theory, Activity Embedding does not require code refactoring, you can determine how the App displays its Activity (side by side or stacked) by creating an XML configuration file or making a Jetpack WindowManager API call .

Activity Embedding automatically maintains support for small screens by default. When the application is on a small screen device, Activities will be stacked one on top of the other; on a large screen, Activities will be displayed side by side.

On this basis, it can adapt to changes in device orientation and work seamlessly on foldable devices, stacking activities that are disassembled when the device is folded or unfolded, such as splitting and stacking in the chat list and chat detail pages.

Whether it is a large-screen device above Android 12L (API 32) or an earlier folding screen platform version, Jetpack WindowManager can help build an Activity Embedding multi-pane layout, which is based on multiple activities rather than fragments or view-based Layouts (such as SlidingPaneLayout) are the easiest way to provide a large-screen user experience without refactoring the source code .

A common example is the list-detail split screen. To ensure high-quality rendering, the system starts the list activity first, and then the app starts the detail activity immediately. The transition system waits until both activities are drawn before displaying them together. For the user, these two activities are started as one page.

Activity Embedding is currently supported on most large-screen devices running Android 12L (API 32) and higher.

Using Jetpack WindowManager to manage and configure Activity Embedding is actually quite flexible . XML rules can be pre-configured, or managed and configured directly through the API. For the rules defined in the XML configuration file, set the following properties:

  • splitRatio: Set the container scale. The value is a floating point number in the open range (0.0, 1.0).
  • splitLayoutDirection: Specifies how the split containers are laid out relative to each other. Values ​​include:
    • ltr: left to right
    • rtl: right to left
    • locale: ltr or rtlas determined by the locale setting

You can see that Jetpack WindowManager has very rich and flexible configuration support, instead of simply dividing the Activity evenly, you can even configure a blank Placeholder to display the placeholder.

To use Activity Embedding you need to depend on implementation 'androidx.window:window:xxx', then add this android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED property to the application manifest file <application>and set the value to true,

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <application>
        <property
            android:name="android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED"
            android:value="true" />
    </application>
</manifest>

Then you can create various Split Rules through xml or WindowManager API to create Split Rules and call them.

<!-- main_split_config.xml -->

<resources
    xmlns:window="http://schemas.android.com/apk/res-auto">

    <!-- Define a split for the named activities. -->
    <SplitPairRule
        window:splitRatio="0.33"
        window:splitLayoutDirection="locale"
        window:splitMinWidthDp="840"
        window:splitMaxAspectRatioInPortrait="alwaysAllow"
        window:finishPrimaryWithSecondary="never"
        window:finishSecondaryWithPrimary="always"
        window:clearTop="false">
        <SplitPairFilter
            window:primaryActivityName=".ListActivity"
            window:secondaryActivityName=".DetailActivity"/>
    </SplitPairRule>

    <!-- Specify a placeholder for the secondary container when content is
         not available. -->
    <SplitPlaceholderRule
        window:placeholderActivityName=".PlaceholderActivity"
        window:splitRatio="0.33"
        window:splitLayoutDirection="locale"
        window:splitMinWidthDp="840"
        window:splitMaxAspectRatioInPortrait="alwaysAllow"
        window:stickyPlaceholder="false">
        <ActivityFilter
            window:activityName=".ListActivity"/>
    </SplitPlaceholderRule>

    <!-- Define activities that should never be part of a split. Note: Takes
         precedence over other split rules for the activity named in the
         rule. -->
    <ActivityRule
        window:alwaysExpand="true">
        <ActivityFilter
            window:activityName=".ExpandedActivity"/>
    </ActivityRule>

</resources>

More can be seen at: https://developer.android.com/guide/topics/large-screens/activity-embedding

SlidingPaneLayout

SlidingPaneLayoutIt supports displaying two panes side by side on large-screen devices and automatically adjusts them. Only one pane is displayed on small-screen devices such as mobile phones, so it is also very practical in foldable scenarios.

SlidingPaneLayoutWhether to display the panes side by side is determined by the width of the two panes, for example:

  • If you measure and find that the list pane has a minimum size of 200dp, and the details pane requires 400dp, then the SlidingPaneLayouttwo panes will be automatically displayed side by side as long as the available width is not less than 600dp
  • If the total width of the subviews exceeds SlidingPaneLayoutthe available width in the , the views will overlap.

If the views do not overlap, SlidingPaneLayoutlayout parameters are supported for subviews layout_weightto specify how to divide the remaining space after the measurement is complete.

For example, in this example SlidingPaneLayout, the layout uses RecyclerView as its left pane, and FragmentContainerView as its main detail view to display the content in the left pane. In fact, it is similar to the UI of using TwoPane in Compose described above.

<!-- two_pane.xml -->
<androidx.slidingpanelayout.widget.SlidingPaneLayout
   xmlns:android="http://schemas.android.com/apk/res/android"
   android:id="@+id/sliding_pane_layout"
   android:layout_width="match_parent"
   android:layout_height="match_parent">

   <!-- The first child view becomes the left pane. When the combined
        desired width (expressed using android:layout_width) would
        not fit on-screen at once, the right pane is permitted to
        overlap the left. -->
   <androidx.recyclerview.widget.RecyclerView
             android:id="@+id/list_pane"
             android:layout_width="280dp"
             android:layout_height="match_parent"
             android:layout_gravity="start"/>

   <!-- The second child becomes the right (content) pane. In this
        example, android:layout_weight is used to expand this detail pane
        to consume leftover available space when the
        the entire window is wide enough to fit both the left and right pane.-->
   <androidx.fragment.app.FragmentContainerView
       android:id="@+id/detail_container"
       android:layout_width="300dp"
       android:layout_weight="1"
       android:layout_height="match_parent"
       android:background="#ff333333"
       android:name="com.example.SelectAnItemFragment" />
</androidx.slidingpanelayout.widget.SlidingPaneLayout>

Also SlidingPaneLayoutworks with NavigationFragment things to manage, and it now also recognizes and adapts to folded and hinged states, for example:

Using a device with a hinge that covers part of the screen automatically places the app's content on either side.

SlidingPaneLayoutLock mode is also introduced to support controlling the sliding behavior when panes overlap, for example:

To prevent the user from swiping to an empty pane, requiring a click on a list item to load information about that pane, but allowing them to swipe back to the list, on foldable devices or tablets where there is space to display two views side by side, lock mode will be ignored.

See more at: https://developer.android.com/guide/topics/ui/layout/twopane?hl=zh-cn

custom adaptation

In addition to the official adaptation scheme, maybe we need a more flexible custom adaptation scheme, so the first thing we need to know is how to identify the folding screen.

Identify folding screen

Still the aforementioned Jetpack WindowManager , Jetpack WindowManager FoldingFeatureprovides types of information about foldable displays, including:

  • state: The folded state of the device, FLAT (fully open) or HALF_OPENED(midway between the open and closed states)
  • orientation: the direction of the fold or hinge, HORIZONTALorVERTICAL
  • occlusionType: Whether the fold or hinge hides part of the display, NONE(unobstructed) or FULL(obstructed)
  • isSeparating: Whether the fold or hinge creates two display areas, true (half-open/dual-screen) or false

Android 11 officially also provides support for reading the folding angle: the new type TYPE_HINGE_ANGLE support and the new one can monitor the hinge angle and provide the angle measurement between the two parts of the device:SensorEventSensorEvent

sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
        hingeAngleSensor = sensorManager?.getDefaultSensor(Sensor.TYPE_HINGE_ANGLE)

As for the posture of the folding screen, we can Jetpack WindowManagerachieve it through the API of :

  • Device is in TableTop mode with screen half open and hinge in horizontal orientation

    fun isTableTopMode(foldFeature: FoldingFeature) =
      foldFeature.isSeparating &&
              foldFeature.orientation == FoldingFeature.Orientation.HORIZONTAL
    

  • Device in Book mode with screen half open and hinge in vertical orientation

    fun isBookMode(foldFeature: FoldingFeature) =
      foldFeature.isSeparating &&
              foldFeature.orientation == FoldingFeature.Orientation.VERTICAL
    

For example, the Google Duo team uses Jetpack WindowManager to identify the state of the folded screen, and then adjust the interface UI during the playback process according to the unfolded state.

Briefly, it is obtained through the WindowManager library during initialization Flow<WindowLayoutInfo>to let the phone know that it is currently in desktop mode and how to obtain the folded position:

    override fun onStart() {
    
    
        super.onStart()
        initializePlayer()
        layoutUpdatesJob = uiScope.launch {
    
    
            windowInfoRepository.windowLayoutInfo
                .collect {
    
     newLayoutInfo ->
                    onLayoutInfoChanged(newLayoutInfo)
                }
        }
    }

    override fun onStop() {
    
    
        super.onStop()
        layoutUpdatesJob?.cancel()
        releasePlayer()
    }

Every time you get new layout information, you can query the display capabilities and check if the device has folds or hinges in the current display:

private fun onLayoutInfoChanged(newLayoutInfo: WindowLayoutInfo) {
    
    
        if (newLayoutInfo.displayFeatures.isEmpty()) {
    
    
            // The display doesn't have a display feature, we may be on a secondary,
            // non foldable-screen, or on the main foldable screen but in a split-view.
            centerPlayer()
        } else {
    
    
            newLayoutInfo.displayFeatures.filterIsInstance(FoldingFeature::class.java)
                .firstOrNull {
    
     feature -> isInTabletopMode(feature) }
                ?.let {
    
     foldingFeature ->
                    val fold = foldPosition(binding.root, foldingFeature)
                    foldPlayer(fold)
                } ?: run {
    
    
                centerPlayer()
            }
        }
    }

If the orientation is horizontal and FoldingFeature.isSeparating() returns true, the device can be used in desktop mode, in which case the relative position of the fold can be calculated and the control moved to that position, otherwise it is moved to 0 (bottom of the screen).

    private fun centerPlayer() {
    
    
        ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, 0)
        binding.playerView.useController = true // use embedded controls
    }

    private fun foldPlayer(fold: Int) {
    
    
        ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, fold)
        binding.playerView.useController = false // use custom controls
    }

window size adaptation

In the adaptation of folding devices, the acquisition of window size is also very important . However, in fact, since the development of Android, some of the APIs have been deprecated, or are still being misused. For the adaptation of large screen configurations, because there are Letterboxing and other situations, so in fact, the old API can no longer meet the needs.

The currently deprecated and often misused Display APIs are:

  • getMetrics()
  • getSize()
  • getRealMetrics()
  • getRealSize()
  • getRectSize()
  • getWidth()
  • getHeight()

Commonly misused View APIs are:

  • getWindowVisibleDisplayFrame()
  • getLocationOnScreen

For example Display the getSize() and getMetrics()have been deprecated in API 30 in favor of new WindowManagermethods.

Android 12 (API 31) deprecates Displayand getRealSize(), getRealMetrics()newer and related getMaximumWindowMetrics()methods.

Because the actual size of your app is not necessarily consistent with the actual size of the screen under folding screens and multiple screens, you cannot rely on the physical display size to locate UI elements. Now it is recommended to rely on the WindowMetrics API :

  • Platform:
    • getCurrentWindowMetrics()
    • getMaximumWindowMetrics()
  • Jetpack:
    • WindowMetricsCalculator#computeCurrentWindowMetrics()
    • WindowMetricsCalculator#computeMaximumWindowMetrics()

The Platform here is that Android 11 (API 30) introduced WindowManagerthe method to provide boundaries for applications running in multi-window mode:

  • getCurrentWindowMetrics(): Return the current window state object of the systemWindowMetrics
  • getMaximumWindowMetrics(): Returns the maximum window state of the systemWindowMetrics

The Jetpack WindowManager library methods computeCurrentWindowMetrics()and , computeMaximumWindowMetrics() respectively, provide similar functionality, but are backwards compatible up to API 14.

val windowMetrics = context.createDisplayContext(display)
                    .createWindowContext(WindowManager.LayoutParams.TYPE_APPLICATION, null)
                    .getSystemService(WindowManager::class.java)
                    .maximumWindowMetrics

Therefore, through this WindowManager, we can dynamically manage the size change of the window and recognize the change of the folding screen, for example, to onConfigurationChanged()configure the application layout of the current window size:

override fun onConfigurationChanged(newConfig: Configuration) {
    
    
    super.onConfigurationChanged(newConfig)
    val windowMetrics = WindowMetricsCalculator.getOrCreate()
        .computeCurrentWindowMetrics(this@MainActivity)
    val bounds = windowMetrics.getBounds()
    ...
}

Finally, in terms of window customization and adaptation, it is a common topic, for example:

  • Use wrap_content, match_parent avoid hardcoding
  • Use to ConstraintLayoutmake the root layout, which is convenient for screen size changes, and the view automatically moves and stretches
  • Set the property of applicationor to in the App's AndroidManifest to support resizing and support responsive/adaptive layout.activityandroid:resizeableActivitytrue
  • res/layout/Adaptive layouts can be provided by creating directories such as layout-w600dp
  • ·····

Multiple windows and lifecycle

Since the folding screen is purely in multiple areas, there may be multiple windows, or even more than two windows. In this case, there will naturally be life cycle adaptation problems, such as multiple apps accessing the Camera at the same time.

Regarding the multi-window process, you can briefly introduce:

  • Android 7.0 supports split screen: display two windows left and right/top and bottom

  • Android 8.0 supports picture-in-picture mode. At this time, the in picture-in-picture Activityis in the foreground, but in Pausedstate

  • Android 9.0 (API 28) and below: under multi-window, only the focused application is in the Resumedstate, and other visible ones Activityare still in the Pausedstate

  • Android 10.0 (API 29): In multi-window mode, each Acttivityis in Resumedstate

See, the life cycle is different under different API levels , so in order to solve the problem that only the focused application is in the state of Android 9.0 and below Resume, the following attributes can be added on the App side, and multiple items are supported by manually adding Resumed:

<meta-data
    android:name="android.allow_multiple_resumed_activities" android:value="true" />

It is commonly known as the Multi-resume state.

In order to support the Multi-resume state, a new life cycle callback is naturally required, that isonTopResumedActivityChanged() .

The system calls this method when an Activity gains or loses the top Resume position, such as when using a shared singleton resource such as a microphone or camera:

override fun onTopResumedActivityChanged(topResumed: Boolean) {
    
    
    if (topResumed) {
    
    
        // Top resumed activity
        // Can be a signal to re-acquire exclusive resources
    } else {
    
    
        // No longer the top resumed activity
    }
}

For example, for the scene using the camera, for the above package, Android 10 (API level 29) CameraManager.AvailabilityCallback#onCameraAccessPrioritiesChanged()provides a callback prompt through to indicate that it may be time to try to access the camera.

It is important to note here that using resizeableActivity=false does not guarantee exclusive camera access , as other apps using the camera may be open on multiple monitors (split screen).

CameraDevice.StateCallback#onDisconnected()Therefore, the App needs to handle related behaviors after receiving the callback. If the API is still operated after onDisconnected, the system will throw a CameraAccessException.

In fact, as long as you make a good judgment through the callback, in fact, this "focus" switching experience is seamless.

In multi-window mode, Android may disable or ignore features that are not applicable to activities that share the device's screen with other activities or applications.

In addition, Activity also provides some methods to support multi-window mode:

  • isInMultiWindowMode()Whether to be in multi-window mode.

  • isInPictureInPictureMode()Whether the Activity is in picture-in-picture mode.

    Note: Picture-in-picture mode is a special case of multi-window mode, if isInPictureInPictureMode()returns true, isInMultiWindowMode()will also return true.

  • onMultiWindowModeChanged()The system calls this method when the Activity enters or exits multi-window mode.

    If the Activity is entering multi-window mode, the system passes this method a value of true; if the Activity is leaving multi-window mode, the system passes this method a value of false.

  • onPictureInPictureModeChanged()The system calls this method when the Activity enters or exits picture-in-picture mode.

    The system passes this method a true value if the Activity is entering picture-in-picture mode, and a false value if the Activity is leaving picture-in-picture mode.

Fragment also provides similar methods, such as Fragment.onMultiWindowModeChanged().

Flutter

Starting from 3.13, Flutter also added a new API to match the various properties of the display #41685 , where the new FlutterView.display returns a Display object, and the Display object will report the physical size of the display, device pixel ratio and refresh rate:

  
  void didChangeMetrics() {
    
    
    final ui.Display? display = _display;
    if (display == null) {
    
    
      return;
    }
    if (display.size.width / display.devicePixelRatio < kOrientationLockBreakpoint) {
    
    
      SystemChrome.setPreferredOrientations(<DeviceOrientation>[
        DeviceOrientation.portraitUp,
      ]);
    } else {
    
    
      SystemChrome.setPreferredOrientations(<DeviceOrientation>[]);
    }
  }

The main purpose of this new API is what was mentioned earlier, because once Flutter enters the Letterboxing mode, Flutter MediaQuerymay not be able to obtain the full avalalbe screen size , so the new API is to provide the real size after folding and changing to Space for developers to adapt.

In addition, support for multiple display sizes on Flutter is still being synchronized #125938#125939 , if you are interested, you can also pay attention.

at last

It can be seen that the people here are all very patient comrades. This survey involves a lot of content and covers a wide range of knowledge points. Some may not be deep enough. In general, it still provides directions and ideas, mainly involving:

  • Compatible Letterboxing mode representation
  • resizeableActivitydifferent behavior of configurations such as
  • Adaptation scheme for Compose /Activity Embedding /SlidingPaneLayout
  • Folding screen judgment, window adaptation and life cycle compatibility
  • Flutter API

I believe that there are still many apps that do not plan to adapt to the folding screen. After all, "it is not impossible to use", but after understanding this article, at least it can give you some confidence. At least it seems that if you really want to adapt, it is not a big deal Things that can't be done.

If you have anything else to say, welcome to leave a comment.

Guess you like

Origin blog.csdn.net/ZuoYueLiang/article/details/132451593