Android12L-处理边衬区大小的动态变化

1,723 阅读4分钟

**Android 12 L 新特性

1. 前言

处理边衬区大小的动态变化

系统会将新的任务栏作为衬边区报告给应用

与手势导航搭配使用时,任务栏可以动态地隐藏和显示,如果应用本就使用边衬区信息来绘制界面,则需要考虑当应用处于恢复状态时,边衬区大小可能会发生变化。在这些情况下,应用需要调用 setOnApplyWindowInsetsListener并处理边衬区的尺寸变化。

注意:虽然任务栏没有自己的边衬区类型,但可使用 WindowInsetsCompat.Type.navigationBars()WindowInsetsCompat.Type.systemBars() 检索其尺寸。

2. edge-to-edge

可以将应用程序配置为在系统栏后面配置其内容,状态栏和导航栏一起称为 系统栏

你的应用程序通过在这些系统栏后面绘图来实现一个边缘到边缘的布局。

当实现 edge-to-edge 时

  • 绘制导航栏后面,以实现更引人注目和现代的用户体验
  • 如果对你的内容和布局有意义,比如在全宽图像的情况下,可以在状态栏后面画,要做到这一点可以使用 AppBarLayout 等API, 它定义了固定在屏幕顶部的应用程序栏。

\

在你的应用程序中实现边缘到边缘需要以下步骤:

  • 全屏布局应用程序
  • 更改系统栏的颜色和透明度
  • 处理任何视觉重叠

\

Step 1: 全屏布局应用程序

这是确保你的应用能够边到边的主要步骤,使用整个显示的宽度和高度进行布局。

使用 WindowCompat.setDecorFitsSystemWindow(window, fasle)系统栏后面布局你的应用

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    WindowCompat.setDecorFitsSystemWindows(getWindow(), false);
}

Step 2: 改变系统栏的颜色

当操作在一个边缘到边缘的布局,你的应用程序需要改变导航和状态栏的颜色,以允许下面的内容是可见的,应用程序执行此步骤后, 系统将处理手势导航模式或按钮模式下所有用户界面的视觉保护。

  • 手势导航模式

系统采用动态颜色适配模式,系统栏的内容会根据其后面的内容改变颜色。在下面的例子中,如果导航栏中的句柄位于浅色内容的上方,则它会变成深色,反之亦然。

\

  • Button modes:

系统栏后面使用半透明稀松(for API level 29 or higher) ,或者透明r (for API level 28 or lower).

系统栏半透明稀松

  • Status bar content color:

控制状态栏内容的颜色,时间,图标等。

\

在 themes.xml 中编辑 导航栏的颜色。同时可以设置状态栏透明且将状态栏设置为深色。

<!-- values-v29/themes.xml -->
<style name="Theme.MyApp">
  <item name="android:navigationBarColor">
    @android:color/transparent
  </item>
  
  <!-- Optional: set to transparent if your app is drawing behind the status bar. -->
  <item name="android:statusBarColor">
    @android:color/transparent
  </item>
  
  <!-- Optional: set the status bar light and content dark. -->
  <item name="android:windowLightStatusBar">
    true
  </item>
</style>

Note: If you prefer to disable automatic content protection on Android 10 (API level 29) or higher, set android:enforceNavigationBarContrast, android:enforceStatusBarContrast, or both to false in your theme.

\

可以直接使用 WindowInsetsController API, 但更加推荐和使用 WindowInsetsControllerCompat - 控制内容颜色。 setAppearanceLightNavigationBars() , true : 将导航栏的前景色变为浅色。 flase : 回复到默认颜色。

WindowInsetsControllerCompat windowInsetsController =
    ViewCompat.getWindowInsetsController(getWindow().getDecorView());
if (windowInsetsController == null) {
    return;
}

windowInsetsController.setAppearanceLightNavigationBars(true);

Step3: 使用插图处理重叠

(以下主要是对重叠部分做了处理)

在实现了边到边的布局后,应用程序的一些试图可能会绘制在系统栏后面。造成视觉重叠。

  • System bars insets
  • System gesture insets

\

为了避免在手势模式或按钮模式中由边缘到边缘引起的这种视觉重叠,可以通过使用 getInsets(int) 和 WindowInsetsCompat.Type.systemBars().

gesture navigation mode, as shown in figures 7 and 8

Figure 7: Resolving visual overlap for button modes

Figure 8: Resolving visual overlap for gesture navigation mode (right)

ViewCompat.setOnApplyWindowInsetsListener(view, (v, windowInsets) -> {
  Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
  // Apply the insets as a margin to the view. Here the system is setting
  // only the bottom, left, and right dimensions, but apply whichever insets are
  // appropriate to your layout. You can also update the view padding
  // if that's more appropriate.
  MarginLayoutParams mlp = (MarginLayoutParams) v.getLayoutParams();
  mlp.leftMargin = insets.left;
  mlp.bottomMargin = insets.bottom;
  mlp.rightMargin = insets.right;
  v.setLayoutParams(mlp);

  // Return CONSUMED if you don't want want the window insets to keep being
  // passed down to descendant views.
    return WindowInsetsCompat.CONSUMED;
});

System gesture insets

系统手势插页表示窗口的区域,系统手势优先于应用程序。

\

使用这些插图可以将可滑动试图从边缘移开,常见的用例包括 底部表格、游戏中的滑动和使用 ViewPager 实现的 carousels

On Android 10 or higher, system gesture insets contain a bottom inset for the home gesture, and a left and right inset for the back gestures:

\

ViewCompat.setOnApplyWindowInsetsListener(view, (v, windowInsets) -> {
    Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemGestures());
    // Apply the insets as padding to the view. Here we're setting all of the
    // dimensions, but apply as appropriate to your layout. You could also
    // update the views margin if more appropriate.
    view.setPadding(insets.left, insets.top, insets.right, insets.bottom);

    // Return CONSUMED if we don't want the window insets to keep being passed
    // down to descendant views.
    return WindowInsetsCompat.CONSUMED;
});

Step 4: 沉浸模式

WindowInsetsControllerWindowInsetsControllerCompat

WindowInsetsControllerCompat windowInsetsController =
      ViewCompat.getWindowInsetsController(getWindow().getDecorView());
if (windowInsetsController == null) {
    return;
  }
// Hide the system bars.
windowInsetsController.hide(WindowInsetsCompat.Type.systemBars());

// Show the system bars.
windowInsetsController.show(WindowInsetsCompat.Type.systemBars());
```**