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

Becoming a master window fitter (Droidcon London 2017)

Chris Banes
October 27, 2017

Becoming a master window fitter (Droidcon London 2017)

Window insets have long been a source of confusion to developers, and that’s because they are indeed very confusing! The system dispatches insets for many reasons, such as drawing behind navigation bars, full-screen immersive modes or handling round displays.

This session will deep-dive on the situations where you need to consider Window Insets, and how you can handle them without resorting to copying random code from StackOverflow. You will learn the answers to questions such as:

‘How do I handle these in my custom view?’, ‘How do I draw behind the status bar?’ and ‘What was the developer of AppBarLayout thinking?!’

Video: https://chris.banes.me/talks/2017/becoming-a-master-window-fitter-lon/

Chris Banes

October 27, 2017
Tweet

More Decks by Chris Banes

Other Decks in Technology

Transcript

  1. BECOMING A MASTER
    WINDOW FITTER
    @chrisbanes

    View Slide

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

    View Slide

  3. What’s a window?

    View Slide

  4. View Slide

  5. 12:00

    View Slide

  6. 12:00

    View Slide

  7. 12:00

    View Slide

  8. 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

    View Slide

  9. 12:00
    Window

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  13. 12:00
    Activity

    View Slide

  14. 12:00
    Activity Activity

    View Slide

  15. Why do I have to

    fit them?

    View Slide

  16. 12:00

    View Slide

  17. View Slide

  18. S

    View Slide

  19. View Slide

  20. View Slide

  21. View Slide

  22. View Slide

  23. View Slide

  24. View Slide

  25. View Slide

  26. Inset

    View Slide

  27. Inset
    How the system tells you where the

    system ui currently is, or may later

    be displayed

    View Slide

  28. BECOMING A MASTER WINDOW FITTER
    History

    View Slide

  29. Pre-KitKat

    View Slide

  30. Pre-KitKat

    View Slide

  31. Pre-KitKat
    Window is placed in between system bars

    View Slide

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

    View Slide

  33. setSystemUiVisibility()

    View Slide

  34. 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

    View Slide

  35. 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

    View Slide

  36. 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

    View Slide

  37. 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

    View Slide

  38. 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

    View Slide

  39. 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

    View Slide

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

    View Slide

  41. W F
    T s
    View.SYSTEM_UI_FLAG_LAYOUT_STABLE
    View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
    or

    View Slide

  42. myView.systemUiVisibility =
    View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
    View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN

    View Slide

  43. myView.systemUiVisibility =
    View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
    View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN

    View Slide

  44. KitKat

    View Slide

  45. KitKat

    View Slide

  46. KitKat
    Translucent system bars

    View Slide

  47. KitKat
    Translucent system bars

    View Slide

  48. KitKat
    Translucent system bars
    android:windowTranslucentStatus
    android:windowTranslucentNavigation

    View Slide

  49. Translucent system bars
    WTFs are implied
    KitKat

    View Slide

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

    View Slide

  51. Lollipop

    View Slide

  52. Lollipop

    View Slide

  53. Lollipop
    android:windowDrawsSystemBarBackgrounds
    System bar backgrounds are placed in
    Window

    View Slide

  54. View Slide

  55. android:statusBarColor
    getWindow().setStatusBarColor()

    View Slide

  56. android:navigationBarColor
    getWindow().setNavigationBarColor()

    View Slide

  57. Lollipop
    WTFs are not implied

    View Slide

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

    View Slide

  59. BECOMING A MASTER WINDOW FITTER
    How can you handle this?

    View Slide

  60. android:fitSystemWindows="true"

    View Slide

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

    View Slide

  62. 12:00

    View Slide

  63. 12:00
    android:fitSystemWindows="true"

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  68. Rule of thumb
    You probably want to avoid the default

    behavior of android:fitSystemWindows

    View Slide

  69. But the docs say to use it?!

    View Slide

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

    View Slide

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

    View Slide

  72. 12:00
    layout_height="match_parent"
    layout_width="match_parent"
    layout_height="match_parent"
    layout_width="match_parent"

    layout_gravity="end" />
    layout_height="match_parent"
    layout_width="match_parent">




    >

    View Slide

  73. 12:00
    >
    fitSystemWindows="true"
    layout_height="match_parent"
    layout_width="match_parent"
    layout_height="match_parent"
    layout_width="match_parent"

    layout_gravity="end" />
    layout_height="match_parent"
    layout_width="match_parent">




    View Slide

  74. layout_height="match_parent"
    layout_width="match_parent"
    layout_height="match_parent"
    layout_width="match_parent"

    layout_gravity="end" />
    layout_height="match_parent"
    layout_width="match_parent">



    12:00
    fitSystemWindows="true">

    View Slide

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

    View Slide

  76. 12:00
    layout_height="match_parent"
    layout_width="match_parent"
    layout_height="match_parent"
    layout_width="match_parent"

    layout_gravity="end"
    layout_height="match_parent"
    layout_width="match_parent">



    fitSystemWindows="true">
    />

    View Slide

  77. 12:00
    layout_height="match_parent"
    layout_width="match_parent"
    layout_height="match_parent"
    layout_width="match_parent"

    layout_gravity="end"
    layout_height="match_parent"
    layout_width="match_parent">



    fitSystemWindows="true">
    />

    View Slide

  78. layout_height="match_parent"
    layout_width="match_parent"
    layout_height="match_parent"
    layout_width="match_parent"

    layout_gravity="end"
    layout_height="match_parent"
    layout_width="match_parent">



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

    View Slide

  79. layout_height="match_parent"
    layout_width="match_parent"
    layout_height="match_parent"
    layout_width="match_parent"

    layout_gravity="end"
    layout_height="match_parent"
    layout_width="match_parent">



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

    View Slide

  80. layout_height="match_parent"
    layout_width="match_parent"
    layout_height="match_parent"
    layout_width="match_parent"

    layout_gravity="end"
    layout_height="match_parent"
    layout_width="match_parent">



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

    View Slide

  81. fitSystemWindows="true">
    />
    fitSystemWindows="true"
    layout_height="match_parent"
    layout_width="match_parent"
    layout_height="match_parent"
    layout_width="match_parent"

    layout_gravity="end"
    layout_height="match_parent"
    layout_width="match_parent">



    12:00

    View Slide

  82. fitSystemWindows="true">
    />
    fitSystemWindows="true"
    layout_height="match_parent"
    layout_width="match_parent"
    layout_height="match_parent"
    layout_width="match_parent"

    layout_gravity="end"
    layout_height="match_parent"
    layout_width="match_parent">



    12:00

    View Slide

  83. fitSystemWindows="true">
    />
    fitSystemWindows="true"
    layout_height="match_parent"
    layout_width="match_parent"
    layout_height="match_parent"
    layout_width="match_parent"

    layout_gravity="end"
    layout_height="match_parent"
    layout_width="match_parent"



    >
    12:00

    View Slide

  84. fitSystemWindows="true">
    />
    fitSystemWindows="true"
    layout_height="match_parent"
    layout_width="match_parent"
    layout_height="match_parent"
    layout_width="match_parent"

    layout_gravity="end"
    layout_height="match_parent"
    layout_width="match_parent"



    fitSystemWindows="true">
    12:00

    View Slide

  85. fitSystemWindows="true">
    />
    fitSystemWindows="true"
    layout_height="match_parent"
    layout_width="match_parent"
    layout_height="match_parent"
    layout_width="match_parent"

    layout_gravity="end"
    layout_height="match_parent"
    layout_width="match_parent"



    12:00
    fitSystemWindows="true">

    View Slide

  86. layout_height="match_parent"
    layout_width="match_parent"
    layout_height="match_parent"
    layout_width="match_parent"

    layout_gravity="end"
    layout_height="match_parent"
    layout_width="match_parent"



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

    View Slide

  87. CoordinatorLayout
    + AppBarLayout + CollapsingToolbarLayout

    View Slide

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

    View Slide

  89. layout_height="match_parent"
    layout_width="match_parent">
    layout_height="match_parent"
    layout_width="wrap_content" />

    id="@+id/poster" />



    View Slide

  90. layout_height="match_parent"
    layout_width="match_parent"
    fitSystemWindows="true">
    layout_height="match_parent"
    layout_width="wrap_content"
    fitSystemWindows="true" />
    fitSystemWindows="true">
    id="@+id/poster"
    fitSystemWindows="true" />



    View Slide

  91. BECOMING A MASTER WINDOW FITTER
    Manual handling

    View Slide

  92. BECOMING A MASTER WINDOW FITTER
    What not to do…

    View Slide

  93. Fixed dimension for status bar
    What not to do…

    View Slide


  94. 24dp

    View Slide


  95. 24dp

    res/values-v23

    25dp

    res/values

    View Slide

  96. What if the status bar size changes?

    View Slide


  97. View Slide

  98. View Slide

  99. What happens if devices have
    different status bar sizes?

    View Slide

  100. 53dp
    24dp

    View Slide

  101. Retrieve internal system

    resources
    What not to do…

    View Slide



  102. 192dp

    192dp

    60%

    240

    48dip
    64dip

    24dp

    48dp

    48dp

    48dp

    frameworks/base/core/res/values/dimens.xml

    View Slide

  103. frameworks/base/core/res/values/dimens.xml


    192dp

    192dp

    60%

    240

    48dip
    64dip

    24dp

    48dp

    48dp

    48dp

    View Slide

  104. var resourceId = resources.getIdentifier(

    "status_bar_height", "dimen", "android")

    return resources.getDimensionPixelSize(resourceId)

    View Slide

  105. What happens if the internal

    resource name changes?

    View Slide

  106. View Slide

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

    View Slide

  108. View Slide

  109. View Slide

  110. View Slide

  111. BECOMING A MASTER WINDOW FITTER
    The supported way: WindowInsets

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  123. BECOMING A MASTER WINDOW FITTER
    WindowInsets will be passed down until

    it has been consumed

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  136. BECOMING A MASTER WINDOW FITTER
    Scenarios

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  140. CollapsingToolbarLayout
    contentScrim
    statusBarScrim

    View Slide

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

    View Slide

  142. View Slide

  143. View Slide

  144. View Slide

  145. View Slide

  146. android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    app:statusBarBackground="@color/statusbar_scrim">e

    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:adjustViewBounds="true"
    android:fitsSystemWindows="true"
    android:src="@drawable/header" />

    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:elevation="@dimen/elevation_toolbar"
    android:theme="@style/ThemeOverlay.AppCompat.Dark"
    app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

    View Slide

  147. android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">e
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:fitsSystemWindows="true"
    android:src="@drawable/header" />
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

    View Slide

  148. android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">e
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:fitsSystemWindows="true"
    android:src="@drawable/header" />
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

    View Slide

  149. android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">e
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:fitsSystemWindows="true"
    android:src="@drawable/header" />
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

    View Slide

  150. android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">e
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:fitsSystemWindows="true"
    android:src="@drawable/header" />
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

    View Slide

  151. View Slide

  152. View Slide

  153. View Slide

  154. View Slide

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

    View Slide

  156. Need to tell CoodinatorLayout to lay out

    within the insets
    android:fitSystemWindows="true"

    View Slide

  157. Need to tell CoodinatorLayout to lay out

    within the insets
    but we also want to stop the default
    padding
    android:fitSystemWindows="true"
    Erm… "

    View Slide

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

    View Slide

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

    View Slide

  160. View Slide

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

    View Slide

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

    View Slide

  163. View Slide

  164. BECOMING A MASTER WINDOW FITTER
    TL;DW

    View Slide

  165. 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

    View Slide

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

    View Slide

  167. 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
    }

    View Slide

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

    View Slide

  169. Over and out…
    @chrisbanes

    View Slide