Slide 1

Slide 1 text

BECOMING A MASTER WINDOW FITTER @chrisbanes

Slide 2

Slide 2 text

BECOMING A MASTER WINDOW FITTER chris.banes.me/windowfitter

Slide 3

Slide 3 text

What’s a window?

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

12:00

Slide 6

Slide 6 text

12:00

Slide 7

Slide 7 text

12:00

Slide 8

Slide 8 text

Window Every view on screen is in a Window Key event handling Touch event handling Window decor Can think of it as a fancy ViewGroup

Slide 9

Slide 9 text

12:00 Window

Slide 10

Slide 10 text

12:00 Activity Window Activities have a Window Activity#getWindow()

Slide 11

Slide 11 text

12:00 Window Activity Dialogs have a Window too Dialog#getWindow() Dialog

Slide 12

Slide 12 text

12:00 Window Activity Dialogs have a Window too Dialog#getWindow() Dialog

Slide 13

Slide 13 text

12:00 Activity

Slide 14

Slide 14 text

12:00 Activity Activity

Slide 15

Slide 15 text

Why do I have to
 fit them?

Slide 16

Slide 16 text

12:00

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

S

Slide 19

Slide 19 text

No content

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

No content

Slide 22

Slide 22 text

No content

Slide 23

Slide 23 text

No content

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

No content

Slide 26

Slide 26 text

Inset

Slide 27

Slide 27 text

Inset How the system tells you where the system ui currently is, or may later be displayed

Slide 28

Slide 28 text

BECOMING A MASTER WINDOW FITTER History

Slide 29

Slide 29 text

Pre-KitKat

Slide 30

Slide 30 text

Pre-KitKat

Slide 31

Slide 31 text

Pre-KitKat Window is placed in between system bars

Slide 32

Slide 32 text

Pre-KitKat setSystemUiVisibility() Window is placed in between system bars

Slide 33

Slide 33 text

setSystemUiVisibility()

Slide 34

Slide 34 text

SYSTEM_UI_FLAG_VISIBLE SYSTEM_UI_FLAG_LOW_PROFILE SYSTEM_UI_FLAG_HIDE_NAVIGATION SYSTEM_UI_FLAG_FULLSCREEN SYSTEM_UI_FLAG_IMMERSIVE_STICKY SYSTEM_UI_FLAG_IMMERSIVE SYSTEM_UI_FLAG_LIGHT_STATUS_BAR SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR SYSTEM_UI_FLAG_LAYOUT_STABLE SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN

Slide 35

Slide 35 text

SYSTEM_UI_FLAG_VISIBLE SYSTEM_UI_FLAG_LOW_PROFILE SYSTEM_UI_FLAG_HIDE_NAVIGATION SYSTEM_UI_FLAG_FULLSCREEN SYSTEM_UI_FLAG_IMMERSIVE_STICKY SYSTEM_UI_FLAG_IMMERSIVE SYSTEM_UI_FLAG_LIGHT_STATUS_BAR SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR SYSTEM_UI_FLAG_LAYOUT_STABLE SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN

Slide 36

Slide 36 text

SYSTEM_UI_FLAG_VISIBLE SYSTEM_UI_FLAG_LOW_PROFILE SYSTEM_UI_FLAG_HIDE_NAVIGATION SYSTEM_UI_FLAG_FULLSCREEN SYSTEM_UI_FLAG_IMMERSIVE_STICKY SYSTEM_UI_FLAG_IMMERSIVE SYSTEM_UI_FLAG_LIGHT_STATUS_BAR SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR SYSTEM_UI_FLAG_LAYOUT_STABLE SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN

Slide 37

Slide 37 text

SYSTEM_UI_FLAG_VISIBLE SYSTEM_UI_FLAG_LOW_PROFILE SYSTEM_UI_FLAG_HIDE_NAVIGATION SYSTEM_UI_FLAG_FULLSCREEN SYSTEM_UI_FLAG_IMMERSIVE_STICKY SYSTEM_UI_FLAG_IMMERSIVE SYSTEM_UI_FLAG_LIGHT_STATUS_BAR SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR SYSTEM_UI_FLAG_LAYOUT_STABLE SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN chris.banes.me/systemuihelper

Slide 38

Slide 38 text

SYSTEM_UI_FLAG_VISIBLE SYSTEM_UI_FLAG_LOW_PROFILE SYSTEM_UI_FLAG_HIDE_NAVIGATION SYSTEM_UI_FLAG_FULLSCREEN SYSTEM_UI_FLAG_IMMERSIVE_STICKY SYSTEM_UI_FLAG_IMMERSIVE SYSTEM_UI_FLAG_LIGHT_STATUS_BAR SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR SYSTEM_UI_FLAG_LAYOUT_STABLE SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN

Slide 39

Slide 39 text

SYSTEM_UI_FLAG_VISIBLE SYSTEM_UI_FLAG_LOW_PROFILE SYSTEM_UI_FLAG_HIDE_NAVIGATION SYSTEM_UI_FLAG_FULLSCREEN SYSTEM_UI_FLAG_IMMERSIVE_STICKY SYSTEM_UI_FLAG_IMMERSIVE SYSTEM_UI_FLAG_LIGHT_STATUS_BAR SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR SYSTEM_UI_FLAG_LAYOUT_STABLE SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN

Slide 40

Slide 40 text

indow lag W F ransform T s View.SYSTEM_UI_FLAG_LAYOUT_STABLE View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or

Slide 41

Slide 41 text

W F T s View.SYSTEM_UI_FLAG_LAYOUT_STABLE View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or

Slide 42

Slide 42 text

myView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN

Slide 43

Slide 43 text

myView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN

Slide 44

Slide 44 text

KitKat

Slide 45

Slide 45 text

KitKat

Slide 46

Slide 46 text

KitKat Translucent system bars

Slide 47

Slide 47 text

KitKat Translucent system bars

Slide 48

Slide 48 text

KitKat Translucent system bars android:windowTranslucentStatus android:windowTranslucentNavigation

Slide 49

Slide 49 text

Translucent system bars WTFs are implied KitKat

Slide 50

Slide 50 text

Translucent system bars WTFs are implied System bar backgrounds are drawn by WindowManager KitKat

Slide 51

Slide 51 text

Lollipop

Slide 52

Slide 52 text

Lollipop

Slide 53

Slide 53 text

Lollipop android:windowDrawsSystemBarBackgrounds System bar backgrounds are placed in Window

Slide 54

Slide 54 text

No content

Slide 55

Slide 55 text

android:statusBarColor getWindow().setStatusBarColor()

Slide 56

Slide 56 text

android:navigationBarColor getWindow().setNavigationBarColor()

Slide 57

Slide 57 text

Lollipop WTFs are not implied

Slide 58

Slide 58 text

Lollipop They take precedence over custom colors Translucent system bars They disable windowDrawsSystemBarBackgrounds

Slide 59

Slide 59 text

BECOMING A MASTER WINDOW FITTER How can you handle this?

Slide 60

Slide 60 text

android:fitSystemWindows="true"

Slide 61

Slide 61 text

android:fitSystemWindows="true" Default View.java behavior: Uses padding to move content within insets

Slide 62

Slide 62 text

12:00

Slide 63

Slide 63 text

12:00 android:fitSystemWindows="true"

Slide 64

Slide 64 text

12:00 android:fitSystemWindows="true" systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN

Slide 65

Slide 65 text

12:00 android:fitSystemWindows="true" systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN

Slide 66

Slide 66 text

12:00 android:fitSystemWindows="true" systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN

Slide 67

Slide 67 text

12:00 android:fitSystemWindows="true" systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN Padding Padding

Slide 68

Slide 68 text

Rule of thumb You probably want to avoid the default behavior of android:fitSystemWindows

Slide 69

Slide 69 text

But the docs say to use it?!

Slide 70

Slide 70 text

But the docs say to use it?! DrawerLayout CoordinatorLayout AppBarLayout CollapsingToolbarLayout

Slide 71

Slide 71 text

DrawerLayout Sets the WTFs for you on API 21+ 12:00

Slide 72

Slide 72 text

12:00 
 >

Slide 73

Slide 73 text

12:00 > fitSystemWindows="true" 


Slide 74

Slide 74 text

12:00 fitSystemWindows="true">

Slide 75

Slide 75 text

DrawerLayout 12:00 Uses fitSystemWindows as a signal from children Sets the WTFs for you on API 21+

Slide 76

Slide 76 text

12:00 fitSystemWindows="true"> />

Slide 77

Slide 77 text

12:00 fitSystemWindows="true"> />

Slide 78

Slide 78 text

fitSystemWindows="true"> /> fitSystemWindows="true" 12:00

Slide 79

Slide 79 text

fitSystemWindows="true"> /> fitSystemWindows="true" 12:00

Slide 80

Slide 80 text

fitSystemWindows="true"> /> fitSystemWindows="true" 12:00

Slide 81

Slide 81 text

fitSystemWindows="true"> /> fitSystemWindows="true" 12:00

Slide 82

Slide 82 text

fitSystemWindows="true"> /> fitSystemWindows="true" 12:00

Slide 83

Slide 83 text

fitSystemWindows="true"> /> fitSystemWindows="true" > 12:00

Slide 84

Slide 84 text

fitSystemWindows="true"> /> fitSystemWindows="true" fitSystemWindows="true"> 12:00

Slide 85

Slide 85 text

fitSystemWindows="true"> /> fitSystemWindows="true" 12:00 fitSystemWindows="true">

Slide 86

Slide 86 text

12:00 fitSystemWindows="true"> fitSystemWindows="true"> /> fitSystemWindows="true"

Slide 87

Slide 87 text

CoordinatorLayout + AppBarLayout + CollapsingToolbarLayout

Slide 88

Slide 88 text

12:00 CoordinatorLayout + AppBarLayout + CollapsingToolbarLayout Uses fitSystemWindows as a signal from children Sets the WTFs for you on API 21+

Slide 89

Slide 89 text

Slide 90

Slide 90 text

Slide 91

Slide 91 text

BECOMING A MASTER WINDOW FITTER Manual handling

Slide 92

Slide 92 text

BECOMING A MASTER WINDOW FITTER What not to do…

Slide 93

Slide 93 text

Fixed dimension for status bar What not to do…

Slide 94

Slide 94 text

24dp

Slide 95

Slide 95 text

24dp res/values-v23 25dp res/values

Slide 96

Slide 96 text

What if the status bar size changes?

Slide 97

Slide 97 text

Slide 98

Slide 98 text

No content

Slide 99

Slide 99 text

What happens if devices have different status bar sizes?

Slide 100

Slide 100 text

53dp 24dp

Slide 101

Slide 101 text

Retrieve internal system resources What not to do…

Slide 102

Slide 102 text

192dp 192dp 60% 240 48dip 64dip 24dp 48dp 48dp 48dp frameworks/base/core/res/values/dimens.xml

Slide 103

Slide 103 text

frameworks/base/core/res/values/dimens.xml 192dp 192dp 60% 240 48dip 64dip 24dp 48dp 48dp 48dp

Slide 104

Slide 104 text

var resourceId = resources.getIdentifier(
 "status_bar_height", "dimen", "android")
 return resources.getDimensionPixelSize(resourceId)

Slide 105

Slide 105 text

What happens if the internal resource name changes?

Slide 106

Slide 106 text

No content

Slide 107

Slide 107 text

What if the device does not let you draw behind the status bar?

Slide 108

Slide 108 text

No content

Slide 109

Slide 109 text

No content

Slide 110

Slide 110 text

No content

Slide 111

Slide 111 text

BECOMING A MASTER WINDOW FITTER The supported way: WindowInsets

Slide 112

Slide 112 text

BECOMING A MASTER WINDOW FITTER WindowInsets getSystemWindowInsetLeft() getSystemWindowInsetTop() getSystemWindowInsetRight() getSystemWindowInsetBottom()

Slide 113

Slide 113 text

BECOMING A MASTER WINDOW FITTER WindowInsetsCompat getSystemWindowInsetLeft() getSystemWindowInsetTop() getSystemWindowInsetRight() getSystemWindowInsetBottom()

Slide 114

Slide 114 text

12:00 getSystemWindowInsetLeft() getSystemWindowInsetTop() getSystemWindowInsetRight() getSystemWindowInsetBottom()

Slide 115

Slide 115 text

12:00 getSystemWindowInsetLeft() getSystemWindowInsetTop() getSystemWindowInsetRight() getSystemWindowInsetBottom() 0

Slide 116

Slide 116 text

12:00 getSystemWindowInsetLeft() getSystemWindowInsetTop() getSystemWindowInsetRight() getSystemWindowInsetBottom() 72 0

Slide 117

Slide 117 text

12:00 getSystemWindowInsetLeft() getSystemWindowInsetTop() getSystemWindowInsetRight() getSystemWindowInsetBottom() 72 0 0

Slide 118

Slide 118 text

12:00 getSystemWindowInsetLeft() getSystemWindowInsetTop() getSystemWindowInsetRight() getSystemWindowInsetBottom() 144 72 0 0

Slide 119

Slide 119 text

BECOMING A MASTER WINDOW FITTER myView.setOnApplyWindowInsetsListener { view, insets -> // TODO handle insets return insets.consumeSystemWindowInsets() }

Slide 120

Slide 120 text

BECOMING A MASTER WINDOW FITTER ViewCompat.setOnApplyWindowInsetsListener(view) { view, insets -> // TODO handle insets return insets.consumeSystemWindowInsets() }

Slide 121

Slide 121 text

BECOMING A MASTER WINDOW FITTER class CustomLayout : LinearLayout { // yadda yadda override fun onApplyWindowInsets( insets: WindowInsets): WindowInsets { // TODO handle the insets return insets.consumeSystemWindowInsets() } }

Slide 122

Slide 122 text

BECOMING A MASTER WINDOW FITTER class CustomLayout : LinearLayout { // yadda yadda override fun onApplyWindowInsets( insets: WindowInsets): WindowInsets { // TODO handle the insets return insets.consumeSystemWindowInsets() } }

Slide 123

Slide 123 text

BECOMING A MASTER WINDOW FITTER WindowInsets will be passed down until it has been consumed

Slide 124

Slide 124 text

BECOMING A MASTER WINDOW FITTER Window Decor LinearLayout Child Child dispatchApplyWindowInsets()

Slide 125

Slide 125 text

BECOMING A MASTER WINDOW FITTER Window Decor dispatchApplyWindowInsets() LinearLayout Child Child

Slide 126

Slide 126 text

BECOMING A MASTER WINDOW FITTER Window Decor LinearLayout Child Child Left: Top: Right: Bottom: 0 72 0 144 dispatchApplyWindowInsets()

Slide 127

Slide 127 text

BECOMING A MASTER WINDOW FITTER Window Decor LinearLayout Child Child Left: Top: Right: Bottom: 0 72 0 144 onApplyWindowInsets()

Slide 128

Slide 128 text

BECOMING A MASTER WINDOW FITTER Window Decor LinearLayout Child Child Left: Top: Right: Bottom: 0 0 0 144 onApplyWindowInsets() Consumes top

Slide 129

Slide 129 text

BECOMING A MASTER WINDOW FITTER Window Decor Child Child LinearLayout WindowInsets.isConsumed() Left: Top: Right: Bottom: 0 0 0 144 false

Slide 130

Slide 130 text

BECOMING A MASTER WINDOW FITTER Child Window Decor Child LinearLayout dispatchApplyWindowInsets() Left: Top: Right: Bottom: 0 0 0 144

Slide 131

Slide 131 text

BECOMING A MASTER WINDOW FITTER Window Decor LinearLayout Child Child Left: Top: Right: Bottom: 0 0 0 144 onApplyWindowInsets()

Slide 132

Slide 132 text

BECOMING A MASTER WINDOW FITTER Window Decor LinearLayout Child Child Left: Top: Right: Bottom: 0 0 0 144 WindowInsets.isConsumed() false

Slide 133

Slide 133 text

BECOMING A MASTER WINDOW FITTER Window Decor LinearLayout Child Child dispatchApplyWindowInsets() Left: Top: Right: Bottom: 0 0 0 144

Slide 134

Slide 134 text

BECOMING A MASTER WINDOW FITTER Window Decor LinearLayout Child Child Left: Top: Right: Bottom: 0 0 0 144 onApplyWindowInsets()

Slide 135

Slide 135 text

BECOMING A MASTER WINDOW FITTER Window Decor LinearLayout Child Child Left: Top: Right: Bottom: 0 0 0 0 WindowInsets.isConsumed() true

Slide 136

Slide 136 text

BECOMING A MASTER WINDOW FITTER Scenarios

Slide 137

Slide 137 text

BECOMING A MASTER WINDOW FITTER I just want to ing draw behind the status bar!

Slide 138

Slide 138 text

DrawerLayout setStatusBackground() Default to ?android:colorPrimaryDark When fitSystemWindows=true

Slide 139

Slide 139 text

CoordinatorLayout setStatusBackground() Default to ?android:colorPrimaryDark When fitSystemWindows=true app:statusBarBackground

Slide 140

Slide 140 text

CollapsingToolbarLayout contentScrim statusBarScrim

Slide 141

Slide 141 text

CollapsingToolbarLayout When fitSystemWindows=true Defaults to @null app:contentScrim Defaults to ?android:colorPrimaryDark app:statusBarScrim

Slide 142

Slide 142 text

No content

Slide 143

Slide 143 text

No content

Slide 144

Slide 144 text

No content

Slide 145

Slide 145 text

No content

Slide 146

Slide 146 text

e 
 


Slide 147

Slide 147 text

e

Slide 148

Slide 148 text

e

Slide 149

Slide 149 text

e

Slide 150

Slide 150 text

e

Slide 151

Slide 151 text

No content

Slide 152

Slide 152 text

No content

Slide 153

Slide 153 text

No content

Slide 154

Slide 154 text

No content

Slide 155

Slide 155 text

android:fitSystemWindows="true" Uses padding to move content within insets Default View.java behavior:

Slide 156

Slide 156 text

Need to tell CoodinatorLayout to lay out within the insets android:fitSystemWindows="true"

Slide 157

Slide 157 text

Need to tell CoodinatorLayout to lay out within the insets but we also want to stop the default padding android:fitSystemWindows="true" Erm… "

Slide 158

Slide 158 text

val header = findViewById(R.id.header_image) header.setOnApplyWindowInsetsListener { v, insets -> insets }

Slide 159

Slide 159 text

If an OnApplyWindowInsetsListener is set, its onApplyWindowInsets method will be called instead of the View's own onApplyWindowInsets method. “

Slide 160

Slide 160 text

No content

Slide 161

Slide 161 text

val header = findViewById(R.id.header_image) header.setOnApplyWindowInsetsListener { v, insets -> }A insets

Slide 162

Slide 162 text

val header = findViewById(R.id.header_image) header.setOnApplyWindowInsetsListener { v, insets -> }A v.onApplyWindowInsets( ) insets

Slide 163

Slide 163 text

No content

Slide 164

Slide 164 text

BECOMING A MASTER WINDOW FITTER TL;DW

Slide 165

Slide 165 text

BECOMING A MASTER WINDOW FITTER If you’re using DrawerLayout or CoordinatorLayout Use android:fitSystemWindows="true" on direct children which you want to be displayed behind the system bars

Slide 166

Slide 166 text

BECOMING A MASTER WINDOW FITTER Avoid translucent system bars #80000000 #80000000

Slide 167

Slide 167 text

BECOMING A MASTER WINDOW FITTER If you need to get access to the status bar size myView.setOnApplyWindowInsetsListener { view, insets -> val statusBarSize = insets.systemWindowInsetTop return insets }

Slide 168

Slide 168 text

BECOMING A MASTER WINDOW FITTER Repeat once per week I will never store or retrieve the status bar size from resources ever again

Slide 169

Slide 169 text

Over and out… @chrisbanes