Compatibility of screen size for Android development

Screen Size and Density

This section provides data on the relative number of devices with a particular screen configuration (defined by screen size and density). To simplify the process of designing interfaces for different screen configurations, Android divides the range of actual screen sizes and densities into intervals, as shown in the table below.

ldpi

mdpi tvdpi hdpi xhdpi xxhdpi Total
Small 0.1% 0.1% 0.2%
Normal 0.4% 0.3% 17.0% 41.1% 25.9% 84.7%
Large 1.8% 2.0% 0.7% 2.6% 2.1% 9.2%
Xlarge 3.5% 1.9% 0.5% 5.9%
Total 0.1% 5.7% 2.3% 19.6% 44.3% 28.0%

 Android runs on a variety of devices with different screen sizes and pixel densities. While basic zooming and resizing functions allow you to adapt your UI to different screens, you should optimize further to ensure that your UI looks good on a variety of screens.

Support for different screen sizes

Android devices come in all shapes and sizes, so your app's layout needs to be flexible. That is, the layout should respond gracefully to different screen sizes and orientations, rather than defining rigid dimensions for the layout, assuming that the screen size and aspect ratio are constant.

By supporting as many screens as possible, your app can run on a variety of different devices so you can serve it to the largest number of users with a single APK. Additionally, being able to make your app flexible to different screen sizes ensures that your app can handle window configuration changes on the device, such as those that occur when the user enables multi-window mode .

This page will show you how to support different screen sizes using the following techniques:

  • Use view dimensions that allow layout resizing
  • Create alternate interface layouts based on screen configurations
  • Provides a bitmap that can stretch with the view

Note, however, that adapting to different screen sizes does not necessarily make your app compatible with all Android device types. You should take additional steps to support Android Wear, Android TV, Android Auto, and Chrome OS devices .

Create flexible layouts

No matter what hardware profile you want to support first, you need to create a layout that is flexible to even small changes in screen size.

Use ConstraintLayout

To create responsive layouts for different screen sizes, it's a best practice to  use ConstraintLayout  as the base layout in your UI. With  ConstraintLayout , you can specify the position and size of each view based on the spatial relationship between the views in the layout. This way, all views can be moved and stretched together when the screen size changes.

 The easiest way to build a layout with ConstraintLayout is to use  the layout editor in Android Studio. With this tool, you can drag a new view into the layout, attach its constraints to parent and other sibling views, and modify the view's properties, all without manually modifying any XML.

However, ConstraintLayout it doesn't solve all layout scenarios (especially dynamically loaded lists, for which RecyclerView should be used ), but no matter what layout you use, you should avoid hardcoding layout dimensions (see next section).

Avoid hardcoded layout dimensions

To ensure that your layout adapts flexibly to different screen sizes, you should use width and height for most view components  "wrap_content" ,  "match_parent"rather than hard-coded dimensions.

"wrap_content" Instructs the view to set its dimensions to the dimensions necessary to fit the corresponding content in the view.

"match_parent" Make the view expand as much as possible within the parent view.

<TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/lorem_ipsum" />
    

 While the actual layout of this view depends on other properties in its parent view and any sibling views, this  TextView wants to set its width to fill all available space ( match_parent) and its height to be exactly what the text length requires space ( wrap_content). This allows this view to adapt to different screen sizes and different text lengths.

If you are using  LinearLayout, you can also expand subviews by layout weight so that each view fills the remaining space in proportion to its own weight value. LinearLayout However, using weights in nested  will require the system to perform multiple layout passes to determine the dimensions of each view, which can degrade interface performance. Luckily, it ConstraintLayout 's possible to build almost  LinearLayout any layout you can, without affecting performance, so you should try converting your layouts to ConstraintLayout . The constraint chain can then be used to define a weighted layout .

NoteMUST NOT be used   when using ConstraintLayout . Instead, set the size   to enable a special behavior called a "match constraint", which is usually the   expected behavior of . See How to Resize Views in ConstraintLayout for details .match_parent0dpmatch_parent

Create an alternate layout

While your layout should always respond to different screen sizes by stretching the space in and around its views, this may not provide the best user experience for every screen size. For example, an interface you design for a phone may not provide a good experience on a tablet. Therefore, your app should also provide alternate layout resources to optimize UI design for specific screen sizes.

You can provide screen-specific layouts by creating additional  res/layout/ directories (one for each screen configuration that requires a different layout), and then appending the screen configuration qualifier to the  layout directory name (for example, for a screen with an available width of 600dp, append qualifier is  layout-w600dp).

These configuration qualifiers represent the visible screen real estate available to the application interface. The system takes into account all system decorations (such as navigation bars) and window configuration changes (such as when the user enables multi-window mode ) when choosing a layout from within the app .

To create an alternate layout in Android Studio (using version 3.0 or higher), follow these steps:

  1. Open the default layout and click  the Orientation for Preview  icon  in the toolbar .
  2. In the drop-down list, click to create a suggested variant (such as  Create Landscape Variant ), or click  Create Other .
  3. If you choose  Create Other , the system displays  Select Resource Directory . In this window, select a screen qualifier on the left and add it to  the Chosen qualifiers  list. After adding the qualifiers, click  OK . (See the sections below for information on screen size qualifiers.)

 

A duplicate layout file is created in the appropriate layout directory so you can start customizing the layout for that screen variant.

Use min-width qualifier

Using the "min-width" screen size qualifier, you can provide alternate layouts for screens with a minimum width (measured in density-independent pixels  dp or dip).

By describing screen sizes as measures of density-independent pixels, Android allows you to create layouts designed for very specific screen sizes without having to worry about varying pixel densities.

For example, you can create a  main_activity layout named and optimized for phones and tablets by creating different versions of the file in a directory like so:

res/layout/main_activity.xml           # For handsets (smaller than 600dp available width)
res/layout-sw600dp/main_activity.xml   # For 7” tablets (600dp wide and bigger)

The min-width qualifier specifies the minimum size of the sides of the screen regardless of the device's current orientation, so it's an easy way to specify the overall screen size available to a layout.

Here's how other minimum width values ​​correspond to typical screen sizes:

  • 320dp: typical mobile phone screen (240x320 ldpi, 320x480 mdpi, 480x800 hdpi, etc.).
  • 480dp: Approx. 5 inches for large phone screens (480x800 mdpi).
  • 600dp: 7-inch tablet (600x1024 mdpi).
  • 720dp: 10" tablet (720x1280 mdpi, 800x1280 mdpi, etc.).

Remember that all values ​​for the min-width qualifier are density-independent pixels , because what matters is the amount of screen space available after the system considers pixel density, not native pixel resolution.

Note : The size you specify with these qualifiers is not the actual screen size , but  the available width or height (in dp) of the Activity window . The Android system may use part of the screen for system interfaces (such as the system bar at the bottom of the screen or the status bar at the top), so part of the screen may not be available for your layout. If your app is used in multi-window mode , it can only use the dimensions of that window. When the window is resized, it triggers a configuration change with the new window dimensions so that the system can choose an appropriate layout file. Therefore, when declaring dimensions, you should specify which dimensions your Activity requires. When declaring the space provided for layout, the system takes into account all space used by the system interface.

 

 Use available width qualifier

You may want to change the layout based on the currently available width or height, rather than the minimum width of the screen. For example, if you have a two-pane layout, you may want to use that layout when the screen width is at least 600dp, but the screen width may change depending on whether the device's screen orientation is landscape or portrait. In this case, you should use the "Available Width" qualifier, like so:

   res/layout/main_activity.xml         # For handsets (smaller than 600dp available width)
   res/layout-w600dp/main_activity.xml  # For 7” tablets or any screen with 600dp
                                         #   available width (possibly landscape handsets)

If you care about available height, you can use the "available height" qualifier to do the same. For example, use qualifiers for screens with a screen height of at least 600dp  layout-h600dp.

Add screen orientation qualifier

While you may only need to combine the "min-width" and "available-width" qualifiers to support all size variations, you may also want to change the user experience when the user switches screen orientation between portrait and landscape.

You can do this by  adding port the or  land qualifier to the resource directory name. Just make sure these qualifiers come after the other size qualifiers. For example:

    res/layout/main_activity.xml                # For handsets
    res/layout-land/main_activity.xml           # For handsets in landscape
    res/layout-sw600dp/main_activity.xml        # For 7” tablets
    res/layout-sw600dp-land/main_activity.xml   # For 7” tablets in landscape

Use Fragment to modularize interface components

When designing an app for multiple screen sizes, you want to make sure that interface behavior isn't unnecessarily duplicated between activities. Therefore, you should use  Fragments  to extract interface logic into separate components. You can then combine the Fragments to create a multi-pane layout when running on a large-screen device, or place the Fragments in separate Activities when running on a phone.

For example, a news app on a tablet might show a list of stories on the left and a full story on the right. When a story is selected on the left, the story view on the right is updated. However, on mobile, these two components should be displayed on separate screens. When a story is selected from the list, the entire screen changes to show that story.

Support Android 3.1 using old size qualifiers

If your app supports Android 3.1 (API level 12) or lower, you need to use the legacy size qualifiers in addition to the minimum/available width qualifiers above .

In the example above, if you want to display the dual-pane layout on larger devices, you need to use the "large" configuration qualifier to support versions 3.1 and below. So, to implement such layouts on these older versions, you may need to create the following files:

    res/layout/main_activity.xml           # For handsets (smaller than 640dp x 480dp)
    res/layout-large/main_activity.xml     # For small tablets (640dp x 480dp and bigger)
    res/layout-xlarge/main_activity.xml    # For large tablets (960dp x 720dp and bigger)

Use layout aliases

To support both versions lower than and higher than Android 3.2, you must use both the min-width and "large" qualifiers for layouts. Therefore, you should create a  res/layout-large/main.xml file called , which may be  res/layout-sw600dp/main.xml exactly the same as .

To avoid this duplication of the same file, you can use an alias file. For example, you can define the following layouts:

    res/layout/main.xml            # single-pane layout
    res/layout/main_twopanes.xml   # two-pane layout

and add the following two files:

  • res/values-large/layout.xml
        <resources>
            <item name="main" type="layout">@layout/main_twopanes</item>
        </resources>
  • res/values-sw600dp/layout.xml
    <resources>
        <item name="main" type="layout">@layout/main_twopanes</item>
    </resources>

The contents of the two files are exactly the same, but they don't actually define the layout, they're just  aliases main for what to set  main_twopanes . Since these files have the  large and  sw600dp selectors, they will work on tablets and TVs of any Android version (tablets and TVs below 3.2 will  large match, and those above 3.2 will  sw600dp match).

Create a stretchable nine-square bitmap

If you're using a bitmap as a background in a resizing view, you'll notice that Android scales your image as the view grows or shrinks based on the screen size or the content in the view. This often results in noticeable blurring or other scaling artifacts. The solution is to use a Jiugongge bitmap, a specially formatted PNG file that indicates which areas can and cannot be stretched.

A Jiugongge bitmap is basically a standard PNG file, but with an extra 1-pixel border indicating which pixels should be stretched (and with an  .9.png extension, not just  .png). As shown in Figure 5, the intersection between the black lines on the left and top edges is the area of ​​the bitmap that can be stretched.

Alternatively, you can also define the safe area where the content should go within the view, by adding lines to the right and bottom edges in the same way.

When applying a nine-square grid as a background to a view, the framework correctly stretches the image to fit the size of the button.

Support for different pixel densities

Not only do Android devices come in different screen sizes (phones, tablets, TVs, etc.), but their screens also come in different pixel sizes. That is, it is possible for one device to have a screen with 160 pixels per square inch and another device with a screen that can fit 480 pixels in the same space. If you don't account for these differences in pixel density, the image may be scaled (causing blurry images), or the image may appear at the wrong size entirely.

use density-independent pixels

The first pitfall you must avoid is using pixels to define distance or size. Using pixels to define size is problematic because different screens have different pixel densities, so the same number of pixels may correspond to different physical sizes on different devices.

To preserve the visible size of the UI on screens of different densities, you must design the UI using density-independent pixels (dp) as a unit of measurement. dp is a virtual pixel unit, 1 dp is approximately equal to 1 pixel on a medium-density screen (160dpi; the "base" density). For each other density, Android converts this value to the corresponding actual number of pixels.

For example, consider the two devices in Figure 1. If you define a view as "100px" wide, it will appear much larger on the left device. So you have to use "100dp" instead to make sure it looks the same size on both screens.

However, when defining text sizes, you should use scalable pixels (sp) as the unit instead (but never use sp for layout dimensions). By default, the sp unit is the same as the dp size, but it will resize based on the user's preferred text size.

For example, when you specify the spacing between two views, use  dp:

    <Button android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/clickme"
        android:layout_marginTop="20dp" />
When specifying text size, always use sp:
    <TextView android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="20sp" />
    
Convert dp units to pixel units

In some cases, you need to  dp express dimensions in terms of pixels and then convert them to pixels. Converting dp units to screen pixels is easy:

px = dp * (dpi / 160)

Consider an application where the user's finger moves at least 16 pixels before the system recognizes a scroll or swipe gesture. On the baseline screen, the user must move  16 pixels / 160 dpi(equal to 1/10 of an inch or 2.5 millimeters) for the gesture to be recognized. On devices with high-density displays (240dpi), the user's finger must move at least  16 pixels / 240 dpi1/15th of an inch (1.7 mm). This distance is much shorter, so the user perceives the app to be more responsive on that device.

dp To fix this, you must represent gesture thresholds in code  before converting to actual pixels.

    // The gesture threshold expressed in dp
    private static final float GESTURE_THRESHOLD_DP = 16.0f;

    // Get the screen's density scale
    final float scale = getResources().getDisplayMetrics().density;
    // Convert the dps to pixels, based on density scale
    mGestureThreshold = (int) (GESTURE_THRESHOLD_DP * scale + 0.5f);

    // Use mGestureThreshold as a distance in pixels...

 

DisplayMetrics.densitydp field specifies the scaling factor that must be used to convert units to pixels,  based on the current pixel density  . On medium-density screens, DisplayMetrics.density it is equal to 1.0; on high-density screens, it is equal to 1.5; on ultra-high-density screens, it is equal to 2.0; on low-density screens, it is equal to 0.75. This number is a factor that is multiplied by the  dp unit to get the actual number of pixels on the current screen.

Use prescaled config values

You can use  ViewConfiguration the class to obtain the distance, speed and time commonly used by the Android system. getScaledTouchSlop() For example, the distance in pixels that the frame uses as a scroll threshold can be obtained with  :

private static final int GESTURE_THRESHOLD_DP = ViewConfiguration.get(myContext).getScaledTouchSlop();
    

ViewConfiguration Methods starting with  getScaled the prefix in are sure to return pixel values ​​that will display normally regardless of the current screen density.

Provide an alternate bitmap

To provide good graphics quality on devices with different pixel densities, you should provide multiple versions of each bitmap (one for each density level) in your app at the appropriate resolution. Otherwise, the Android system must scale the bitmap so that it occupies the same visible space on each screen, causing scaling artifacts such as blurring.

There are several density levels available for use in your application. Table 1 describes the different configuration qualifiers available and the screen types they apply to.

density qualifier illustrate
ldpi Resources for low-density (ldpi) screens (~120dpi).
mdpi Resources for medium density (mdpi) screens (~ 160dpi) (this is the baseline density).
hdpi Resources for high-density (hdpi) screens (~240dpi).
xhdpi Resources for extra high (xhdpi) density screens (~320dpi).
xxhdpi Resources for extra-extra high-density (xxhdpi) screens (~480dpi).
xxxhdpi Resources for ultra-extra high-density (xxxhdpi) screens (~640dpi).
nodpi Resources available for all densities. These are density-independent resources. Resources marked with this qualifier will not be scaled regardless of the current screen density.
tvdpi Resources for screens with densities between mdpi and hdpi (~213dpi). This is not part of the "main" density group. It's mostly used on TVs, and most apps don't need it. Providing mdpi and hdpi resources is sufficient for most applications, and the system will scale them as appropriate. If you find it necessary to provide a tvdpi resource, it should be sized by a factor of 1.33*mdpi. For example, if an image is 100px x 100px on an mdpi screen, it should be 133px x 133px on a tvdpi screen.

 

To create alternate bitmap drawable resources for different densities, you should follow the  3:4:6:8:12:16 scaling ratio between the six main densities . For example, if you have a bitmap drawable that measures 48x48 pixels on a medium-density screen, its size on other densities would be:

  • 36x36 (0.75x) - low density (ldpi)
  • 48x48 (1.0x baseline) - medium density (mdpi)
  • 72x72 (1.5x) - High Density (hdpi)
  • 96x96 (2.0x) - Extra High Density (xhdpi)
  • 144x144 (3.0x) - Ultra-Extra High Density (xxhdpi)
  • 192x192 (4.0x) - Ultra Ultra High Density (xxxhdpi)

Then, place the generated image files  res/ in the appropriate subdirectories below, and the system will automatically select the correct file based on the screen density of the device running your app:

    res/
      drawable-xxxhdpi/
        awesome-image.png
      drawable-xxhdpi/
        awesome-image.png
      drawable-xhdpi/
        awesome-image.png
      drawable-hdpi/
        awesome-image.png
      drawable-mdpi/
        awesome-image.png

Then, whenever you reference it  @drawable/awesomeimage , the appropriate bitmap is selected based on the screen dpi. If you don't provide a density-specific resource for a density, the system picks the next best match and scales it to fit the screen.

Tip : If you have drawable resources that the system should never scale (perhaps because you're doing some tweaking of the image yourself at runtime), you should put them in a directory with a configuration qualifier  nodpi . Resources using this qualifier are considered density-independent and the system does not scale them.

Put the app icon in the mipmap directory

As with all other bitmap resources, you need to provide density-specific versions for app icons. However, some app launchers display app icons that are as much as 25% larger than required by the device's density level.

For example, if the device's density bucket is xxhdpi and you provide a maximum app icon density level of  drawable-xxhdpi, the launcher app will scale up the icon, which can cause it to look less sharp. Therefore, you should  mipmap-xxxhdpi provide a denser launcher icon in the directory, and then the launcher can use the xxxhdpi resource instead.

Since app icons can be enlarged like this, you should put all app icons  mipmap in a directory, not  drawable in a directory. Unlike  drawable directories, all  mipmap directories are preserved in the APK, even if you build density-specific APKs. This allows the launcher app to pick the best resolution icon to display on the home screen.

    res/
      mipmap-xxxhdpi/
        launcher-icon.png
      mipmap-xxhdpi/
        launcher-icon.png
      mipmap-xhdpi/
        launcher-icon.png
      mipmap-hdpi/
        launcher-icon.png
      mipmap-mdpi/
        launcher-icon.png

Use vector graphics instead

An alternative to creating multiple density-specific versions of a picture is to create just one vector graphic. When creating pictures with vector graphics, use XML to define paths and colors instead of pixel bitmaps. As a result, vector graphics can be scaled to any size without scaling artifacts, although they are usually best for illustrations such as icons and less so for photographs.

Vector graphics are usually provided as SVG (Scalable Vector Graphics) files, but Android does not support this format, so you must convert the SVG file to Android's vector graphics format.

You can use Vector Asset Studio in Android Studio to   easily convert SVG to vector graphics, the specific steps are as follows:

  1. In  the Project  window, right-click  the res  directory and select  New > Vector Asset .
  2. Select  Local file (SVG, PSD) .
  3. Find the file to import and make any adjustments.

    Figure 3.  Importing an SVG file using Android Studio

    You may notice   some errors in the Asset Studio window stating that some properties of the file are not supported for vector graphics. But that won't stop you from importing, it just ignores unsupported properties.

  4. Click Next .

  5. On the next screen, confirm the source set from which you want to find the project files , and click  Finish .

    Because one vector drawing is available for all pixel densities, this file is in the default drawable directory (you don't need to use density-specific directories):

       res/
          drawable/
            ic_android_launcher.xml

Advice for Uncommon Density Issues

This section details how the Android system performs scaling of bitmaps on screens with different pixel densities, and how you can further control how bitmaps are drawn on screens with different pixel densities. You can ignore this section unless your app manipulates graphics, or your app has problems running on devices with different pixel densities.

To better understand how to support multiple densities during runtime manipulation of graphics, you should first understand that the system helps ensure that bitmaps are scaled correctly in the following ways:

  1. Prescaled resources (such as bitmap drawable resources)

    Depending on the current screen's density, the system uses any density-specific resources in your app. If no asset is available for the appropriate density, the system loads the default asset and scales it up or down as needed. The system assumes that default resources (those in directories with no configuration qualifiers) are designed for the baseline pixel density (mdpi), and resizes these bitmaps to fit the current pixel density.

    If you request the dimensions of a prescaled asset, a value representing the scaled dimensions will be returned. For example, if a 50x50 pixel bitmap designed for an mdpi screen scales to 75x75 pixels on an hdpi screen (if there are no alternate resources for hdpi), the system will report the size as 75x75 pixels.

    In some cases, you may not want the Android system to prescale resources. The easiest way to avoid prescaling is to place resources  nodpi in resource directories with configuration qualifiers. For example:

    res/drawable-nodpi/icon.png

    icon.png When the system uses bitmaps in this folder  , they are not scaled according to the current device density.

  2. Automatic scaling of pixel dimensions and coordinates

    You can disable prescaling by setting   android  :anyDensity"false" in the manifest to , or  Bitmap programmatically  inScaled for  "false". In this case, all absolute pixel coordinate and pixel dimension values ​​are automatically scaled while drawing. This is done to ensure that screen elements defined in pixels appear to be roughly the same size as their physical size on a screen with a base pixel density (mdpi). The system handles this scaling transparently to the application and reports scaled pixel dimensions to the application rather than physical pixel dimensions.

    For example, suppose an application is running on a device with a WVGA high-density screen that measures 480x800, which is about the same size as a traditional HVGA screen, but with prescaling disabled. In this case, when the app queries the screen size, the system "lies" about it, reporting the screen size as 320x533 (approximately converted for a screen with a pixel density of mdpi). Then, when the app performs a drawing operation, such as invalidating the rectangle from (10,10) to (100,100), the system transforms the coordinates by scaling them by the appropriate amount, effectively making the (15,15) to A range of (150,150) is invalid. This difference can lead to unexpected behavior if your app manipulates scaled bitmaps directly, but is considered a reasonable trade-off in order to keep app performance as good as possible. If this happens to you, read Converting dp units to pixel units .

    Normally, prescaling should not be disabled . The best way to support multiple screens is to follow the basic techniques described in this document.

If your app manipulates bitmaps or interacts directly with on-screen pixels in some other way, you may need to take additional steps to support different pixel densities. For example, if you're responding to touch gestures by counting the number of pixels a finger slides over, you'll need to use the appropriate density-independent pixel values, not actual pixels, but you can easily convert between dp and px values .

Tested against all pixel densities

Be sure to test your app on multiple devices with different pixel densities so you can make sure the UI scales correctly. Testing on a physical device is easy, but if you don't have access to a physical device with various pixel densities, you can also use the  Android emulator .

Guess you like

Origin blog.csdn.net/mozushixin_1/article/details/131551512