@@ -398,10 +398,16 @@ abstract class BaseSlider<
398398 @ NonNull private final RectF iconRectF = new RectF ();
399399 @ NonNull private final Rect iconRect = new Rect ();
400400 @ NonNull private final Matrix rotationMatrix = new Matrix ();
401- @ NonNull private final MaterialShapeDrawable defaultThumbDrawable = new MaterialShapeDrawable ();
401+ @ NonNull private final List <MaterialShapeDrawable > defaultThumbDrawables = new ArrayList <>();
402+
402403 @ Nullable private Drawable customThumbDrawable ;
403404 @ NonNull private List <Drawable > customThumbDrawablesForValues = Collections .emptyList ();
404405
406+ private float thumbElevation ;
407+ private float thumbStrokeWidth ;
408+ @ Nullable private ColorStateList thumbStrokeColor ;
409+ @ NonNull private ColorStateList thumbTintList ;
410+
405411 private float touchPosition ;
406412 @ SeparationUnit private int separationUnit = UNIT_PX ;
407413
@@ -494,10 +500,6 @@ public BaseSlider(
494500 setFocusable (true );
495501 setClickable (true );
496502
497- // Set up the thumb drawable to always show the compat shadow.
498- defaultThumbDrawable .setShadowCompatibilityMode (
499- MaterialShapeDrawable .SHADOW_COMPAT_MODE_ALWAYS );
500-
501503 scaledTouchSlop = ViewConfiguration .get (context ).getScaledTouchSlop ();
502504
503505 accessibilityHelper = new AccessibilityHelper (this );
@@ -544,12 +546,12 @@ private void processAttributes(Context context, AttributeSet attrs, int defStyle
544546
545547 valueFrom = a .getFloat (R .styleable .Slider_android_valueFrom , 0.0f );
546548 valueTo = a .getFloat (R .styleable .Slider_android_valueTo , 1.0f );
547- setValues (valueFrom );
548549 setCentered (a .getBoolean (R .styleable .Slider_centered , false ));
549550 stepSize = a .getFloat (R .styleable .Slider_android_stepSize , 0.0f );
550551 continuousModeTickCount = a .getInt (R .styleable .Slider_continuousModeTickCount , 0 );
551552
552- float defaultMinTouchTargetSize = MaterialAttributes .resolveMinimumAccessibleTouchTarget (context );
553+ float defaultMinTouchTargetSize =
554+ MaterialAttributes .resolveMinimumAccessibleTouchTarget (context );
553555 minTouchTargetSize =
554556 (int )
555557 Math .ceil (
@@ -578,8 +580,10 @@ private void processAttributes(Context context, AttributeSet attrs, int defStyle
578580 context , R .color .material_slider_active_track_color ));
579581 ColorStateList thumbColor =
580582 MaterialResources .getColorStateList (context , a , R .styleable .Slider_thumbColor );
581- defaultThumbDrawable .setFillColor (thumbColor );
582-
583+ setThumbTintList (
584+ thumbColor != null
585+ ? thumbColor
586+ : AppCompatResources .getColorStateList (context , R .color .material_slider_thumb_color ));
583587 if (a .hasValue (R .styleable .Slider_thumbStrokeColor )) {
584588 setThumbStrokeColor (
585589 MaterialResources .getColorStateList (context , a , R .styleable .Slider_thumbStrokeColor ));
@@ -660,6 +664,8 @@ private void processAttributes(Context context, AttributeSet attrs, int defStyle
660664 setEnabled (false );
661665 }
662666
667+ setValues (valueFrom );
668+
663669 a .recycle ();
664670 }
665671
@@ -899,6 +905,7 @@ private void setValuesInternal(@NonNull ArrayList<Float> values) {
899905
900906 this .values = values ;
901907 dirtyConfig = true ;
908+ updateDefaultThumbDrawables ();
902909 // Only update the focused thumb index. The active thumb index will be updated on touch.
903910 focusedThumbIdx = 0 ;
904911 updateHaloHotspot ();
@@ -907,6 +914,30 @@ private void setValuesInternal(@NonNull ArrayList<Float> values) {
907914 postInvalidate ();
908915 }
909916
917+ private void updateDefaultThumbDrawables () {
918+ if (defaultThumbDrawables .size () != values .size ()) {
919+ defaultThumbDrawables .clear ();
920+ for (int i = 0 ; i < values .size (); i ++) {
921+ // Create default thumbs to make sure each one is an independent drawable.
922+ defaultThumbDrawables .add (createNewDefaultThumb ());
923+ }
924+ }
925+ }
926+
927+ private MaterialShapeDrawable createNewDefaultThumb () {
928+ MaterialShapeDrawable thumb = new MaterialShapeDrawable ();
929+ thumb .setShadowCompatibilityMode (MaterialShapeDrawable .SHADOW_COMPAT_MODE_ALWAYS );
930+ thumb .setFillColor (getThumbTintList ());
931+ thumb .setShapeAppearanceModel (
932+ ShapeAppearanceModel .builder ().setAllCorners (ROUNDED , thumbWidth / 2f ).build ());
933+ thumb .setBounds (0 , 0 , thumbWidth , thumbHeight );
934+ thumb .setElevation (getThumbElevation ());
935+ thumb .setStrokeWidth (getThumbStrokeWidth ());
936+ thumb .setStrokeTint (getThumbStrokeColor ());
937+ thumb .setState (getDrawableState ());
938+ return thumb ;
939+ }
940+
910941 private void createLabelPool () {
911942 // If there are too many labels, remove the extra ones from the end.
912943 if (labels .size () > values .size ()) {
@@ -1093,12 +1124,17 @@ private Drawable initializeCustomThumbDrawable(Drawable originalDrawable) {
10931124 }
10941125
10951126 private void adjustCustomThumbDrawableBounds (Drawable drawable ) {
1127+ adjustCustomThumbDrawableBounds (thumbWidth , drawable );
1128+ }
1129+
1130+ private void adjustCustomThumbDrawableBounds (
1131+ @ IntRange (from = 0 ) @ Px int width , Drawable drawable ) {
10961132 int originalWidth = drawable .getIntrinsicWidth ();
10971133 int originalHeight = drawable .getIntrinsicHeight ();
10981134 if (originalWidth == -1 && originalHeight == -1 ) {
1099- drawable .setBounds (0 , 0 , thumbWidth , thumbHeight );
1135+ drawable .setBounds (0 , 0 , width , thumbHeight );
11001136 } else {
1101- float scaleRatio = (float ) max (thumbWidth , thumbHeight ) / max (originalWidth , originalHeight );
1137+ float scaleRatio = (float ) max (width , thumbHeight ) / max (originalWidth , originalHeight );
11021138 drawable .setBounds (
11031139 0 , 0 , (int ) (originalWidth * scaleRatio ), (int ) (originalHeight * scaleRatio ));
11041140 }
@@ -1201,7 +1237,7 @@ public void setLabelFormatter(@Nullable LabelFormatter formatter) {
12011237 * @attr ref com.google.android.material.R.styleable#Slider_thumbElevation
12021238 */
12031239 public float getThumbElevation () {
1204- return defaultThumbDrawable . getElevation () ;
1240+ return thumbElevation ;
12051241 }
12061242
12071243 /**
@@ -1211,7 +1247,13 @@ public float getThumbElevation() {
12111247 * @attr ref com.google.android.material.R.styleable#Slider_thumbElevation
12121248 */
12131249 public void setThumbElevation (float elevation ) {
1214- defaultThumbDrawable .setElevation (elevation );
1250+ if (elevation == thumbElevation ) {
1251+ return ;
1252+ }
1253+ thumbElevation = elevation ;
1254+ for (int i = 0 ; i < defaultThumbDrawables .size (); i ++) {
1255+ defaultThumbDrawables .get (i ).setElevation (thumbElevation );
1256+ }
12151257 }
12161258
12171259 /**
@@ -1296,16 +1338,26 @@ public void setThumbWidth(@IntRange(from = 0) @Px int width) {
12961338 }
12971339
12981340 thumbWidth = width ;
1299-
1300- defaultThumbDrawable .setShapeAppearanceModel (
1301- ShapeAppearanceModel .builder ().setAllCorners (ROUNDED , thumbWidth / 2f ).build ());
1302- defaultThumbDrawable .setBounds (0 , 0 , thumbWidth , thumbHeight );
1303-
1341+ // Update custom thumbs, if any.
13041342 if (customThumbDrawable != null ) {
1305- adjustCustomThumbDrawableBounds (customThumbDrawable );
1343+ adjustCustomThumbDrawableBounds (width , customThumbDrawable );
13061344 }
1307- for (Drawable customDrawable : customThumbDrawablesForValues ) {
1308- adjustCustomThumbDrawableBounds (customDrawable );
1345+ for (int i = 0 ; i < customThumbDrawablesForValues .size (); i ++) {
1346+ adjustCustomThumbDrawableBounds (width , customThumbDrawablesForValues .get (i ));
1347+ }
1348+ // Update default thumb(s).
1349+ setThumbWidth (width , /* thumbIndex= */ null );
1350+ }
1351+
1352+ private void setThumbWidth (@ IntRange (from = 0 ) @ Px int width , @ Nullable Integer thumbIndex ) {
1353+ for (int i = 0 ; i < defaultThumbDrawables .size (); i ++) {
1354+ if (thumbIndex == null || i == thumbIndex ) {
1355+ defaultThumbDrawables
1356+ .get (i )
1357+ .setShapeAppearanceModel (
1358+ ShapeAppearanceModel .builder ().setAllCorners (ROUNDED , thumbWidth / 2f ).build ());
1359+ defaultThumbDrawables .get (i ).setBounds (0 , 0 , width , thumbHeight );
1360+ }
13091361 }
13101362
13111363 updateWidgetLayout (false );
@@ -1355,7 +1407,9 @@ public void setThumbHeight(@IntRange(from = 0) @Px int height) {
13551407
13561408 thumbHeight = height ;
13571409
1358- defaultThumbDrawable .setBounds (0 , 0 , thumbWidth , thumbHeight );
1410+ for (int i = 0 ; i < defaultThumbDrawables .size (); i ++) {
1411+ defaultThumbDrawables .get (i ).setBounds (0 , 0 , thumbWidth , thumbHeight );
1412+ }
13591413
13601414 if (customThumbDrawable != null ) {
13611415 adjustCustomThumbDrawableBounds (customThumbDrawable );
@@ -1390,7 +1444,15 @@ public void setThumbHeightResource(@DimenRes int height) {
13901444 * @see #getThumbStrokeColor()
13911445 */
13921446 public void setThumbStrokeColor (@ Nullable ColorStateList thumbStrokeColor ) {
1393- defaultThumbDrawable .setStrokeColor (thumbStrokeColor );
1447+ if (thumbStrokeColor == this .thumbStrokeColor ) {
1448+ return ;
1449+ }
1450+
1451+ this .thumbStrokeColor = thumbStrokeColor ;
1452+ for (int i = 0 ; i < defaultThumbDrawables .size (); i ++) {
1453+ defaultThumbDrawables .get (i ).setStrokeColor (thumbStrokeColor );
1454+ }
1455+
13941456 postInvalidate ();
13951457 }
13961458
@@ -1418,8 +1480,9 @@ public void setThumbStrokeColorResource(@ColorRes int thumbStrokeColorResourceId
14181480 * @see #setThumbStrokeColor(ColorStateList)
14191481 * @see #setThumbStrokeColorResource(int)
14201482 */
1483+ @ Nullable
14211484 public ColorStateList getThumbStrokeColor () {
1422- return defaultThumbDrawable . getStrokeColor () ;
1485+ return thumbStrokeColor ;
14231486 }
14241487
14251488 /**
@@ -1432,7 +1495,15 @@ public ColorStateList getThumbStrokeColor() {
14321495 * @see #getThumbStrokeWidth()
14331496 */
14341497 public void setThumbStrokeWidth (float thumbStrokeWidth ) {
1435- defaultThumbDrawable .setStrokeWidth (thumbStrokeWidth );
1498+ if (thumbStrokeWidth == this .thumbStrokeWidth ) {
1499+ return ;
1500+ }
1501+
1502+ this .thumbStrokeWidth = thumbStrokeWidth ;
1503+ for (int i = 0 ; i < defaultThumbDrawables .size (); i ++) {
1504+ defaultThumbDrawables .get (i ).setStrokeWidth (thumbStrokeWidth );
1505+ }
1506+
14361507 postInvalidate ();
14371508 }
14381509
@@ -1460,7 +1531,7 @@ public void setThumbStrokeWidthResource(@DimenRes int thumbStrokeWidthResourceId
14601531 * @see #setThumbStrokeWidthResource(int)
14611532 */
14621533 public float getThumbStrokeWidth () {
1463- return defaultThumbDrawable . getStrokeWidth () ;
1534+ return thumbStrokeWidth ;
14641535 }
14651536
14661537 /**
@@ -1708,7 +1779,7 @@ public void setHaloTintList(@NonNull ColorStateList haloColor) {
17081779 */
17091780 @ NonNull
17101781 public ColorStateList getThumbTintList () {
1711- return defaultThumbDrawable . getFillColor () ;
1782+ return thumbTintList ;
17121783 }
17131784
17141785 /**
@@ -1718,11 +1789,15 @@ public ColorStateList getThumbTintList() {
17181789 * @attr ref com.google.android.material.R.styleable#Slider_thumbColor
17191790 */
17201791 public void setThumbTintList (@ NonNull ColorStateList thumbColor ) {
1721- if (thumbColor .equals (defaultThumbDrawable . getFillColor () )) {
1792+ if (thumbColor .equals (thumbTintList )) {
17221793 return ;
17231794 }
17241795
1725- defaultThumbDrawable .setFillColor (thumbColor );
1796+ thumbTintList = thumbColor ;
1797+ for (int i = 0 ; i < defaultThumbDrawables .size (); i ++) {
1798+ defaultThumbDrawables .get (i ).setFillColor (thumbTintList );
1799+ }
1800+
17261801 invalidate ();
17271802 }
17281803
@@ -3080,7 +3155,7 @@ private void drawThumbs(@NonNull Canvas canvas, int width, int yCenter) {
30803155 } else if (i < customThumbDrawablesForValues .size ()) {
30813156 drawThumbDrawable (canvas , width , yCenter , value , customThumbDrawablesForValues .get (i ));
30823157 } else {
3083- // Clear out the track behind the thumb if we're in a disable state since the thumb is
3158+ // Clear out the track behind the thumb if we're in a disabled state since the thumb is
30843159 // transparent.
30853160 if (!isEnabled ()) {
30863161 canvas .drawCircle (
@@ -3089,7 +3164,7 @@ private void drawThumbs(@NonNull Canvas canvas, int width, int yCenter) {
30893164 getThumbRadius (),
30903165 thumbPaint );
30913166 }
3092- drawThumbDrawable (canvas , width , yCenter , value , defaultThumbDrawable );
3167+ drawThumbDrawable (canvas , width , yCenter , value , defaultThumbDrawables . get ( i ) );
30933168 }
30943169 }
30953170 }
@@ -3224,13 +3299,7 @@ && abs(lastEvent.getY() - event.getY()) <= scaledTouchSlop) {
32243299 if (activeThumbIdx != -1 ) {
32253300 snapTouchPosition ();
32263301 updateHaloHotspot ();
3227- // Reset the thumb width.
3228- if (hasGapBetweenThumbAndTrack ()
3229- && defaultThumbWidth != -1
3230- && defaultThumbTrackGapSize != -1 ) {
3231- setThumbWidth (defaultThumbWidth );
3232- setThumbTrackGapSize (defaultThumbTrackGapSize );
3233- }
3302+ resetThumbWidth ();
32343303 activeThumbIdx = -1 ;
32353304 onStopTrackingTouch ();
32363305 }
@@ -3248,17 +3317,29 @@ && abs(lastEvent.getY() - event.getY()) <= scaledTouchSlop) {
32483317 }
32493318
32503319 private void updateThumbWidthWhenPressed () {
3251- // Update thumb width and track gap size when pressed.
3252- if (hasGapBetweenThumbAndTrack ()) {
3320+ // Update default thumb width and track gap size when pressed.
3321+ if (hasGapBetweenThumbAndTrack ()
3322+ && customThumbDrawable == null
3323+ && customThumbDrawablesForValues .isEmpty ()) {
32533324 defaultThumbWidth = thumbWidth ;
32543325 defaultThumbTrackGapSize = thumbTrackGapSize ;
32553326 int pressedThumbWidth = Math .round (thumbWidth * THUMB_WIDTH_PRESSED_RATIO );
32563327 int delta = thumbWidth - pressedThumbWidth ;
3257- setThumbWidth (pressedThumbWidth );
3328+ // Only the currently pressed thumb should change width.
3329+ setThumbWidth (pressedThumbWidth , /* thumbIndex= */ activeThumbIdx );
32583330 setThumbTrackGapSize (thumbTrackGapSize - delta / 2 );
32593331 }
32603332 }
32613333
3334+ private void resetThumbWidth () {
3335+ // Reset the default thumb width.
3336+ if (hasGapBetweenThumbAndTrack () && defaultThumbWidth != -1 && defaultThumbTrackGapSize != -1 ) {
3337+ // Only the currently pressed thumb should change width.
3338+ setThumbWidth (defaultThumbWidth , /* thumbIndex= */ activeThumbIdx );
3339+ setThumbTrackGapSize (defaultThumbTrackGapSize );
3340+ }
3341+ }
3342+
32623343 private double snapPosition (float position ) {
32633344 if (stepSize > 0.0f ) {
32643345 int stepCount = (int ) ((valueTo - valueFrom ) / stepSize );
@@ -3766,8 +3847,10 @@ protected void drawableStateChanged() {
37663847 label .setState (getDrawableState ());
37673848 }
37683849 }
3769- if (defaultThumbDrawable .isStateful ()) {
3770- defaultThumbDrawable .setState (getDrawableState ());
3850+ for (int i = 0 ; i < defaultThumbDrawables .size (); i ++) {
3851+ if (defaultThumbDrawables .get (i ).isStateful ()) {
3852+ defaultThumbDrawables .get (i ).setState (getDrawableState ());
3853+ }
37713854 }
37723855 haloPaint .setColor (getColorForState (haloColor ));
37733856 haloPaint .setAlpha (HALO_ALPHA );
@@ -3802,6 +3885,7 @@ public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) {
38023885 }
38033886
38043887 if (keyCode == KeyEvent .KEYCODE_TAB ) {
3888+ resetThumbWidth ();
38053889 if (event .hasNoModifiers ()) {
38063890 return moveFocus (1 );
38073891 }
@@ -3851,6 +3935,7 @@ private boolean moveFocus(int direction) {
38513935 return false ;
38523936 }
38533937 activeThumbIdx = focusedThumbIdx ;
3938+ updateThumbWidthWhenPressed ();
38543939 updateHaloHotspot ();
38553940 postInvalidate ();
38563941 return true ;
@@ -3918,6 +4003,7 @@ protected void onFocusChanged(
39184003 boolean gainFocus , int direction , @ Nullable Rect previouslyFocusedRect ) {
39194004 super .onFocusChanged (gainFocus , direction , previouslyFocusedRect );
39204005 if (!gainFocus ) {
4006+ resetThumbWidth ();
39214007 activeThumbIdx = -1 ;
39224008 accessibilityHelper .clearKeyboardFocusForVirtualView (focusedThumbIdx );
39234009 } else {
@@ -3927,6 +4013,8 @@ protected void onFocusChanged(
39274013 focusThumbOnFocusGained (direction );
39284014 activeThumbIdx = focusedThumbIdx ;
39294015 }
4016+ resetThumbWidth ();
4017+ updateThumbWidthWhenPressed ();
39304018 accessibilityHelper .requestKeyboardFocusForVirtualView (focusedThumbIdx );
39314019 }
39324020 }
0 commit comments