package cn.rongcloud.im.ui.widget.switchbutton;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.StateListDrawable;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.v4.content.ContextCompat;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.SoundEffectConstants;
import android.view.ViewConfiguration;
import android.view.ViewParent;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.CompoundButton;
import cn.rongcloud.im.R;
/**
* SwitchButton
*
* @author kyleduo
* @since 2014-09-24
*/
public class SwitchButton extends CompoundButton {
public static final float DEFAULT_BACK_MEASURE_RATIO = 1.8f;
public static final int DEFAULT_THUMB_SIZE_DP = 20;
public static final int DEFAULT_THUMB_MARGIN_DP = 2;
public static final int DEFAULT_TEXT_MARGIN_DP = 2;
public static final int DEFAULT_ANIMATION_DURATION = 250;
public static final int DEFAULT_TINT_COLOR = 0x327FC2;
private static int[] CHECKED_PRESSED_STATE = new int[] {android.R.attr.state_checked, android.R.attr.state_enabled, android.R.attr.state_pressed};
private static int[] UNCHECKED_PRESSED_STATE = new int[] { -android.R.attr.state_checked, android.R.attr.state_enabled, android.R.attr.state_pressed};
private Drawable mThumbDrawable, mBackDrawable;
private ColorStateList mBackColor, mThumbColor;
private float mThumbRadius, mBackRadius;
private RectF mThumbMargin;
private float mBackMeasureRatio;
private long mAnimationDuration;
// fade back drawable or color when dragging or animating
private boolean mFadeBack;
private int mTintColor;
private PointF mThumbSizeF;
private int mCurrThumbColor, mCurrBackColor, mNextBackColor, mOnTextColor, mOffTextColor;
private Drawable mCurrentBackDrawable, mNextBackDrawable;
private RectF mThumbRectF, mBackRectF, mSafeRectF, mTextOnRectF, mTextOffRectF;
private Paint mPaint;
// whether using Drawable for thumb or back
private boolean mIsThumbUseDrawable, mIsBackUseDrawable;
private boolean mDrawDebugRect = false;
private ObjectAnimator mProcessAnimator;
// animation control
private float mProcess;
// temp position of thumb when dragging or animating
private RectF mPresentThumbRectF;
private float mStartX, mStartY, mLastX;
private int mTouchSlop;
private int mClickTimeout;
private Paint mRectPaint;
private CharSequence mTextOn;
private CharSequence mTextOff;
private TextPaint mTextPaint;
private Layout mOnLayout;
private Layout mOffLayout;
private float mTextWidth;
private float mTextHeight;
private float mTextMarginH;
public SwitchButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(attrs);
}
public SwitchButton(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public SwitchButton(Context context) {
super(context);
init(null);
}
private void init(AttributeSet attrs) {
mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
mClickTimeout = ViewConfiguration.getPressedStateDuration() + ViewConfiguration.getTapTimeout();
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mRectPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mRectPaint.setStyle(Paint.Style.STROKE);
mRectPaint.setStrokeWidth(getResources().getDisplayMetrics().density);
mTextPaint = getPaint();
mThumbRectF = new RectF();
mBackRectF = new RectF();
mSafeRectF = new RectF();
mThumbSizeF = new PointF();
mThumbMargin = new RectF();
mTextOnRectF = new RectF();
mTextOffRectF = new RectF();
mProcessAnimator = ObjectAnimator.ofFloat(this, "process", 0, 0).setDuration(DEFAULT_ANIMATION_DURATION);
mProcessAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
mPresentThumbRectF = new RectF();
Resources res = getResources();
float density = res.getDisplayMetrics().density;
Drawable thumbDrawable = null;
ColorStateList thumbColor = null;
float margin = density * DEFAULT_THUMB_MARGIN_DP;
float marginLeft = 0;
float marginRight = 0;
float marginTop = 0;
float marginBottom = 0;
float thumbWidth = density * DEFAULT_THUMB_SIZE_DP;
float thumbHeight = density * DEFAULT_THUMB_SIZE_DP;
float thumbRadius = density * DEFAULT_THUMB_SIZE_DP / 2;
float backRadius = thumbRadius;
Drawable backDrawable = null;
ColorStateList backColor = null;
float backMeasureRatio = DEFAULT_BACK_MEASURE_RATIO;
int animationDuration = DEFAULT_ANIMATION_DURATION;
boolean fadeBack = true;
int tintColor = Integer.MIN_VALUE;
String textOn = null;
String textOff = null;
float textMarginH = density * DEFAULT_TEXT_MARGIN_DP;
TypedArray ta = attrs == null ? null : getContext().obtainStyledAttributes(attrs, R.styleable.SwitchButton);
if (ta != null) {
thumbDrawable = ta.getDrawable(R.styleable.SwitchButton_kswThumbDrawable);
thumbColor = ta.getColorStateList(R.styleable.SwitchButton_kswThumbColor);
margin = ta.getDimension(R.styleable.SwitchButton_kswThumbMargin, margin);
marginLeft = ta.getDimension(R.styleable.SwitchButton_kswThumbMarginLeft, margin);
marginRight = ta.getDimension(R.styleable.SwitchButton_kswThumbMarginRight, margin);
marginTop = ta.getDimension(R.styleable.SwitchButton_kswThumbMarginTop, margin);
marginBottom = ta.getDimension(R.styleable.SwitchButton_kswThumbMarginBottom, margin);
thumbWidth = ta.getDimension(R.styleable.SwitchButton_kswThumbWidth, thumbWidth);
thumbHeight = ta.getDimension(R.styleable.SwitchButton_kswThumbHeight, thumbHeight);
thumbRadius = ta.getDimension(R.styleable.SwitchButton_kswThumbRadius, Math.min(thumbWidth, thumbHeight) / 2.f);
backRadius = ta.getDimension(R.styleable.SwitchButton_kswBackRadius, thumbRadius + density * 2f);
backDrawable = ta.getDrawable(R.styleable.SwitchButton_kswBackDrawable);
backColor = ta.getColorStateList(R.styleable.SwitchButton_kswBackColor);
backMeasureRatio = ta.getFloat(R.styleable.SwitchButton_kswBackMeasureRatio, backMeasureRatio);
animationDuration = ta.getInteger(R.styleable.SwitchButton_kswAnimationDuration, animationDuration);
fadeBack = ta.getBoolean(R.styleable.SwitchButton_kswFadeBack, true);
tintColor = ta.getColor(R.styleable.SwitchButton_kswTintColor, tintColor);
textOn = ta.getString(R.styleable.SwitchButton_kswTextOn);
textOff = ta.getString(R.styleable.SwitchButton_kswTextOff);
textMarginH = ta.getDimension(R.styleable.SwitchButton_kswTextMarginH, textMarginH);
ta.recycle();
}
// text
mTextOn = textOn;
mTextOff = textOff;
mTextMarginH = textMarginH;
// thumb drawable and color
mThumbDrawable = thumbDrawable;
mThumbColor = thumbColor;
mIsThumbUseDrawable = mThumbDrawable != null;
mTintColor = tintColor;
if (mTintColor == Integer.MIN_VALUE) {
mTintColor = DEFAULT_TINT_COLOR;
}
if (!mIsThumbUseDrawable && mThumbColor == null) {
mThumbColor = ColorUtils.generateThumbColorWithTintColor(mTintColor);
mCurrThumbColor = mThumbColor.getDefaultColor();
}
if (mIsThumbUseDrawable) {
thumbWidth = Math.max(thumbWidth, mThumbDrawable.getMinimumWidth());
thumbHeight = Math.max(thumbHeight, mThumbDrawable.getMinimumHeight());
}
mThumbSizeF.set(thumbWidth, thumbHeight);
// back drawable and color
mBackDrawable = backDrawable;
mBackColor = backColor;
mIsBackUseDrawable = mBackDrawable != null;
if (!mIsBackUseDrawable && mBackColor == null) {
mBackColor = ColorUtils.generateBackColorWithTintColor(mTintColor);
mCurrBackColor = mBackColor.getDefaultColor();
mNextBackColor = mBackColor.getColorForState(CHECKED_PRESSED_STATE, mCurrBackColor);
}
// margin
mThumbMargin.set(marginLeft, marginTop, marginRight, marginBottom);
// size & measure params must larger than 1
mBackMeasureRatio = mThumbMargin.width() >= 0 ? Math.max(backMeasureRatio, 1) : backMeasureRatio;
mThumbRadius = thumbRadius;
mBackRadius = backRadius;
mAnimationDuration = animationDuration;
mFadeBack = fadeBack;
mProcessAnimator.setDuration(mAnimationDuration);
setFocusable(true);
setClickable(true);
// sync checked status
if (isChecked()) {
setProcess(1);
}
}
private Layout makeLayout(CharSequence text) {
return new StaticLayout(text, mTextPaint, (int) Math.ceil(Layout.getDesiredWidth(text, mTextPaint)), Layout.Alignment.ALIGN_CENTER, 1.f, 0, false);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mOnLayout == null && mTextOn != null) {
mOnLayout = makeLayout(mTextOn);
}
if (mOffLayout == null && mTextOff != null) {
mOffLayout = makeLayout(mTextOff);
}
setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
}
private int measureWidth(int widthMeasureSpec) {
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int measuredWidth;
int minWidth = (int) (mThumbSizeF.x * mBackMeasureRatio);
if (mIsBackUseDrawable) {
minWidth = Math.max(minWidth, mBackDrawable.getMinimumWidth());
}
float onWidth = mOnLayout != null ? mOnLayout.getWidth() : 0;
float offWidth = mOffLayout != null ? mOffLayout.getWidth() : 0;
if (onWidth != 0 || offWidth != 0) {
mTextWidth = Math.max(onWidth, offWidth) + mTextMarginH * 2;
float left = minWidth - mThumbSizeF.x;
if (left < mTextWidth) {
minWidth += mTextWidth - left;
}
}
minWidth = Math.max(minWidth, (int) (minWidth + mThumbMargin.left + mThumbMargin.right));
minWidth = Math.max(minWidth, minWidth + getPaddingLeft() + getPaddingRight());
minWidth = Math.max(minWidth, getSuggestedMinimumWidth());
if (widthMode == MeasureSpec.EXACTLY) {
measuredWidth = Math.max(minWidth, widthSize);
} else {
measuredWidth = minWidth;
if (widthMode == MeasureSpec.AT_MOST) {
measuredWidth = Math.min(measuredWidth, widthSize);
}
}
return measuredWidth;
}
private int measureHeight(int heightMeasureSpec) {
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int measuredHeight;
int minHeight = (int) Math.max(mThumbSizeF.y, mThumbSizeF.y + mThumbMargin.top + mThumbMargin.right);
float onHeight = mOnLayout != null ? mOnLayout.getHeight() : 0;
float offHeight = mOffLayout != null ? mOffLayout.getHeight() : 0;
if (onHeight != 0 || offHeight != 0) {
mTextHeight = Math.max(onHeight, offHeight);
minHeight = (int) Math.max(minHeight, mTextHeight);
}
minHeight = Math.max(minHeight, getSuggestedMinimumHeight());
minHeight = Math.max(minHeight, minHeight + getPaddingTop() + getPaddingBottom());
if (heightMode == MeasureSpec.EXACTLY) {
measuredHeight = Math.max(minHeight, heightSize);
} else {
measuredHeight = minHeight;
if (heightMode == MeasureSpec.AT_MOST) {
measuredHeight = Math.min(measuredHeight, heightSize);
}
}
return measuredHeight;
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (w != oldw || h != oldh) {
setup();
}
}
/**
* set up the rect of back and thumb
*/
private void setup() {
float thumbTop = getPaddingTop() + Math.max(0, mThumbMargin.top);
float thumbLeft = getPaddingLeft() + Math.max(0, mThumbMargin.left);
if (mOnLayout != null && mOffLayout != null) {
if (mThumbMargin.top + mThumbMargin.bottom > 0) {
// back is higher than thumb
float addition = (getMeasuredHeight() - getPaddingBottom() - getPaddingTop() - mThumbSizeF.y - mThumbMargin.top - mThumbMargin.bottom) / 2;
thumbTop += addition;
}
}
if (mIsThumbUseDrawable) {
mThumbSizeF.x = Math.max(mThumbSizeF.x, mThumbDrawable.getMinimumWidth());
mThumbSizeF.y = Math.max(mThumbSizeF.y, mThumbDrawable.getMinimumHeight());
}
mThumbRectF.set(thumbLeft, thumbTop, thumbLeft + mThumbSizeF.x, thumbTop + mThumbSizeF.y);
float backLeft = mThumbRectF.left - mThumbMargin.left;
float textDiffWidth = Math.min(0, (Math.max(mThumbSizeF.x * mBackMeasureRatio, mThumbSizeF.x + mTextWidth) - mThumbRectF.width() - mTextWidth) / 2);
float textDiffHeight = Math.min(0, (mThumbRectF.height() + mThumbMargin.top + mThumbMargin.bottom - mTextHeight) / 2);
mBackRectF.set(backLeft + textDiffWidth,
mThumbRectF.top - mThumbMargin.top + textDiffHeight,
backLeft + mThumbMargin.left + Math.max(mThumbSizeF.x * mBackMeasureRatio, mThumbSizeF.x + mTextWidth) + mThumbMargin.right - textDiffWidth,
mThumbRectF.bottom + mThumbMargin.bottom - textDiffHeight);
mSafeRectF.set(mThumbRectF.left, 0, mBackRectF.right - mThumbMargin.right - mThumbRectF.width(), 0);
float minBackRadius = Math.min(mBackRectF.width(), mBackRectF.height()) / 2.f;
mBackRadius = Math.min(minBackRadius, mBackRadius);
if (mBackDrawable != null) {
mBackDrawable.setBounds((int) mBackRectF.left, (int) mBackRectF.top, (int) mBackRectF.right, (int) mBackRectF.bottom);
}
if (mOnLayout != null) {
float marginOnX = mBackRectF.left + (mBackRectF.width() - mThumbRectF.width() - mOnLayout.getWidth()) / 2 - mThumbMargin.left + mTextMarginH * (mThumbMargin.left > 0 ? 1 : -1);
float marginOnY = mBackRectF.top + (mBackRectF.height() - mOnLayout.getHeight()) / 2;
mTextOnRectF.set(marginOnX, marginOnY, marginOnX + mOnLayout.getWidth(), marginOnY + mOnLayout.getHeight());
}
if (mOffLayout != null) {
float marginOffX = mBackRectF.right - (mBackRectF.width() - mThumbRectF.width() - mOffLayout.getWidth()) / 2 + mThumbMargin.right - mOffLayout.getWidth() - mTextMarginH * (mThumbMargin.right > 0 ? 1 : -1);
float marginOffY = mBackRectF.top + (mBackRectF.height() - mOffLayout.getHeight()) / 2;
mTextOffRectF.set(marginOffX, marginOffY, marginOffX + mOffLayout.getWidth(), marginOffY + mOffLayout.getHeight());
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// fade back
if (mIsBackUseDrawable) {
if (mFadeBack && mCurrentBackDrawable != null && mNextBackDrawable != null) {
int alpha = (int) (255 * (isChecked() ? getProcess() : (1 - getProcess())));
mCurrentBackDrawable.setAlpha(alpha);
mCurrentBackDrawable.draw(canvas);
alpha = 255 - alpha;
mNextBackDrawable.setAlpha(alpha);
mNextBackDrawable.draw(canvas);
} else {
mBackDrawable.setAlpha(255);
mBackDrawable.draw(canvas);
}
} else {
if (mFadeBack) {
int alpha;
int colorAlpha;
// curr back
alpha = (int) (255 * (isChecked() ? getProcess() : (1 - getProcess())));
colorAlpha = Color.alpha(mCurrBackColor);
colorAlpha = colorAlpha * alpha / 255;
mPaint.setARGB(colorAlpha, Color.red(mCurrBackColor), Color.green(mCurrBackColor), Color.blue(mCurrBackColor));
canvas.drawRoundRect(mBackRectF, mBackRadius, mBackRadius, mPaint);
// next back
alpha = 255 - alpha;
colorAlpha = Color.alpha(mNextBackColor);
colorAlpha = colorAlpha * alpha / 255;
mPaint.setARGB(colorAlpha, Color.red(mNextBackColor), Color.green(mNextBackColor), Color.blue(mNextBackColor));
canvas.drawRoundRect(mBackRectF, mBackRadius, mBackRadius, mPaint);
mPaint.setAlpha(255);
} else {
mPaint.setColor(mCurrBackColor);
canvas.drawRoundRect(mBackRectF, mBackRadius, mBackRadius, mPaint);
}
}
// text
Layout switchText = getProcess() > 0.5 ? mOnLayout : mOffLayout;
RectF textRectF = getProcess() > 0.5 ? mTextOnRectF : mTextOffRectF;
if (switchText != null && textRectF != null) {
int alpha = (int) (255 * (getProcess() >= 0.75 ? getProcess() * 4 - 3 : (getProcess() < 0.25 ? 1 - getProcess() * 4 : 0)));
int textColor = getProcess() > 0.5 ? mOnTextColor : mOffTextColor;
int colorAlpha = Color.alpha(textColor);
colorAlpha = colorAlpha * alpha / 255;
switchText.getPaint().setARGB(colorAlpha, Color.red(textColor), Color.green(textColor), Color.blue(textColor));
canvas.save();
canvas.translate(textRectF.left, textRectF.top);
switchText.draw(canvas);
canvas.restore();
}
// thumb
mPresentThumbRectF.set(mThumbRectF);
mPresentThumbRectF.offset(mProcess * mSafeRectF.width(), 0);
if (mIsThumbUseDrawable) {
mThumbDrawable.setBounds((int) mPresentThumbRectF.left, (int) mPresentThumbRectF.top, (int) mPresentThumbRectF.right, (int) mPresentThumbRectF.bottom);
mThumbDrawable.draw(canvas);
} else {
mPaint.setColor(mCurrThumbColor);
canvas.drawRoundRect(mPresentThumbRectF, mThumbRadius, mThumbRadius, mPaint);
}
if (mDrawDebugRect) {
mRectPaint.setColor(Color.parseColor("#AA0000"));
canvas.drawRect(mBackRectF, mRectPaint);
mRectPaint.setColor(Color.parseColor("#0000FF"));
canvas.drawRect(mPresentThumbRectF, mRectPaint);
mRectPaint.setColor(Color.parseColor("#00CC00"));
canvas.drawRect(getProcess() > 0.5 ? mTextOnRectF : mTextOffRectF, mRectPaint);
}
}
@Override
protected void drawableStateChanged() {
super.drawableStateChanged();
if (!mIsThumbUseDrawable && mThumbColor != null) {
mCurrThumbColor = mThumbColor.getColorForState(getDrawableState(), mCurrThumbColor);
} else {
setDrawableState(mThumbDrawable);
}
int[] nextState = isChecked() ? UNCHECKED_PRESSED_STATE : CHECKED_PRESSED_STATE;
ColorStateList textColors = getTextColors();
if (textColors != null) {
int defaultTextColor = textColors.getDefaultColor();
mOnTextColor = textColors.getColorForState(CHECKED_PRESSED_STATE, defaultTextColor);
mOffTextColor = textColors.getColorForState(UNCHECKED_PRESSED_STATE, defaultTextColor);
}
if (!mIsBackUseDrawable && mBackColor != null) {
mCurrBackColor = mBackColor.getColorForState(getDrawableState(), mCurrBackColor);
mNextBackColor = mBackColor.getColorForState(nextState, mCurrBackColor);
} else {
if (mBackDrawable instanceof StateListDrawable && mFadeBack) {
mBackDrawable.setState(nextState);
mNextBackDrawable = mBackDrawable.getCurrent().mutate();
} else {
mNextBackDrawable = null;
}
setDrawableState(mBackDrawable);
if (mBackDrawable != null) {
mCurrentBackDrawable = mBackDrawable.getCurrent().mutate();
}
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (!isEnabled() || !isClickable()) {
return false;
}
int action = event.getAction();
float deltaX = event.getX() - mStartX;
float deltaY = event.getY() - mStartY;
// status the view going to change to when finger released
boolean nextStatus;
switch (action) {
case MotionEvent.ACTION_DOWN:
catchView();
mStartX = event.getX();
mStartY = event.getY();
mLastX = mStartX;
setPressed(true);
break;
case MotionEvent.ACTION_MOVE:
float x = event.getX();
setProcess(getProcess() + (x - mLastX) / mSafeRectF.width());
mLastX = x;
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
setPressed(false);
nextStatus = getStatusBasedOnPos();
float time = event.getEventTime() - event.getDownTime();
if (deltaX < mTouchSlop && deltaY < mTouchSlop && time < mClickTimeout) {
performClick();
} else {
if (nextStatus != isChecked()) {
playSoundEffect(SoundEffectConstants.CLICK);
setChecked(nextStatus);
} else {
animateToState(nextStatus);
}
}
break;
default:
break;
}
return true;
}
/**
* return the status based on position of thumb
*
* @return
*/
private boolean getStatusBasedOnPos() {
return getProcess() > 0.5f;
}
public final float getProcess() {
return mProcess;
}
public final void setProcess(final float process) {
float tp = process;
if (tp > 1) {
tp = 1;
} else if (tp < 0) {
tp = 0;
}
this.mProcess = tp;
invalidate();
}
@Override
public boolean performClick() {
return super.performClick();
}
/**
* processing animation
*
* @param checked checked or unChecked
*/
protected void animateToState(boolean checked) {
if (mProcessAnimator == null) {
return;
}
if (mProcessAnimator.isRunning()) {
mProcessAnimator.cancel();
}
mProcessAnimator.setDuration(mAnimationDuration);
if (checked) {
mProcessAnimator.setFloatValues(mProcess, 1f);
} else {
mProcessAnimator.setFloatValues(mProcess, 0);
}
mProcessAnimator.start();
}
private void catchView() {
ViewParent parent = getParent();
if (parent != null) {
parent.requestDisallowInterceptTouchEvent(true);
}
}
@Override
public void setChecked(final boolean checked) {
// animate before super.setChecked() become user may call setChecked again in OnCheckedChangedListener
if (isChecked() != checked) {
animateToState(checked);
}
super.setChecked(checked);
}
public void setCheckedImmediately(boolean checked) {
super.setChecked(checked);
if (mProcessAnimator != null && mProcessAnimator.isRunning()) {
mProcessAnimator.cancel();
}
setProcess(checked ? 1 : 0);
invalidate();
}
public void toggleImmediately() {
setCheckedImmediately(!isChecked());
}
private void setDrawableState(Drawable drawable) {
if (drawable != null) {
int[] myDrawableState = getDrawableState();
drawable.setState(myDrawableState);
invalidate();
}
}
public boolean isDrawDebugRect() {
return mDrawDebugRect;
}
public void setDrawDebugRect(boolean drawDebugRect) {
mDrawDebugRect = drawDebugRect;
invalidate();
}
public long getAnimationDuration() {
return mAnimationDuration;
}
public void setAnimationDuration(long animationDuration) {
mAnimationDuration = animationDuration;
}
public Drawable getThumbDrawable() {
return mThumbDrawable;
}
public void setThumbDrawable(Drawable thumbDrawable) {
mThumbDrawable = thumbDrawable;
mIsThumbUseDrawable = mThumbDrawable != null;
setup();
refreshDrawableState();
requestLayout();
invalidate();
}
public void setThumbDrawableRes(int thumbDrawableRes) {
setThumbDrawable(ContextCompat.getDrawable(getContext(), thumbDrawableRes));
}
public Drawable getBackDrawable() {
return mBackDrawable;
}
public void setBackDrawable(Drawable backDrawable) {
mBackDrawable = backDrawable;
mIsBackUseDrawable = mBackDrawable != null;
setup();
refreshDrawableState();
requestLayout();
invalidate();
}
public void setBackDrawableRes(int backDrawableRes) {
setBackDrawable(ContextCompat.getDrawable(getContext(), backDrawableRes));
}
public ColorStateList getBackColor() {
return mBackColor;
}
public void setBackColor(ColorStateList backColor) {
mBackColor = backColor;
if (mBackColor != null) {
setBackDrawable(null);
}
invalidate();
}
public void setBackColorRes(int backColorRes) {
// setBackColor(ContextCompat.getColorStateList(getContext(), backColorRes));
}
public ColorStateList getThumbColor() {
return mThumbColor;
}
public void setThumbColor(ColorStateList thumbColor) {
mThumbColor = thumbColor;
if (mThumbColor != null) {
setThumbDrawable(null);
}
}
public void setThumbColorRes(int thumbColorRes) {
// setThumbColor(ContextCompat.getColorStateList(getContext(), thumbColorRes));
}
public float getBackMeasureRatio() {
return mBackMeasureRatio;
}
public void setBackMeasureRatio(float backMeasureRatio) {
mBackMeasureRatio = backMeasureRatio;
requestLayout();
}
public RectF getThumbMargin() {
return mThumbMargin;
}
public void setThumbMargin(RectF thumbMargin) {
if (thumbMargin == null) {
setThumbMargin(0, 0, 0, 0);
} else {
setThumbMargin(thumbMargin.left, thumbMargin.top, thumbMargin.right, thumbMargin.bottom);
}
}
public void setThumbMargin(float left, float top, float right, float bottom) {
mThumbMargin.set(left, top, right, bottom);
requestLayout();
}
public void setThumbSize(float width, float height) {
mThumbSizeF.set(width, height);
setup();
requestLayout();
}
public float getThumbWidth() {
return mThumbSizeF.x;
}
public float getThumbHeight() {
return mThumbSizeF.y;
}
public void setThumbSize(PointF size) {
if (size == null) {
float defaultSize = getResources().getDisplayMetrics().density * DEFAULT_THUMB_SIZE_DP;
setThumbSize(defaultSize, defaultSize);
} else {
setThumbSize(size.x, size.y);
}
}
public PointF getThumbSizeF() {
return mThumbSizeF;
}
public float getThumbRadius() {
return mThumbRadius;
}
public void setThumbRadius(float thumbRadius) {
mThumbRadius = thumbRadius;
if (!mIsThumbUseDrawable) {
invalidate();
}
}
public PointF getBackSizeF() {
return new PointF(mBackRectF.width(), mBackRectF.height());
}
public float getBackRadius() {
return mBackRadius;
}
public void setBackRadius(float backRadius) {
mBackRadius = backRadius;
if (!mIsBackUseDrawable) {
invalidate();
}
}
public boolean isFadeBack() {
return mFadeBack;
}
public void setFadeBack(boolean fadeBack) {
mFadeBack = fadeBack;
}
public int getTintColor() {
return mTintColor;
}
public void setTintColor(int tintColor) {
mTintColor = tintColor;
mThumbColor = ColorUtils.generateThumbColorWithTintColor(mTintColor);
mBackColor = ColorUtils.generateBackColorWithTintColor(mTintColor);
mIsBackUseDrawable = false;
mIsThumbUseDrawable = false;
// call this method to refresh color states
refreshDrawableState();
invalidate();
}
public void setText(CharSequence onText, CharSequence offText) {
mTextOn = onText;
mTextOff = offText;
mOnLayout = null;
mOffLayout = null;
requestLayout();
}
@Override
public Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
ss.onText = mTextOn;
ss.offText = mTextOff;
return ss;
}
@Override
public void onRestoreInstanceState(Parcelable state) {
SavedState ss = (SavedState) state;
setText(ss.onText, ss.offText);
super.onRestoreInstanceState(ss.getSuperState());
}
static class SavedState extends BaseSavedState {
CharSequence onText;
CharSequence offText;
SavedState(Parcelable superState) {
super(superState);
}
private SavedState(Parcel in) {
super(in);
onText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
offText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
}
@Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
TextUtils.writeToParcel(onText, out, flags);
TextUtils.writeToParcel(offText, out, flags);
}
public static final Creator<SavedState> CREATOR
= new Creator<SavedState>() {
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
}