2121import static com .google .android .material .theme .overlay .MaterialThemeOverlay .wrap ;
2222
2323import android .content .Context ;
24+ import android .content .res .ColorStateList ;
25+ import android .graphics .PorterDuff ;
26+ import android .graphics .PorterDuff .Mode ;
27+ import android .graphics .drawable .Drawable ;
28+ import android .graphics .drawable .LayerDrawable ;
29+ import androidx .appcompat .content .res .AppCompatResources ;
30+ import androidx .appcompat .widget .DrawableUtils ;
2431import androidx .appcompat .widget .SwitchCompat ;
32+ import androidx .appcompat .widget .TintTypedArray ;
2533import android .util .AttributeSet ;
34+ import androidx .annotation .DrawableRes ;
2635import androidx .annotation .NonNull ;
2736import androidx .annotation .Nullable ;
37+ import androidx .core .graphics .drawable .DrawableCompat ;
38+ import com .google .android .material .internal .ThemeEnforcement ;
2839
2940/**
3041 * A class that creates a Material Themed Switch. This class is intended to provide a brand new
3445public class MaterialSwitch extends SwitchCompat {
3546 private static final int DEF_STYLE_RES = R .style .Widget_Material3_CompoundButton_MaterialSwitch ;
3647
48+ @ Nullable private Drawable trackDrawable ;
49+ @ Nullable private Drawable trackDecorationDrawable ;
50+
51+ @ Nullable private ColorStateList trackTintList ;
52+ @ Nullable private ColorStateList trackDecorationTintList ;
53+ @ NonNull private PorterDuff .Mode trackDecorationTintMode ;
54+
3755 public MaterialSwitch (@ NonNull Context context ) {
3856 this (context , null );
3957 }
@@ -44,5 +62,173 @@ public MaterialSwitch(@NonNull Context context, @Nullable AttributeSet attrs) {
4462
4563 public MaterialSwitch (@ NonNull Context context , @ Nullable AttributeSet attrs , int defStyleAttr ) {
4664 super (wrap (context , attrs , defStyleAttr , DEF_STYLE_RES ), attrs , defStyleAttr );
65+ // Ensure we are using the correctly themed context rather than the context that was passed in.
66+ context = getContext ();
67+
68+ trackDrawable = super .getTrackDrawable ();
69+ trackTintList = super .getTrackTintList ();
70+ super .setTrackTintList (null ); // Always use our custom tinting logic
71+
72+ TintTypedArray attributes =
73+ ThemeEnforcement .obtainTintedStyledAttributes (
74+ context , attrs , R .styleable .MaterialSwitch , defStyleAttr , DEF_STYLE_RES );
75+
76+ trackDecorationDrawable =
77+ attributes .getDrawable (R .styleable .MaterialSwitch_trackDecoration );
78+ trackDecorationTintList =
79+ attributes .getColorStateList (R .styleable .MaterialSwitch_trackDecorationTint );
80+ trackDecorationTintMode =
81+ DrawableUtils .parseTintMode (
82+ attributes .getInt (R .styleable .MaterialSwitch_trackDecorationTintMode , -1 ), Mode .SRC_IN );
83+
84+ attributes .recycle ();
85+
86+ refreshTrackDrawable ();
87+ }
88+
89+ @ Override
90+ public void setTrackDrawable (@ Nullable Drawable track ) {
91+ trackDrawable = track ;
92+ refreshTrackDrawable ();
93+ }
94+
95+ @ Override
96+ @ Nullable
97+ public Drawable getTrackDrawable () {
98+ return trackDrawable ;
99+ }
100+
101+ @ Override
102+ public void setTrackTintList (@ Nullable ColorStateList tint ) {
103+ trackTintList = tint ;
104+ refreshTrackDrawable ();
105+ }
106+
107+ @ Override
108+ @ Nullable
109+ public ColorStateList getTrackTintList () {
110+ return trackTintList ;
111+ }
112+
113+ @ Override
114+ public void setTrackTintMode (@ Nullable PorterDuff .Mode tintMode ) {
115+ super .setTrackTintMode (tintMode );
116+ refreshTrackDrawable ();
117+ }
118+
119+ /**
120+ * Set the drawable used for the track decoration that will be drawn upon the track.
121+ *
122+ * @param resId Resource ID of a track decoration drawable
123+ *
124+ * @attr ref com.google.android.material.R.styleable#MaterialSwitch_trackDecoration
125+ */
126+ public void setTrackDecorationResource (@ DrawableRes int resId ) {
127+ setTrackDecorationDrawable (AppCompatResources .getDrawable (getContext (), resId ));
128+ }
129+
130+ /**
131+ * Set the drawable used for the track decoration that will be drawn upon the track.
132+ *
133+ * @param trackDecoration Track decoration drawable
134+ *
135+ * @attr ref com.google.android.material.R.styleable#MaterialSwitch_trackDecoration
136+ */
137+ public void setTrackDecorationDrawable (@ Nullable Drawable trackDecoration ) {
138+ trackDecorationDrawable = trackDecoration ;
139+ refreshTrackDrawable ();
140+ }
141+
142+ /**
143+ * Get the drawable used for the track decoration that will be drawn upon the track.
144+ *
145+ * @attr ref com.google.android.material.R.styleable#MaterialSwitch_trackDecoration
146+ */
147+ @ Nullable
148+ public Drawable getTrackDecorationDrawable () {
149+ return trackDecorationDrawable ;
150+ }
151+
152+ /**
153+ * Applies a tint to the track decoration drawable. Does not modify the current
154+ * tint mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
155+ *
156+ * <p>Subsequent calls to {@link #setTrackDecorationDrawable(Drawable)} will
157+ * automatically mutate the drawable and apply the specified tint and tint
158+ * mode using {@link DrawableCompat#setTintList(Drawable, ColorStateList)}.
159+ *
160+ * @param tint the tint to apply, may be {@code null} to clear tint
161+ *
162+ * @attr ref com.google.android.material.R.styleable#MaterialSwitch_trackDecorationTint
163+ */
164+ public void setTrackDecorationTintList (@ Nullable ColorStateList tint ) {
165+ trackDecorationTintList = tint ;
166+ refreshTrackDrawable ();
167+ }
168+
169+ /**
170+ * Returns the tint applied to the track decoration drawable
171+ *
172+ * @attr ref com.google.android.material.R.styleable#MaterialSwitch_trackDecorationTint
173+ */
174+ @ Nullable
175+ public ColorStateList getTrackDecorationTintList () {
176+ return trackDecorationTintList ;
177+ }
178+
179+ /**
180+ * Specifies the blending mode used to apply the tint specified by
181+ * {@link #setTrackDecorationTintList(ColorStateList)}} to the track decoration drawable.
182+ * The default mode is {@link PorterDuff.Mode#SRC_IN}.
183+ *
184+ * @param tintMode the blending mode used to apply the tint
185+
186+ * @attr ref com.google.android.material.R.styleable#MaterialSwitch_trackDecorationTintMode
187+ */
188+ public void setTrackDecorationTintMode (@ NonNull PorterDuff .Mode tintMode ) {
189+ trackDecorationTintMode = tintMode ;
190+ refreshTrackDrawable ();
191+ }
192+
193+ /**
194+ * Returns the blending mode used to apply the tint to the track decoration drawable
195+ *
196+ * @attr ref com.google.android.material.R.styleable#MaterialSwitch_trackDecorationTintMode
197+ */
198+ @ NonNull
199+ public PorterDuff .Mode getTrackDecorationTintMode () {
200+ return trackDecorationTintMode ;
201+ }
202+
203+ private void refreshTrackDrawable () {
204+ trackDrawable = setDrawableTintListIfNeeded (trackDrawable , trackTintList , getTrackTintMode ());
205+ trackDecorationDrawable = setDrawableTintListIfNeeded (
206+ trackDecorationDrawable , trackDecorationTintList , trackDecorationTintMode );
207+
208+ Drawable finalTrackDrawable ;
209+ if (trackDrawable != null && trackDecorationDrawable != null ) {
210+ finalTrackDrawable =
211+ new LayerDrawable (new Drawable []{ trackDrawable , trackDecorationDrawable });
212+ } else if (trackDrawable != null ) {
213+ finalTrackDrawable = trackDrawable ;
214+ } else {
215+ finalTrackDrawable = trackDecorationDrawable ;
216+ }
217+ super .setTrackDrawable (finalTrackDrawable );
218+ }
219+
220+ private static Drawable setDrawableTintListIfNeeded (
221+ Drawable drawable , ColorStateList tintList , Mode tintMode ) {
222+ if (drawable == null ) {
223+ return null ;
224+ }
225+ if (tintList != null ) {
226+ drawable = DrawableCompat .wrap (drawable ).mutate ();
227+ }
228+ DrawableCompat .setTintList (drawable , tintList );
229+ if (tintList != null && tintMode != null ) {
230+ DrawableCompat .setTintMode (drawable , tintMode );
231+ }
232+ return drawable ;
47233 }
48234}
0 commit comments