ReactSwitch.java
104 lines
/*
/*
* Copyright (c) Facebook, Inc. and its affiliates.
* Copyright (c) Facebook, Inc. and its affiliates.
*
*
* This source code is licensed under the MIT license found in the
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
* LICENSE file in the root directory of this source tree.
*/
*/
package com.facebook.react.views.switchview;
package com.facebook.react.views.switchview;
import android.content.Context;
import android.content.Context;
import android.graphics.PorterDuff;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Drawable;
import androidx.annotation.Nullable;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.SwitchCompat;
import androidx.appcompat.widget.SwitchCompat;
/**
/**
* Switch that has its value controlled by JS. Whenever the value of the switch changes, we do not
* Switch that has its value controlled by JS. Whenever the value of the switch changes, we do not
* allow any other changes to that switch until JS sets a value explicitly. This stops the Switch
* allow any other changes to that switch until JS sets a value explicitly. This stops the Switch
* from changing its value multiple times, when those changes have not been processed by JS first.
* from changing its value multiple times, when those changes have not been processed by JS first.
*/
*/
/*package*/ class ReactSwitch extends SwitchCompat {
/*package*/ class ReactSwitch extends SwitchCompat {
private boolean mAllowChange;
private boolean mAllowChange;
@Nullable private Integer mTrackColorForFalse;
@Nullable private Integer mTrackColorForFalse;
@Nullable private Integer mTrackColorForTrue;
@Nullable private Integer mTrackColorForTrue;
public ReactSwitch(Context context) {
public ReactSwitch(Context context) {
super(context);
super(context);
mAllowChange = true;
mAllowChange = true;
mTrackColorForFalse = null;
mTrackColorForFalse = null;
mTrackColorForTrue = null;
mTrackColorForTrue = null;
}
}
@Override
@Override
public void setChecked(boolean checked) {
public void setChecked(boolean checked) {
if (mAllowChange && isChecked() != checked) {
if (mAllowChange && isChecked() != checked) {
mAllowChange = false;
mAllowChange = false;
super.setChecked(checked);
super.setChecked(checked);
setTrackColor(checked);
setTrackColor(checked);
} else {
} else {
// Even if mAllowChange is set to false or the checked value hasn't changed, we still must
// Even if mAllowChange is set to false or the checked value hasn't changed, we still must
// call the super method, since it will make sure the thumb is moved back to the correct edge.
// call the super method, since it will make sure the thumb is moved back to the correct edge.
// Without calling the super method, the thumb might stuck in the middle of the switch.
// Without calling the super method, the thumb might stuck in the middle of the switch.
super.setChecked(isChecked());
super.setChecked(isChecked());
}
}
}
}
void setColor(Drawable drawable, @Nullable Integer color) {
void setColor(Drawable drawable, @Nullable Integer color) {
if (color == null) {
if (color == null) {
drawable.clearColorFilter();
drawable.clearColorFilter();
} else {
} else {
drawable.setColorFilter(color, PorterDuff.Mode.MULTIPLY);
drawable.setColorFilter(color, PorterDuff.Mode.MULTIPLY);
}
}
}
}
public void setTrackColor(@Nullable Integer color) {
public void setTrackColor(@Nullable Integer color) {
setColor(super.getTrackDrawable(), color);
setColor(super.getTrackDrawable(), color);
}
}
public void setThumbColor(@Nullable Integer color) {
public void setThumbColor(@Nullable Integer color) {
setColor(super.getThumbDrawable(), color);
setColor(super.getThumbDrawable(), color);
}
}
/*package*/ void setOn(boolean on) {
/*package*/ void setOn(boolean on) {
// If the switch has a different value than the value sent by JS, we must change it.
// If the switch has a different value than the value sent by JS, we must change it.
if (isChecked() != on) {
if (isChecked() != on) {
super.setChecked(on);
super.setChecked(on);
setTrackColor(on);
setTrackColor(on);
}
}
mAllowChange = true;
mAllowChange = true;
}
}
public void setTrackColorForTrue(@Nullable Integer color) {
public void setTrackColorForTrue(@Nullable Integer color) {
if (color == mTrackColorForTrue) {
if (color == mTrackColorForTrue) {
return;
return;
}
}
mTrackColorForTrue = color;
mTrackColorForTrue = color;
if (isChecked()) {
if (isChecked()) {
setTrackColor(mTrackColorForTrue);
setTrackColor(mTrackColorForTrue);
}
}
}
}
public void setTrackColorForFalse(@Nullable Integer color) {
public void setTrackColorForFalse(@Nullable Integer color) {
if (color == mTrackColorForFalse) {
if (color == mTrackColorForFalse) {
return;
return;
}
}
mTrackColorForFalse = color;
mTrackColorForFalse = color;
if (!isChecked()) {
if (!isChecked()) {
setTrackColor(mTrackColorForFalse);
setTrackColor(mTrackColorForFalse);
}
}
}
}
public void setWidth(@Nullable Float width) {
if (width == null) {
return;
}
// given width is in dp, but setSwitchMinWidth method needs input in pixels.
setSwitchMinWidth(dpToPixels(width));
}
private void setTrackColor(boolean checked) {
private void setTrackColor(boolean checked) {
if (mTrackColorForTrue != null || mTrackColorForFalse != null) {
if (mTrackColorForTrue != null || mTrackColorForFalse != null) {
// Update the track color to reflect the new value. We only want to do this if these
// Update the track color to reflect the new value. We only want to do this if these
// props were actually set from JS; otherwise we'll just reset the color to the default.
// props were actually set from JS; otherwise we'll just reset the color to the default.
Integer currentTrackColor = checked ? mTrackColorForTrue : mTrackColorForFalse;
Integer currentTrackColor = checked ? mTrackColorForTrue : mTrackColorForFalse;
setTrackColor(currentTrackColor);
setTrackColor(currentTrackColor);
}
}
}
}
private float dpToPixels(float dp) {
return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
dp,
getContext().getResources().getDisplayMetrics()
);
}
}
}