Skip to content

Instantly share code, notes, and snippets.

@ixiyang
Last active August 29, 2015 14:03
Show Gist options
  • Save ixiyang/9ebdeeb2560fb98903d4 to your computer and use it in GitHub Desktop.
Save ixiyang/9ebdeeb2560fb98903d4 to your computer and use it in GitHub Desktop.
from circleprogressbutton
public class CircularProgressButton extends Button{
public static final int IDLE_STATE_PROGRESS = 0;
public static final int ERROR_STATE_PROGRESS = -1;
private GradientDrawable background;
private State mState;
private String mIdleText;
private String mCompleteText;
private String mErrorText;
private int mColorIdle;
private int mColorError;
private int mColorProgress;
private int mColorComplete;
private int mColorIndicator;
private int mColorIndicatorBackground;
private int mIconComplete;
private int mIconError;
private float mCornerRadius;
private int mStrokeWidth;
private enum State {
PROGRESS, IDLE, COMPLETE, ERROR;
}
private int mMaxProgress;
private int mProgress;
private boolean mMorphingInProgress;
public CircularProgressButton(Context context) {
super(context);
init(context, null);
}
public CircularProgressButton(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public CircularProgressButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs);
}
private void init(Context context, AttributeSet attributeSet) {
mStrokeWidth = (int) getContext().getResources().getDimension(R.dimen.stroke_width);
initAttributes(context, attributeSet);
mMaxProgress = 100;
mState = State.IDLE;
setText(mIdleText);
background = (GradientDrawable) context.getResources().getDrawable(R.drawable.background).mutate();
background.setColor(mColorIdle);
background.setStroke(mStrokeWidth, mColorIdle);
background.setCornerRadius(mCornerRadius);
setBackgroundCompat(background);
}
private void initAttributes(Context context, AttributeSet attributeSet) {
TypedArray attr = getTypedArray(context, attributeSet, R.styleable.CircularProgressButton);
if (attr == null) {
return;
}
try {
mIdleText = attr.getString(R.styleable.CircularProgressButton_textIdle);
mCompleteText = attr.getString(R.styleable.CircularProgressButton_textComplete);
mErrorText = attr.getString(R.styleable.CircularProgressButton_textError);
mIconComplete = attr.getResourceId(R.styleable.CircularProgressButton_iconComplete, 0);
mIconError = attr.getResourceId(R.styleable.CircularProgressButton_iconError, 0);
mCornerRadius = attr.getDimension(R.styleable.CircularProgressButton_cornerRadius, 0);
int blue = getColor(R.color.blue);
int red = getColor(R.color.red);
int green = getColor(R.color.green);
int white = getColor(R.color.white);
int grey = getColor(R.color.grey);
mColorIdle = attr.getColor(R.styleable.CircularProgressButton_colorIdle, blue);
mColorError = attr.getColor(R.styleable.CircularProgressButton_colorError, red);
mColorComplete = attr.getColor(R.styleable.CircularProgressButton_colorComplete, green);
mColorProgress = attr.getColor(R.styleable.CircularProgressButton_colorProgress, white);
mColorIndicator = attr.getColor(R.styleable.CircularProgressButton_colorIndicator, blue);
mColorIndicatorBackground = attr.getColor(R.styleable.CircularProgressButton_colorIndicatorBackground, grey);
} finally {
attr.recycle();
}
}
protected int getColor(int id) {
return getResources().getColor(id);
}
protected TypedArray getTypedArray(Context context, AttributeSet attributeSet, int[] attr) {
return context.obtainStyledAttributes(attributeSet, attr, 0, 0);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mProgress > 0 && mState == State.PROGRESS && !mMorphingInProgress) {
doDraw(canvas);
}
}
private RectF mRectF;
private Paint mPaint;
private void doDraw(Canvas canvas) {
float sweepAngle = (360f / mMaxProgress) * mProgress;
int offset = (getWidth() - getHeight()) / 2;
System.err.println("getwidth==="+getWidth());
System.err.println("getHeight==="+getHeight());
Path path = new Path();
path.addArc(getRect(), -90, sweepAngle);
path.offset(offset, 0);
canvas.drawPath(path, createPaint());
}
private RectF getRect() {
if (mRectF == null) {
int index = mStrokeWidth / 2;
mRectF = new RectF(index, index, getHeight() - index, getHeight() - index);
}
return mRectF;
}
private Paint createPaint() {
if (mPaint == null) {
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(mStrokeWidth);
mPaint.setColor(mColorIndicator);
}
return mPaint;
}
private void morphToProgress() {
mMorphingInProgress = true;
setWidth(getWidth());
setText(null);
MorphingAnimation animation = new MorphingAnimation(this, background);
animation.setFromCornerRadius(mCornerRadius);
animation.setToCornerRadius(getHeight());
animation.setFromWidth(getWidth());
animation.setToWidth(getHeight());
animation.setFromColor(mColorIdle);
animation.setToColor(mColorProgress);
animation.setFromStrokeColor(mColorIdle);
animation.setToStrokeColor(mColorIndicatorBackground);
animation.setListener(new OnAnimationEndListener() {
@Override
public void onAnimationEnd() {
mMorphingInProgress = false;
mState = State.PROGRESS;
}
});
animation.start();
}
private void morphToToComplete() {
mMorphingInProgress = true;
MorphingAnimation animation = new MorphingAnimation(this, background);
animation.setFromCornerRadius(getHeight());
animation.setToCornerRadius(mCornerRadius);
animation.setFromWidth(getHeight());
animation.setToWidth(getWidth());
animation.setFromColor(mColorProgress);
animation.setToColor(mColorComplete);
animation.setFromStrokeColor(mColorIndicator);
animation.setToStrokeColor(mColorComplete);
animation.setListener(new OnAnimationEndListener() {
@Override
public void onAnimationEnd() {
if (mIconComplete != 0) {
setIcon(mIconComplete);
} else {
setText(mCompleteText);
}
mMorphingInProgress = false;
mState = State.COMPLETE;
}
});
animation.start();
}
private void morphToToError() {
mMorphingInProgress = true;
MorphingAnimation animation = new MorphingAnimation(this, background);
animation.setFromCornerRadius(getHeight());
animation.setToCornerRadius(mCornerRadius);
animation.setFromWidth(getHeight());
animation.setToWidth(getWidth());
animation.setFromColor(mColorProgress);
animation.setToColor(mColorError);
animation.setFromStrokeColor(mColorIndicator);
animation.setToStrokeColor(mColorError);
animation.setListener(new OnAnimationEndListener() {
@Override
public void onAnimationEnd() {
if (mIconComplete != 0) {
setIcon(mIconError);
} else {
setText(mErrorText);
}
mMorphingInProgress = false;
mState = State.ERROR;
}
});
animation.start();
}
private void morphToToIdle() {
background.setStroke(mStrokeWidth, mColorIdle);
background.setColor(mColorIdle);
removeIcon();
setText(mIdleText);
mMorphingInProgress = false;
mState = State.IDLE;
}
private void setIcon(int icon) {
Drawable drawable = getResources().getDrawable(icon);
if (drawable != null) {
int padding = (getWidth() / 2) - (drawable.getIntrinsicWidth() / 2);
setCompoundDrawablesWithIntrinsicBounds(icon, 0, 0, 0);
setPadding(padding, 0, 0, 0);
}
}
protected void removeIcon() {
setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
setPadding(0, 0, 0, 0);
}
/**
* Set the View's background. Masks the API changes made in Jelly Bean.
*/
@SuppressWarnings("deprecation")
@SuppressLint("NewApi")
public void setBackgroundCompat(Drawable drawable) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
setBackground(drawable);
} else {
setBackgroundDrawable(drawable);
}
}
public void setProgress(int progress) {
mProgress = progress;
if (!mMorphingInProgress) {
if (mProgress >= mMaxProgress) {
if (mState == State.PROGRESS) {
morphToToComplete();
}
} else if (mProgress > IDLE_STATE_PROGRESS) {
if (mState == State.IDLE) {
morphToProgress();
} else if (mState == State.PROGRESS) {
invalidate();
}
} else if (mProgress == ERROR_STATE_PROGRESS) {
if (mState == State.PROGRESS) {
morphToToError();
}
} else if (mProgress == IDLE_STATE_PROGRESS) {
morphToToIdle();
}
}
}
public int getProgress() {
return mProgress;
}
}
gradientdrawable
class MorphingAnimation {
private static final int ANIMATION_DURATION = 400;
private OnAnimationEndListener mListener;
private int mFromWidth;
private int mToWidth;
private int mFromColor;
private int mToColor;
private int mFromStrokeColor;
private int mToStrokeColor;
private float mFromCornerRadius;
private float mToCornerRadius;
private TextView mView;
private GradientDrawable mDrawable;
public MorphingAnimation(TextView viewGroup, GradientDrawable drawable) {
mView = viewGroup;
mDrawable = drawable;
}
public void setListener(OnAnimationEndListener listener) {
mListener = listener;
}
public void setFromWidth(int fromWidth) {
mFromWidth = fromWidth;
}
public void setToWidth(int toWidth) {
mToWidth = toWidth;
}
public void setFromColor(int fromColor) {
mFromColor = fromColor;
}
public void setToColor(int toColor) {
mToColor = toColor;
}
public void setFromStrokeColor(int fromStrokeColor) {
mFromStrokeColor = fromStrokeColor;
}
public void setToStrokeColor(int toStrokeColor) {
mToStrokeColor = toStrokeColor;
}
public void setFromCornerRadius(float fromCornerRadius) {
mFromCornerRadius = fromCornerRadius;
}
public void setToCornerRadius(float toCornerRadius) {
mToCornerRadius = toCornerRadius;
}
public void start() {
ValueAnimator widthAnimation = ValueAnimator.ofInt(mFromWidth, mToWidth);
widthAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Integer value = (Integer) animation.getAnimatedValue();
int leftOffset;
int rightOffset;
if(mFromWidth > mToWidth) {
leftOffset = (mFromWidth - value) / 2;
rightOffset = mFromWidth - leftOffset;
} else {
leftOffset = (mToWidth - value) / 2;
rightOffset = mToWidth - leftOffset;
}
mDrawable.setBounds(leftOffset, 0, rightOffset, mView.getHeight());
}
});
ValueAnimator bgColorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), mFromColor, mToColor);
bgColorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(final ValueAnimator animator) {
mDrawable.setColor((Integer) animator.getAnimatedValue());
}
});
final int strokeWidth = (int) mView.getContext().getResources().getDimension(R.dimen.stroke_width);
ValueAnimator strokeColorAnimation =
ValueAnimator.ofObject(new ArgbEvaluator(), mFromStrokeColor, mToStrokeColor);
strokeColorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(final ValueAnimator animator) {
mDrawable.setStroke(strokeWidth, (Integer) animator.getAnimatedValue());
}
});
ValueAnimator cornerAnimation = ValueAnimator.ofFloat(mFromCornerRadius, mToCornerRadius);
cornerAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Float value = (Float) animation.getAnimatedValue();
mDrawable.setCornerRadius(value);
}
});
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.setDuration(ANIMATION_DURATION);
animatorSet.playTogether(widthAnimation, bgColorAnimation, strokeColorAnimation, cornerAnimation);
animatorSet.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
if (mListener != null) {
mListener.onAnimationEnd();
}
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
animatorSet.start();
}
}
//animationset
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment