Android’s reach is growing and the experience is getting better, with more than 250 million larger devices now running Android, including tablets, foldable devices, and Chrome OS devices. Adapting to different screen sizes and maintaining a good experience has always been a challenge for developers. Especially with the emergence of foldable devices and other emerging products, adaptation work is increasingly urgent. This article highlights updates to the Material Design guide and provides some suggestions to help developers build applications based on the principles of adaptive interfaces that work on tablets and foldable devices.

This article will focus on adaptation in the View system. For more information on how to build large-screen applications with Compose, see the article “Building Android Interfaces for Any Screen Size.”

If you prefer to follow this article through video, click here.

Design guidelines

In early 2021, we published a guide for larger screen devices on the Material Design website. During the Android Developer Summit we updated a few things to help developers prepare for foldable devices and more.

In-depth understanding of layout

The In-depth Layout Guide introduces the concept of layout containers and provides an overall framework to help developers think about how to arrange interface elements such as navigation bars, toolbars, and content on the screen.

△ Three main areas of the layout

The composition section of the guide shows you how to make the best use of screen space for readability and how to arrange important content and action options in different scenarios in a way that respects the user’s mental model. This includes scaling appropriately to show more content, such as subheadings and dates in the example, and smaller composition techniques, such as visually grouping content in a compact layout and keeping it relevant.

△ Part of the layout involved in the composition guide

The Fortnightly example app, for example, has a very balanced interface layout on the tablet, thanks to following the container advice in the guide. And as you can see, Fortnightly uses the Visual Divider to separate the latest news stories, while on the other side of the screen, it uses white space and typography to group different categories of news stories.

△ Fortnightly follows the guidelines for separating and grouping content

Grid system

Many apps now treat the screen like a large canvas or a single column, drawing elements horizontally and vertically in relation to each other, and some apps also leave margins on one side as a whole. While this might work on a smaller screen, it can be problematic when the screen size is larger. A grid system divides your layout into a series of columns to help you design a more expressive layout in a regular grid. Using a grid of columns in the layout (pictured below) gives the experience of a larger device a more intimate and organized impression, allowing the device and content to blend more naturally.

△ Column grid

You can use these columns to improve the information hierarchy by dividing the screen into areas to accommodate related information and actions. As shown in the figure below, there are three areas that draw the user’s attention to the main piece of information or group of information on the screen in the order that the designer expects the user to read. Most importantly, the column grid provides a reasonable way to think about how to rearrange content as the screen size gets larger or smaller, helping you respond consistently to different screen sizes.

Use a grid of columns to divide the screen into three main areas

In this case, the three main areas are rearranged to keep the same information hierarchy, but displayed in a more human way on a small screen.

Rearrange content in different screen sizes using a column grid

Remember that grid systems help you choose component behavior, deciding whether to replace or change components in different layouts in a way that makes the most sense for device size and scenario. For example, on a larger device, you can use Navigation Rail (left sidebar Navigation bar) instead of Bottom Navigation, which has the same function and similar visual presentation, but provides a more user-friendly layout of the page. Full-screen dialogs on phones can be replaced with Simple dialogs on larger screens to keep the context of what the user is doing.

▽ Simple dialog box (right) instead of full screen dialog box (left) on large screen

Size categories

Remember, when replacing components, you must first meet the functional and human needs of your users. Finding the right threshold to adjust an interface is an important step toward a responsive interface. So we define new breakpoint values that help classify devices into preset size categories that represent the actual size of devices on the market. They help translate the raw dimensions of the application board into discrete standardized groups from which you can make higher-level interface decisions. For example, almost all standard phones use a combination of Compact width and Medium height in portrait mode, and due to the widespread use of vertical scrolling, fitting according to the size category of the width is sufficient for most applications.

△ Size category based on width

△ Dimensions based on height

These sizing classes will appear as new apis in version 1.1 of the Jetpack Window Manager library. Starting with Android Studio Bumblebee, we also integrated the size categories into the tool in the form of Reference devices, which made the interface more consistent and easier to use. And developers don’t need to check actual physical dimensions or screen orientation, or other error-prone markers. As you design and build the different size categories, think about how people will hold and touch the devices they represent. Paying attention to the shape and size of your device can help you create a more personal experience. For example, on a tablet or a large-screen phone, the top area of the screen can be difficult to reach without fully adjusting the grip, so keep important actions and content in an accessible area.

Standardize the layout

The canonical layout provides a number of common layout solutions that are useful for designing large screen applications. The first is a list/detail, or simple combination of list grid views, with the navigation container set/unset at the beginning of the screen where the content is displayed.

△ List/detail layout

The support panel can be used for experiences where people need to focus, such as documents. Add a panel at the tail or bottom of the screen for easy access to tools or contextual controls.

△ Support panel

News flow is a common pattern in news or social applications, where templates take the form of tiles to entice users to discover more. The interaction is the same as with mobile phones — opening one opens a new page, but the experience is more immersive and designed for larger screen sizes.

Delta information flow

The home banner prioritizes content at the top of the screen with support elements around and below the content, making it a great experience for media-centric apps.

△ Homepage Banner

Standard layout practice

Adopting responsive interfaces is not only about providing parallel architecture for different screen sizes, but also about being flexible enough to adjust the size to suit various needs, such as rotating devices, multi-window modes, and folded and unfolded poses. So at runtime, an application can transition from one dimension category to another and back again. It is important not to treat size categories as completely separate buckets, and the application needs to be continuous (i.e., without disrupting the user experience) so that application state or data cannot be lost.

△ Responsive interface adjusts content layout according to screen size

Imagine if you resize your browser window and the browser rewinds one page, redirects to another, or modifies its history. It’s a very strange experience. Therefore, each page should be flexible enough and should be able to stay the same during the size transition, where the canonical layout is important. For each page, think about what you can add as the screen size increases. What you can delete when the screen size gets smaller. Then choose the right strategy. This may mean that you need to revisit your navigation chart, especially if your current design is mobile-oriented.

To build a responsive interface, we should prioritize the location of long-resident elements in the interface, such as navigation elements. Following the Material guide, we can provide alternative layouts based on the size category of the width, adjusting the navigation to the most convenient location. For example, small screens have a bottom Navigation view, medium screens have Navigation Rail, and large screens have a full Navigation view. Please note that these layouts use the width qualifier “-w”, not the minimum width qualifier “-sw”. The remaining space is used to arrange the content, and we can apply the canonical layout to this space.

List/Details

For lists/details, there is a special control in AndroidX called SlidingPaneLayout that specifies layout_width for its two child elements before using it. At runtime, SlidingPaneLayout determines if there is enough space to display both panes:

<SlidingPaneLayout... >
      <FragmentCOntainerView
              android : id="@ + id/list_pane"
              android : layout_width="300 dp"
              android : layout_weight="1"... />

      <FragmentCOntainerView
              android : id="@ + id/detail_pane"
              android : layout_width="360 dp"
              android : layout_weight="2"

<SlidingPaneLayout... >
Copy the code

Example SlidingPaneLayout layout

When there is enough screen space, both panes must be at least the specified width. The remaining space can be allocated by layout_weight, as shown on the left. If there is insufficient space, as shown in the image on the right, each pane uses the full width of the superview, and the details pane is slid aside or directly overwrites the first pane.

△ Result of space allocation in SlidingPaneLayout

viewModel.selectedItemFlow.collect { item ->
// Update the details pane
detailPane.showItem(item)
// Slide the details pane to the view
// If two panes are placed side by side
// There is no actual effect
slidingPaneLayout.openPane()
}
Copy the code

As shown in the code above, you can control the sliding pane by code, and when the user selects an item from the list, we receive that item from the Kotlin stream in the ViewModel, then update the contents of the details pane and slide it into view by calling openPane. The effect in Trackr application is shown below:

For more information on how to implement a two-pane layout using SlidingPaneLayout, see the Android Developer website: Creating a two-pane layout, which also covers other topics such as integrating the system back button to slide back to the pane.

The flow of information

We can display a data set through information flow immersion, so RecyclerView is a very suitable choice, we can change its presentation form by changing the LayoutManager used by RecyclerView. LinearLayoutManager is suitable for smaller widths, but in medium width and unfolded width scenarios, the page content will be overstretched and deformed. Use GridLayoutManager instead. Or even StaggeredGridLayoutManager FlexBoxLayoutManager, they may be more appropriate.

Change its display form by changing the LayoutManager of RecyclerView

The home page banners

We can also change the layout of individual items so that some items are taller or wider than others to highlight their importance and create more interesting visuals. In the home banner layout, we emphasize a particular element and rearrange other supporting elements around it. There are many ways to do this, of course, but ConstraintLayout provides the most flexibility because it provides many ways to constrain the size and position of child elements relative to other child elements. In the following media class example application, the header is limited to a 16:9 aspect ratio, the description pane takes up 60% of the width, and the remaining space is reserved for other elements. Constraints can be changed and even animated with MotionLayout, which is a special ConstraintLayout.

△ Home page banner example

For supporting panels, any layout control from LinearLayout to ConstraintLayout can be used as a container to position the panel. As shown in the figure below, we consider one thing, where the content on the panel should go when transitioning to a small screen size. There are many options, such as using a side drawer navigation bar at the end of the screen, or using a sliding bottom action bar, or using options menus, or even hiding the content completely.

Suitable for foldable devices

Foldable devices not only have bigger screens, they can also adjust the orientation/posture of the device based on how it folds and how the user is using it.

There are three common device configurations: folded, unfolded, and desktop mode (hover). In addition, we will look at other theoretical states later, such as book mode.

▷ Three common positions of folding equipment

As with any large screen device, we need to think about how the user will hold the unfolded device. On tablets, for example, some areas of the screen are hard to reach with your thumb, and it’s hard to control the screen with your whole hand. Users can easily reach the bottom corner of the screen, but may not be able to reach the top, especially in portrait mode. This means that if you use a component like Navigation Rail, having Navigation buttons centered or anchored to the bottom of the screen makes it easier for the user to navigate.

△ User operation hot area in large-screen equipment

We also need to consider the effect of hinge position on interaction. The hinge creates a noticeable tactile difference and even physical separation between the two screens. Therefore, avoid placing buttons and other important action items directly in the hinge area. The hinged area is about 48 DP wide on most devices, so avoid placing interface elements in the hinged area in desktop mode as there is almost no use for the area in this device mode.

△ Hinge region

There are two main technical scenarios that can be used to design a layout when a device transitions from folded mode to unfolded mode. The first is to expand the screen, which uses a simple responsive layout where the app expands and fills the screen. In general, we extend the column grid according to the Material guide mentioned earlier.

The second option is to add another page, which, depending on the application you’re building, could be the same as listing/details or supplementing the main panel with another panel.

△ Situation 1: Enlarge the screen (left) situation 2: Increase the page (right)

In both cases, according to the Material. IO guidelines, you need to create a grid of eight bars evenly distributed on either side of the hinge area, and when Navigation rails and other Navigation containers are added, the beginning side of the screen is compressed to accommodate them.

△ Eight grids evenly distributed on both sides of hinges (blue background)

Fit sample

Now let’s look at how to take advantage of the collapsed state at run time. The Jetpack Window Manager library provides an API to detect application Window folding. Any Activity can acquire a WindowInfoRepository instance. Then, between the life cycle states Started and Stopped, we can safely gather information from the window layout information flow. Each time the stream emits a value, we can check the displayFeature and then target the FoldingFeature.

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

        val windowInfoRepo = windowInfoRepository()

        // Securely gather data from the windowInfoRepo between life cycle states STARTED and STOPPED
        lifecycleScope.launch(Dispatchers.Main) {
            lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
                windowInfoRepo.windowLayoutInfo.collect { info ->
                    for (feature in info.displayFeatures) {
                        val fold = feature as? FoldingFeature ? :continue
                        / / use FoldingFeature
                    }
                }
            }
        }
    }
Copy the code

Recognize folding posture

With information about the folding posture in hand, there are ways to see if the device is in one of the positions mentioned above. In book mode, the device is in HALF_OPENED state and its direction is VERTICAL. In desktop mode, the state is HALF_OPENED and the direction is HORIZONTAL.

// Book mode is a half-open vertical folding mode
fun FoldingFeature.isBookMode(a) =
    state == FoldingFeature.State.HALF_OPENED &&
        orientation == FoldingFeature.Orientation.VERTICAL

// Desktop mode is a half-open horizontal collapse mode
fun FoldingFeature.isTableTopMode(a) =
    state == FoldingFeature.State.HALF_OPENED &&
        orientation == FoldingFeature.Orientation.HORIZONTAL
Copy the code

△ Criteria for deciding book mode over desktop mode

The FoldingFeature also contains the folding position in the window, so we should update the layout parameters if the folding causes the content view to be split. You can make adjustments such as placing the support panel on one side or displaying the home banner on the top half of the fold. First, we need to know where the content view is in the window, which we can get with getLocationInWindow. We will create a Rect object using these coordinates, along with the width and height, so that we get the view boundary in the window coordinate space.

The FoldingFeature gives the folded boundary in the coordinate space of the window, so we can directly check whether the two regions intersect. If they do, we can convert the boundary of featureRect to the coordinate space of the view and return it. By the way, if you use SlidingPaneLayout for list/detail layout, you automatically get support for book mode. As long as both panes fit, SlidingPaneLayout places the panes on the other side of the folded pose.

fun getFoldBoundsInView(
       foldingFeature: FoldingFeature,
       view: View
): Rect? {
       // Get the boundary of the view in the window coordinate space
       val viewLocation = IntArray(2)
       view.getLocationInWindow(viewLocation)

       val (viewX, viewY) = viewLocation
       valViewRect = Rect(left = viewX, top = viewY right = viewX + view.width, bottom = view + view.height)...// The boundary of the display function is already in the window coordinate space
       // Check whether the view boundary intersects the display boundary
       val featureRect = Rect(foldingFeature.bounds)
       val intersects = featureRect. intersect (viewRect)

       if (featureRect.isEmpty || ! intersects)
           return null
       }

       // Convert function boundary coordinates to view coordinate space
       featureRect.offset(-viewX, -viewY)
       return featureRect
}
Copy the code

△ Obtain information of folding position

test

If your application has a particular behavior related to folded state, you need to write unit tests for it. There is a test rule in Jetpack Window Manager that enables the FoldingFeature to be simulated during piling tests. Due to test needs to view, we added WindowLayoutInfoPublisherRule, and ActivityScenarioRule, together form a chain test rules. In this test method, we get the Activity through activityRule, then create a window feature to simulate the desktop mode, build a WindowLayoutInfo object and publish it using publisherRule. After that, we can use Espresso and JUnit assertions to check if the Activity is running properly in desktop mode.

private val publisherRule = WindowLayoutInfoPublisherRule()
private val activityRule = ActivityScenarioRule (MyActivity: :class.java)

@get :Rule
val testRule = RuleChain.outerRule (publisherRule) .around(activityRule)

@Test
fun testDeviceOpen_TableTop(a): Unit = testScope.runBlockingTest {
    activityRule.scenario.onActivity { activity ->
        val feature = FoldingFeature (activity, HALF_OPENED, HORIZONTAL)
        val testWindowInfo = WindowLayoutInfo.Builder( )
                .setDisplayFeatures (listOf (feature))
                .build()

        publisherRule.overrideWindowLayoutInfo(testWindowInfo)
    }
        // Write assertions based on desktop mode
}
Copy the code

△ Test folding state

Interface testing is difficult because some tests have to be done on specific devices. To that end, Android Studio is adding support for virtual appliances hosted by Gradle. You can use the Android Gradle plugin 7.1 or later to experience this feature.

Under the testOptions module in the build.gradle file at the application level, specify the virtual appliance configuration file as you would normally manage and run virtual devices in Android Studio. For example, the Pixel C tablet image is used here. Gradle then creates a target that can perform tests on the specified device and even download the device image as needed.

Android {testoptions {devices {pixelCapi30 (ManagedVirtualDevice) {device = "Pixel C" // tablet apilevel = 30 SystemImageSource = "aosp" // For GooglePlay services, use the "Google" abi = "x86 "}}}}Copy the code
#Gradle target = {device name} + {build variant} + "AndroidTest"
./gradlew pixelCapi30debugAndroidTest
Copy the code

▽ Virtual device configuration

To help distinguish which tests are for which devices, we will create a custom annotation, LargeScreenTest, that marks the test function. When running the previous Gradle command, we add a parameter to AndroidTestRunner to ensure that only tests with this comment are run. If you don’t use annotations, you can also use TestRunner’s other filtering options, such as running tests in a specific class. By combining these features, we can run configurations consistently for test Settings.

annotation class LargeScreenTest @RunWith(AndroidJUnit4: :class) class MyActivityTest {@test@largesCreentest Fun largeScreenDeviceTest() {// Test interface on tablet devices}} # Only run tests with specified annotations.  /gradlew pixelCapi30debugAndroidTest \-Pandroid.testInstrumentationRunnerArguments.annotation=com.mypkg.LargeScreenTestCopy the code

Write tests for specified devices using custom annotations

For more information

In addition to making the content on the screen look bigger, the larger screen presents some other opportunities to help your app shine. In multi-window mode, your application can be used side by side with other applications. In addition to responsive adjustment, you can also consider how to make your application more useful in this mode, such as support for drag and drop. This small feature can make your users more productive and more likely to use your app.

▽ Multi-window mode effect

Large screen devices support other forms of interaction besides touch. The larger the screen size of the device, the more likely the user is to use a keyboard, stylus, mouse, gamepad or other add-on. If you want to improve your application’s ease of use in these situations, you can plan to support some of these input methods. For more details, see the article “It’s Time for Good input support for All Devices.”

With such a diverse hardware ecosystem, it can be difficult to have devices of all shapes and sizes, but the Android SDK now provides images of emulators for foldable devices that allow you to change the folding state to the Angle of the hinge on the go. The upcoming Android Studio Chipmunk will also feature a resizable emulator that allows you to freely change the size of your app window, allowing every developer to try out their app on almost any type of device.

△ Resizable emulator in Android Studio Chipmunk

We’ve also been working on new tools in Android Studio that will allow you to build big-screen apps. The new Layout Validation tool previews a Layout on a reference device that covers a variety of size categories, suggests problem areas (such as text using long lines), and recommends different interface components for different breakpoints.

Layout Validation in Android Studio

Finally, we on the Android developer website lists the application quality guidelines for the big screen, front part of the guide to introduce basic compatibility is expected, such as whether the application supports both horizontal and vertical screen mode, behind a few part focuses on a variety of screen type and status, and use the specific screen type or state create a different experience.

We hope that you can take advantage of what we’ve shared today and use our new quality guidelines to build apps that appeal to users at all screen sizes.

Please click here to submit your feedback to us, or share your favorite content or questions. Your feedback is very important to us, thank you for your support!