3535import androidx .annotation .DimenRes ;
3636import androidx .annotation .DrawableRes ;
3737import androidx .annotation .IntDef ;
38+ import androidx .annotation .NonNull ;
3839import androidx .annotation .Nullable ;
3940import androidx .annotation .Px ;
4041import androidx .annotation .RestrictTo ;
5455import android .widget .Checkable ;
5556import java .lang .annotation .Retention ;
5657import java .lang .annotation .RetentionPolicy ;
58+ import java .util .LinkedHashSet ;
5759
5860/**
5961 * A convenience class for creating a new Material button.
@@ -104,6 +106,11 @@ public interface OnCheckedChangeListener {
104106 void onCheckedChanged (MaterialButton button , boolean isChecked );
105107 }
106108
109+ /** Interface to listen for press state changes on this button. Internal use only. */
110+ interface OnPressedChangeListener {
111+ void onPressedChanged (MaterialButton button , boolean isPressed );
112+ }
113+
107114 private static final int [] CHECKABLE_STATE_SET = {android .R .attr .state_checkable };
108115 private static final int [] CHECKED_STATE_SET = {android .R .attr .state_checked };
109116
@@ -142,7 +149,10 @@ public interface OnCheckedChangeListener {
142149 @ Px private int iconLeft ;
143150 private boolean checked = false ;
144151 private boolean broadcasting = false ;
145- @ Nullable private OnCheckedChangeListener onCheckedChangeListener ;
152+
153+ private final LinkedHashSet <OnCheckedChangeListener > onCheckedChangeListeners =
154+ new LinkedHashSet <>();
155+ @ Nullable private OnPressedChangeListener onPressedChangeListenerInternal ;
146156
147157 @ IconGravity private int iconGravity ;
148158
@@ -801,12 +811,31 @@ protected int[] onCreateDrawableState(int extraSpace) {
801811 }
802812
803813 /**
804- * Register a callback to be invoked when the checked state of this MaterialButton changes.
814+ * Add a listener that will be invoked when the checked state of this MaterialButton changes. See
815+ * {@link OnCheckedChangeListener}.
816+ *
817+ * <p>Components that add a listener should take care to remove it when finished via {@link
818+ * #removeOnCheckedChangeListener(OnCheckedChangeListener)}.
819+ *
820+ * @param listener listener to add
821+ */
822+ public void addOnCheckedChangeListener (@ NonNull OnCheckedChangeListener listener ) {
823+ onCheckedChangeListeners .add (listener );
824+ }
825+
826+ /**
827+ * Remove a listener that was previously added via {@link
828+ * #addOnCheckedChangeListener(OnCheckedChangeListener)}.
805829 *
806- * @param listener the callback to call on checked state change
830+ * @param listener listener to remove
807831 */
808- public void setOnCheckedChangeListener (@ Nullable OnCheckedChangeListener listener ) {
809- onCheckedChangeListener = listener ;
832+ public void removeOnCheckedChangeListener (@ NonNull OnCheckedChangeListener listener ) {
833+ onCheckedChangeListeners .remove (listener );
834+ }
835+
836+ /** Remove all previously added {@link OnCheckedChangeListener}s. */
837+ public void clearOnCheckedChangeListeners () {
838+ onCheckedChangeListeners .clear ();
810839 }
811840
812841 @ Override
@@ -821,10 +850,9 @@ public void setChecked(boolean checked) {
821850 }
822851
823852 broadcasting = true ;
824- if ( onCheckedChangeListener != null ) {
825- onCheckedChangeListener .onCheckedChanged (this , this .checked );
853+ for ( OnCheckedChangeListener listener : onCheckedChangeListeners ) {
854+ listener .onCheckedChanged (this , this .checked );
826855 }
827-
828856 broadcasting = false ;
829857 }
830858 }
@@ -883,6 +911,22 @@ ShapeAppearanceModel getShapeAppearanceModel() {
883911 return null ;
884912 }
885913
914+ /**
915+ * Register a callback to be invoked when the pressed state of this button changes. This callback
916+ * is used for internal purpose only.
917+ */
918+ void setOnPressedChangeListenerInternal (@ Nullable OnPressedChangeListener listener ) {
919+ onPressedChangeListenerInternal = listener ;
920+ }
921+
922+ @ Override
923+ public void setPressed (boolean pressed ) {
924+ if (onPressedChangeListenerInternal != null ) {
925+ onPressedChangeListenerInternal .onPressedChanged (this , pressed );
926+ }
927+ super .setPressed (pressed );
928+ }
929+
886930 private boolean isUsingOriginalBackground () {
887931 return materialButtonHelper != null && !materialButtonHelper .isBackgroundOverwritten ();
888932 }
0 commit comments