Slide 1

Slide 1 text

Practical “edge-to-edge” Explanation of “edge to edge” Yuki Ando / LINE Corporation 2022.10

Slide 2

Slide 2 text

DO YOU KNOW WHAT “EDGE-TO-EDGE” IS?

Slide 3

Slide 3 text

DO YOU KNOW WHAT “EDGE-TO-EDGE” IS?

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

HOW MANY APPS DO YOU THINK APPLY “EDGE TO EDGE”?

Slide 6

Slide 6 text

PROBABLY, NOT MANY 🤔

Slide 7

Slide 7 text

NOT ALL OS PRE-INSTALLED APPS ARE SUPPORTED EITHER😇

Slide 8

Slide 8 text

Official Policy Guidelines of LINE Android Client Implementations Problems and Pitfalls 01 02 03 04 Contents 8

Slide 9

Slide 9 text

Official Policy Guidelines of LINE Android Client Implementations Problems and Pitfalls 01 02 03 04 Contents 9

Slide 10

Slide 10 text

Status
 bar Navigation bar Insets Official “edge-to-edge” application policy 10

Slide 11

Slide 11 text

Policy: Navigation Bar 11 Overlap the contents Figure 2: Overlap the contents in button navigation bar

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

Policy: Insets 14

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

Official Policy Guidelines of LINE Android Client Implementations Problems and Pitfalls 01 02 03 04 Contents 17

Slide 18

Slide 18 text

GUIDELINES OF LINE ANDROID CLIENT

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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:

Slide 21

Slide 21 text

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 }

Slide 22

Slide 22 text

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 }

Slide 23

Slide 23 text

Official Policy Guidelines of LINE Android Client Implementations Problems and Pitfalls 01 02 03 04 Contents 23

Slide 24

Slide 24 text

IMPLEMENTATIONS

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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 @android:color/transparent @android:color/transparent true OR

Slide 27

Slide 27 text

02.Set “setDecorFitsSystemWindows” to false 27 // In activity WindowCompat.setDecorFitsSystemWindows(window, false)

Slide 28

Slide 28 text

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 }

Slide 29

Slide 29 text

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())

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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 @android:color/transparent @android:color/transparent true OR

Slide 32

Slide 32 text

02.Set “setDecorFitsSystemWindows” to false 32 // In activity WindowCompat.setDecorFitsSystemWindows(window, false)

Slide 33

Slide 33 text

03.Using Modifier extension functions 33 Box( modifier = Modifier .fillMaxSize() .background(Color(0x00000000)) ) { Box( modifier = Modifier .fillMaxSize() .windowInsetsPadding(WindowInsets.safeDrawing) .background(Color(0x00000000)) ) }

Slide 34

Slide 34 text

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 }

Slide 35

Slide 35 text

Official Policy Guidelines of LINE Android Client Implementations Problems and Pitfalls 01 02 03 04 Contents 35

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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?

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

Handle “fitsSystemWindows” 45 override fun onAttachedToWindow() { super.onAttachedToWindow() // ...snip if (shouldOverlapSystemBars) { findViewById(R.id.container)?.fitsSystemWindows = false findViewById(R.id.coordinator)?.fitsSystemWindows = false } // ...snip }

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

SUMMARY

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

LET'S APPLY IT FROM EDGE TO EDGE!

Slide 52

Slide 52 text

THANK YOU

Slide 53

Slide 53 text

No content