Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Practical “edge-to-edge” Explanation of “edge to edge”

Practical “edge-to-edge” Explanation of “edge to edge”

`edge-to-edge`とはその名の通り、システムの領域も含めた画面の "端から端" を全てアプリの領域として描画する機能です。
Googleはアプリへの没入感を高めるために、この`edge-to-edge`を推奨しています。

`edge-to-edge` を適用するには、アプリの描画が全画面になるようにフラグを設定し、システムバー(ステータスバーとナビゲーションバー)の色を設定するだけでも十分に思われます。
しかし、実際には考慮すべき点や落とし穴があるため一筋縄では適用できません。例えば、既存のアプリに適用する場合は、UIデザインの変更が必要になります。
他にも、Android デバイスによっては、システムバーに対してデバイス固有の変更が施されている場合があり、その対処も簡単ではありません。
本セッションでは、実際にコミュニケーションアプリLINE に`edge-to-edge`を適用した際に得られた知見を元に、以下の内容を紹介します。

・Googleが提唱する`edge-to-edge`の適用ポリシーについて
・UIをデザインする上での`edge-to-edge`の適用基準について
・通常のアプリとJetpack Composeで構成されたアプリそれぞれに対しての適用方法
・LINE Androidアプリに対して`edge-to-edge`を適用する際に発生した問題点・落とし穴やその解決方法について

ぜひ皆さんもこのセッションから`edge-to-edge`の知見を得て、アプリへの適用を実践してみてください!

発表者:Yuki Ando
詳細:https://droidkaigi.jp/2022/timetable/362273

LINE Developers

October 06, 2022
Tweet

More Decks by LINE Developers

Other Decks in Technology

Transcript

  1. Expand the screen to the edge • by overlapping the

    status bar • by overlapping the navigation bar 4 ※1ɿhttps://developer.android.com/develop/ui/views/layout/edge-to-edge Figure 1: System bars with edge-to-edge ※1 Edge-to-edge
  2. Policy: Navigation Bar 11 Overlap the contents Degree of transparency

    depends on bar type Gesture Navigation Transparent Button Navigation Translucent Figure 2: Overlap the contents in button navigation bar Figure 3: Overlap the contents in gesture navigation bar
  3. Policy: Status Bar Overlap only if there is underlaying content

    • Background Image • Camera View • Map View 13 ※1ɿhttps://developer.android.com/develop/ui/views/layout/edge-to-edge Figure 4:Translucent status bar ※1
  4. What are insets? Size of gap between the visible area

    and the UI container • System bars height • Width of the area where the OS accepts gestures • IME Height 15 ※1ɿhttps://developer.android.com/develop/ui/views/layout/edge-to-edge Figure 5:Translucent status bar ※1
  5. Policy: Insets Set padding/margin to resolve conflict between: • Elements

    placed on the edge • Navigation Bar/Status Bar 16 Figure 6: FAB with required padding set Figure 5: FAB without required padding set
  6. Why are the Guidelines required? There are problems: • Difficult

    to overlap on the some screens due to design reasons • Difficult to adjust padding for all screens using insets 19 If not needed, change the background color and do not overlap
  7. Application options Overlap with transparent color 20 Figure 8: Opaque

    color navigation bar Figure 7: Transparent navigation bar No-overlap with opaque color There are two options of application method:
  8. Pseudo Code for Overlap Decision (navigation) 21 fun decideShouldOverlapNavigationBar(): Color

    { if (isDifficultToMakeSafeArea) { return Color.OpaqueColor } if (isThereScrollableViewAtTheBottom) { return Color.TransparentColor } if (isThereOperableViewAtTheBottom || noBackgroundAtTheBottom) { return Color.OpaqueColor } return Color.TransparentColor }
  9. Pseudo Code for Overlap Decision (status) 22 fun decideShouldOverlapStatusBar(): Color

    { if (isDifficultToMakeSafeArea) { return Color.OpaqueColor } if (isThereScrollableViewAtTheTop) { return Color.TransparentColor } if (isThereOperableViewAtTheTop || noBackgroundAtTheTop) { return Color.OpaqueColor } return Color.TransparentColor }
  10. Set the color of the navigation bar and status bar

    Set “setDecorFitsSystemWindows” to false Set padding, margin using “ViewCompat.setOnApplyWindowInsetsListener” Hide the systembars if necessary 01 02 03 04 25 Steps to apply to a regular application
  11. 01.Set the color of the system bars 26 // In

    activity window.navigationBarColor = ContextCompat.getColor(this, R.color.transparent) window.statusBarColor = ContextCompat.getColor(this, R.color.transparent) val windowInsetsController = WindowInsetsControllerCompat(window, rootView) windowInsetsController.isAppearanceLightStatusBars = true <!-- themes.xml --> <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> OR
  12. 03.Set padding, margin using listener 28 // In activity ViewCompat.setOnApplyWindowInsetsListener(targetView)

    { view, windowInsets -> val systemInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) view.updatePadding(bottom = systemInsets.bottom) windowInsets }
  13. 04.Hide the system bars if necessary 29 // In activity

    val windowInsetsController = WindowInsetsControllerCompat(window, targetView) // Hide the system bars. windowInsetsController.hide(WindowInsetsCompat.Type.systemBars()) // Show the system bars. windowInsetsController.show(WindowInsetsCompat.Type.systemBars())
  14. Set the color of the navigation bar and status bar

    Set “setDecorFitsSystemWindows” to false Using Modifier extension functions 01 02 03 30 Steps to apply to a Compose application
  15. 01.Set the color of the system bars 31 // In

    activity window.navigationBarColor = ContextCompat.getColor(this, R.color.transparent) window.statusBarColor = ContextCompat.getColor(this, R.color.transparent) val windowInsetsController = WindowInsetsControllerCompat(window, rootView) windowInsetsController.isAppearanceLightStatusBars = true <!-- themes.xml --> <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> OR
  16. 03.Using Modifier extension functions 33 Box( modifier = Modifier .fillMaxSize()

    .background(Color(0x00000000)) ) { Box( modifier = Modifier .fillMaxSize() .windowInsetsPadding(WindowInsets.safeDrawing) .background(Color(0x00000000)) ) }
  17. 03.Using Modifier extension functions 34 // Same as windowInsetsPadding(WindowInsets.safeDrawing) Box(

    modifier = Modifier .fillMaxSize() .safeDrawingPadding() .background(Color(0x00000000)) ) // Apply padding only partially. TopAppBar( modifier = Modifier.windowInsetsPadding( WindowInsets.safeDrawing.only(WindowInsetsSides.Top) ) ) { // ...snip }
  18. Case 1: Cannot apply in 
 button navigation mode 36

    Specify background color in button navigation Solution Difficulty seeing button navigation on certain devices Problem Button navigation UI differs from device to device Cause
  19. 37 Specify background color in button navigation Solution Difficulty seeing

    button navigation on certain devices Problem Button navigation UI differs from device to device Cause A NEW BUG HAS ARRIVED🥺 Case 1: Cannot apply in 
 button navigation mode
  20. 38 Giving up support during button navigation Solution? Some devices

    are completely blind to button navigation. Problem Theme system with custom OS. Cause Case 1: Cannot apply in 
 button navigation mode
  21. How to detect the current navigation mode 39 val navigationModeResourceId

    = resources.getIdentifier("config_navBarInteractionMode", "integer", "android") .takeIf { it > 0 } val navigationModeInt = try { navigationModeResourceId?.let(resources::getInteger) } catch (_: Resources.NotFoundException) { null } return navigationModeInt == 2 ☠ WARNING
  22. Case 2: Issue when switching 
 the method of application

    in navigation mode There are two problems from Case 1: 40 Problem • Safe-area handling • Setting the navigation bar color
  23. Case 2.1: Safe-area handling 41 Set padding in `onStart` function.

    Solution Padding with Insets is not applied correctly. Problem Set padding in `onCreate` function. Cause
  24. Case 2.2: Setting the navigation bar color 42 Set navigation

    bar background color in `onStart` function Solution Navigation bar background color is not applied correctly Problem Set navigation bar background color in `onCreate` function Cause
  25. Case 3: Device specific issues There are many problems that

    occur only with certain devices: 43 Problem • Mysterious padding is added when navigation mode is changed • Code to change color of navigation bar not working properly • Display cutout processing in landscape mode differs from device to device Not yet fixed as a known issue Solution?
  26. Case 4: BottomSheetDialog issue 44 Create custom class that handles

    `fitsSystemWindows` properly Solution Unintended padding is added in the bottom sheet dialog Problem True is set to `setFitsSystemWindows` on `BottomSheetDialog` Cause
  27. Handle “fitsSystemWindows” 45 override fun onAttachedToWindow() { super.onAttachedToWindow() // ...snip

    if (shouldOverlapSystemBars) { findViewById<View>(R.id.container)?.fitsSystemWindows = false findViewById<View>(R.id.coordinator)?.fitsSystemWindows = false } // ...snip }
  28. Case 5: Another navigation modes 46 Fix navigation mode detection

    Solution Edge-to-edge is not applied with special gesture navigation Problem Different values were used to identify the mode Cause
  29. Detect the current navigation mode 47 val gestureModeValues = setOf(2,

    3) val navigationModeResourceId = resources.getIdentifier("config_navBarInteractionMode", "integer", "android") .takeIf { it > 0 } val navigationModeInt = try { navigationModeResourceId?.let(resources::getInteger) } catch (_: Resources.NotFoundException) { null } return gestureModeValues.contains(navigationModeInt) ☠ WARNING
  30. Case 6: Android theme with App theme 48 Make utility

    class for edge-to-edge Solution Appropriate navigation bar colors are not set for each screen Problem The app has unique and complex theme Cause
  31. Summary • Follow the official policy to apply “edge-to-edge” feature

    • If you cannot comply with official policies, there are more things to consider • Your app experience will be better if you can apply it 50