2323import android .content .res .ColorStateList ;
2424import androidx .appcompat .widget .TintTypedArray ;
2525import android .util .AttributeSet ;
26+ import android .view .Gravity ;
2627import android .view .View ;
28+ import android .view .ViewGroup ;
2729import android .widget .FrameLayout ;
2830import androidx .annotation .AttrRes ;
2931import androidx .annotation .ColorInt ;
3032import androidx .annotation .NonNull ;
3133import androidx .annotation .Nullable ;
3234import androidx .annotation .StyleRes ;
35+ import androidx .coordinatorlayout .widget .CoordinatorLayout ;
36+ import androidx .core .graphics .Insets ;
37+ import androidx .core .view .WindowInsetsCompat ;
3338import com .google .android .material .internal .ThemeEnforcement ;
39+ import com .google .android .material .internal .ViewUtils ;
40+ import com .google .android .material .internal .ViewUtils .RelativePadding ;
3441import com .google .android .material .shape .MaterialShapeDrawable ;
3542import com .google .android .material .shape .ShapeAppearanceModel ;
3643
@@ -47,6 +54,8 @@ public class DockedToolbarLayout extends FrameLayout {
4754
4855 private static final String TAG = DockedToolbarLayout .class .getSimpleName ();
4956 private static final int DEF_STYLE_RES = R .style .Widget_Material3_DockedToolbar ;
57+ private Boolean paddingTopSystemWindowInsets ;
58+ private Boolean paddingBottomSystemWindowInsets ;
5059
5160 public DockedToolbarLayout (@ NonNull Context context ) {
5261 this (context , null );
@@ -88,8 +97,98 @@ public DockedToolbarLayout(
8897
8998 setBackground (materialShapeDrawable );
9099 }
91-
100+
101+ // Reading out if we are handling inset padding, so we can apply it to the content.
102+ if (attributes .hasValue (R .styleable .DockedToolbar_paddingTopSystemWindowInsets )) {
103+ paddingTopSystemWindowInsets =
104+ attributes .getBoolean (R .styleable .DockedToolbar_paddingTopSystemWindowInsets , true );
105+ }
106+ if (attributes .hasValue (R .styleable .DockedToolbar_paddingBottomSystemWindowInsets )) {
107+ paddingBottomSystemWindowInsets =
108+ attributes .getBoolean (R .styleable .DockedToolbar_paddingBottomSystemWindowInsets , true );
109+ }
110+
111+ ViewUtils .doOnApplyWindowInsets (
112+ this ,
113+ new ViewUtils .OnApplyWindowInsetsListener () {
114+ @ NonNull
115+ @ Override
116+ public WindowInsetsCompat onApplyWindowInsets (
117+ View view ,
118+ @ NonNull WindowInsetsCompat insets ,
119+ @ NonNull RelativePadding initialPadding ) {
120+ if (paddingTopSystemWindowInsets != null
121+ && paddingBottomSystemWindowInsets != null
122+ && !paddingTopSystemWindowInsets
123+ && !paddingBottomSystemWindowInsets ) {
124+ return insets ;
125+ }
126+
127+ Insets systemBarInsets = insets .getInsets (WindowInsetsCompat .Type .systemBars ());
128+ Insets cutoutInsets = insets .getInsets (WindowInsetsCompat .Type .displayCutout ());
129+ int bottomInset = systemBarInsets .bottom + cutoutInsets .bottom ;
130+ int topInset = systemBarInsets .top + cutoutInsets .top ;
131+ int bottomPadding = 0 ;
132+ int topPadding = 0 ;
133+
134+ ViewGroup .LayoutParams lp = view .getLayoutParams ();
135+ // If the inset flags are not explicitly set, and the toolbar is inside a
136+ // CoordinatorLayout or a FrameLayout, we can use the gravity
137+ // to ascertain what padding should be automatically added.
138+ if (hasGravity (lp , Gravity .TOP ) && paddingTopSystemWindowInsets == null && getFitsSystemWindows ()) {
139+ topPadding = topInset ;
140+ }
141+ if (hasGravity (lp , Gravity .BOTTOM ) && paddingBottomSystemWindowInsets == null && getFitsSystemWindows ()) {
142+ bottomPadding = bottomInset ;
143+ }
144+
145+ // If paddingTopSystemWindowInsets or paddingBottomSystemWindowInsets is explicitly
146+ // set, then insets should always be applied to the padding.
147+ if (paddingBottomSystemWindowInsets != null ) {
148+ bottomPadding = paddingBottomSystemWindowInsets ? bottomInset : 0 ;
149+ }
150+ if (paddingTopSystemWindowInsets != null ) {
151+ topPadding = paddingTopSystemWindowInsets ? topInset : 0 ;
152+ }
153+ initialPadding .top += topPadding ;
154+ initialPadding .bottom += bottomPadding ;
155+ initialPadding .applyToView (view );
156+
157+ return insets ;
158+ }
159+ });
160+
92161 setImportantForAccessibility (View .IMPORTANT_FOR_ACCESSIBILITY_YES );
93162 attributes .recycle ();
94163 }
164+
165+ private boolean hasGravity (ViewGroup .LayoutParams lp , int gravity ) {
166+ if (lp instanceof CoordinatorLayout .LayoutParams ) {
167+ return (((CoordinatorLayout .LayoutParams ) lp ).gravity & gravity ) == gravity ;
168+ } else if (lp instanceof FrameLayout .LayoutParams ) {
169+ return (((FrameLayout .LayoutParams ) lp ).gravity & gravity ) == gravity ;
170+ }
171+ return false ;
172+ }
173+
174+ @ Override
175+ protected void onMeasure (int widthMeasureSpec , int heightMeasureSpec ) {
176+ super .onMeasure (widthMeasureSpec , heightMeasureSpec );
177+ if (MeasureSpec .getMode (heightMeasureSpec ) != MeasureSpec .EXACTLY ) {
178+ int childCount = getChildCount ();
179+ int newHeight =
180+ Math .max (
181+ getMeasuredHeight (),
182+ getSuggestedMinimumHeight () + getPaddingTop () + getPaddingBottom ());
183+
184+ for (int i = 0 ; i < childCount ; i ++) {
185+ measureChild (
186+ getChildAt (i ),
187+ widthMeasureSpec ,
188+ MeasureSpec .makeMeasureSpec (newHeight , MeasureSpec .EXACTLY ));
189+ }
190+
191+ setMeasuredDimension (getMeasuredWidth (), newHeight );
192+ }
193+ }
95194}
0 commit comments