@@ -147,11 +147,23 @@ public class NavigationView extends ScrimInsetsFrameLayout implements MaterialBa
147147 private boolean startInsetScrimEnabled = true ;
148148 private boolean endInsetScrimEnabled = true ;
149149
150+ @ Nullable private Drawable itemBackground ;
151+ @ Nullable private ShapeAppearanceModel itemShapeAppearanceModel ;
152+
153+ private int itemShapeInsetStart ;
154+ private int itemShapeInsetTop ;
155+ private int itemShapeInsetEnd ;
156+ private int itemShapeInsetBottom ;
157+ private int itemShapeInsetLeft ;
158+ private int itemShapeInsetRight ;
159+
160+ @ Nullable private ColorStateList itemShapeFillColor ;
161+ @ Nullable private ColorStateList itemRippleColor ;
162+
150163 @ Px private int drawerLayoutCornerSize = 0 ;
151164 private final boolean drawerLayoutCornerSizeBackAnimationEnabled ;
152165 @ Px private final int drawerLayoutCornerSizeBackAnimationMax ;
153166 private final ShapeableDelegate shapeableDelegate = ShapeableDelegate .create (this );
154- @ Nullable private ShapeAppearanceModel itemShapeAppearanceModel ;
155167
156168 private final MaterialSideContainerBackHelper sideContainerBackHelper =
157169 new MaterialSideContainerBackHelper (this );
@@ -280,30 +292,7 @@ public NavigationView(@NonNull Context context, @Nullable AttributeSet attrs, in
280292 itemTextColor = createDefaultColorStateList (android .R .attr .textColorPrimary );
281293 }
282294
283- Drawable itemBackground = a .getDrawable (R .styleable .NavigationView_itemBackground );
284- // Set a shaped itemBackground if itemBackground hasn't been set and there is a shape
285- // appearance.
286- if (itemBackground == null && hasShapeAppearance (a )) {
287- itemBackground = createDefaultItemBackground (a );
288-
289- ColorStateList itemRippleColor =
290- MaterialResources .getColorStateList (
291- context , a , R .styleable .NavigationView_itemRippleColor );
292-
293- // Use a ripple matching the item's shape as the foreground if a ripple color is set.
294- // Otherwise the selectableItemBackground foreground from the item layout will be used.
295- if (itemRippleColor != null ) {
296- Drawable itemRippleMask = createDefaultItemDrawable (a , null );
297- RippleDrawable ripple =
298- new RippleDrawable (
299- RippleUtils .sanitizeRippleDrawableColor (itemRippleColor ), null , itemRippleMask );
300- FocusRingDrawable focusRingDrawable = FocusRingDrawable .layer (context , ripple );
301- if (focusRingDrawable != null ) {
302- focusRingDrawable .setFocusRingShapeAppearance (itemShapeAppearanceModel );
303- }
304- presenter .setItemForeground (ripple );
305- }
306- }
295+ initItemBackgrounds (context , a );
307296
308297 if (a .hasValue (R .styleable .NavigationView_itemHorizontalPadding )) {
309298 final int itemHorizontalPadding =
@@ -372,7 +361,6 @@ public void onMenuModeChange(MenuBuilder menu) {}
372361 }
373362 presenter .setItemTextAppearanceActiveBoldEnabled (textAppearanceActiveBoldEnabled );
374363 presenter .setItemTextColor (itemTextColor );
375- presenter .setItemBackground (itemBackground );
376364 presenter .setItemIconPadding (itemIconPadding );
377365 this .menu .addMenuPresenter (presenter );
378366 addView ((View ) presenter .getMenuView (this ));
@@ -390,6 +378,95 @@ public void onMenuModeChange(MenuBuilder menu) {}
390378 setupInsetScrimsListener ();
391379 }
392380
381+ private void initItemBackgrounds (@ NonNull Context context , @ NonNull TintTypedArray a ) {
382+ itemBackground = a .getDrawable (R .styleable .NavigationView_itemBackground );
383+ if (itemBackground == null && hasShapeAppearance (a )) {
384+ int shapeAppearanceResId = a .getResourceId (R .styleable .NavigationView_itemShapeAppearance , 0 );
385+ int shapeAppearanceOverlayResId = a .getResourceId (R .styleable .NavigationView_itemShapeAppearanceOverlay , 0 );
386+
387+ itemShapeAppearanceModel = ShapeAppearanceModel
388+ .builder (context , shapeAppearanceResId , shapeAppearanceOverlayResId )
389+ .build ();
390+
391+ itemShapeInsetStart = a .getDimensionPixelSize (R .styleable .NavigationView_itemShapeInsetStart , 0 );
392+ itemShapeInsetTop = a .getDimensionPixelSize (R .styleable .NavigationView_itemShapeInsetTop , 0 );
393+ itemShapeInsetEnd = a .getDimensionPixelSize (R .styleable .NavigationView_itemShapeInsetEnd , 0 );
394+ itemShapeInsetBottom = a .getDimensionPixelSize (R .styleable .NavigationView_itemShapeInsetBottom , 0 );
395+
396+ itemShapeFillColor = MaterialResources .getColorStateList (context , a , R .styleable .NavigationView_itemShapeFillColor );
397+ itemRippleColor = MaterialResources .getColorStateList (context , a , R .styleable .NavigationView_itemRippleColor );
398+ }
399+
400+ updateItemShapeInsets ();
401+ updateItemBackground ();
402+ updateItemForeground ();
403+ }
404+
405+ private void updateItemShapeInsets () {
406+ final int layoutDirection = getLayoutDirection ();
407+ itemShapeInsetLeft = layoutDirection == View .LAYOUT_DIRECTION_LTR
408+ ? itemShapeInsetStart
409+ : itemShapeInsetEnd ;
410+
411+ itemShapeInsetRight = layoutDirection == View .LAYOUT_DIRECTION_LTR
412+ ? itemShapeInsetEnd
413+ : itemShapeInsetStart ;
414+ }
415+
416+ private void updateItemBackground () {
417+ if (itemBackground != null ) {
418+ presenter .setItemBackground (itemBackground );
419+ } else if (itemShapeAppearanceModel != null ) {
420+ final MaterialShapeDrawable itemShapeDrawable = new MaterialShapeDrawable (itemShapeAppearanceModel );
421+ itemShapeDrawable .setFillColor (itemShapeFillColor );
422+
423+ final InsetDrawable itemDrawable = new InsetDrawable (
424+ itemShapeDrawable ,
425+ itemShapeInsetLeft ,
426+ itemShapeInsetTop ,
427+ itemShapeInsetRight ,
428+ itemShapeInsetBottom );
429+
430+ presenter .setItemBackground (itemDrawable );
431+ } else {
432+ presenter .setItemBackground (null );
433+ }
434+ }
435+
436+ private void updateItemForeground () {
437+ if (itemShapeAppearanceModel != null ) {
438+ final MaterialShapeDrawable itemShapeDrawable = new MaterialShapeDrawable (itemShapeAppearanceModel );
439+ final InsetDrawable itemRippleMaskDrawable = new InsetDrawable (
440+ itemShapeDrawable ,
441+ itemShapeInsetLeft ,
442+ itemShapeInsetTop ,
443+ itemShapeInsetRight ,
444+ itemShapeInsetBottom );
445+
446+ final RippleDrawable itemRippleDrawable = new RippleDrawable (
447+ RippleUtils .sanitizeRippleDrawableColor (itemRippleColor ), null , itemRippleMaskDrawable );
448+
449+ final FocusRingDrawable itemFocusRingDrawable =
450+ FocusRingDrawable .layer (getContext (), itemRippleDrawable );
451+
452+ if (itemFocusRingDrawable != null ) {
453+ itemFocusRingDrawable .setFocusRingShapeAppearance (itemShapeAppearanceModel );
454+ }
455+
456+ presenter .setItemForeground (itemRippleDrawable );
457+ } else {
458+ presenter .setItemForeground (null );
459+ }
460+ }
461+
462+ @ Override
463+ public void onRtlPropertiesChanged (int layoutDirection ) {
464+ super .onRtlPropertiesChanged (layoutDirection );
465+ updateItemShapeInsets ();
466+ updateItemBackground ();
467+ updateItemForeground ();
468+ }
469+
393470 @ Override
394471 public void setOverScrollMode (int overScrollMode ) {
395472 super .setOverScrollMode (overScrollMode );
@@ -515,41 +592,6 @@ public void setElevation(float elevation) {
515592 MaterialShapeUtils .setElevation (this , elevation );
516593 }
517594
518- /**
519- * Creates a {@link MaterialShapeDrawable} to use as the {@code itemBackground} and wraps it in an
520- * {@link InsetDrawable} for margins.
521- *
522- * @param a The TintTypedArray containing the resolved NavigationView style attributes.
523- */
524- @ NonNull
525- private Drawable createDefaultItemBackground (@ NonNull TintTypedArray a ) {
526- ColorStateList fillColor =
527- MaterialResources .getColorStateList (
528- getContext (), a , R .styleable .NavigationView_itemShapeFillColor );
529- return createDefaultItemDrawable (a , fillColor );
530- }
531-
532- @ NonNull
533- private Drawable createDefaultItemDrawable (
534- @ NonNull TintTypedArray a , @ Nullable ColorStateList fillColor ) {
535- int shapeAppearanceResId = a .getResourceId (R .styleable .NavigationView_itemShapeAppearance , 0 );
536- int shapeAppearanceOverlayResId =
537- a .getResourceId (R .styleable .NavigationView_itemShapeAppearanceOverlay , 0 );
538- itemShapeAppearanceModel =
539- ShapeAppearanceModel .builder (
540- getContext (), shapeAppearanceResId , shapeAppearanceOverlayResId )
541- .build ();
542- MaterialShapeDrawable materialShapeDrawable =
543- new MaterialShapeDrawable (itemShapeAppearanceModel );
544- materialShapeDrawable .setFillColor (fillColor );
545-
546- int insetLeft = a .getDimensionPixelSize (R .styleable .NavigationView_itemShapeInsetStart , 0 );
547- int insetTop = a .getDimensionPixelSize (R .styleable .NavigationView_itemShapeInsetTop , 0 );
548- int insetRight = a .getDimensionPixelSize (R .styleable .NavigationView_itemShapeInsetEnd , 0 );
549- int insetBottom = a .getDimensionPixelSize (R .styleable .NavigationView_itemShapeInsetBottom , 0 );
550- return new InsetDrawable (materialShapeDrawable , insetLeft , insetTop , insetRight , insetBottom );
551- }
552-
553595 @ Override
554596 protected Parcelable onSaveInstanceState () {
555597 Parcelable superState = super .onSaveInstanceState ();
0 commit comments