package com.dd.xda; import com.dd.circular.progress.button.R; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.os.Parcel; import android.os.Parcelable; import android.util.AttributeSet; import android.widget.ImageButton; public class CircularProgressButton extends ImageButton { public static final int IDLE_STATE_PROGRESS = 0; private CircularAnimatedDrawable mAnimatedDrawable; private StateManager mStateManager; private State mState; private int mColorIndicator; private int mStrokeWidth; private int mPaddingProgress; private float mProgress; private boolean mMorphingInProgress; private int mDefaultSource; 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); } protected static TypedArray getTypedArray(Context context, AttributeSet attributeSet, int[] attr) { return context.obtainStyledAttributes(attributeSet, attr, 0, 0); } private void init(Context context, AttributeSet attributeSet) { mStrokeWidth = (int) getContext().getResources().getDimension(R.dimen.cpb_stroke_width); initAttributes(context, attributeSet); mState = State.IDLE; mStateManager = new StateManager(this); } private void initAttributes(Context context, AttributeSet attributeSet) { TypedArray attr = getTypedArray(context, attributeSet, R.styleable.CircularProgressButton); if (attr == null) { return; } try { mPaddingProgress = attr.getDimensionPixelSize(R.styleable .CircularProgressButton_cpb_paddingProgress, 0); int blue = getColor(R.color.cpb_blue); mColorIndicator = attr.getColor(R.styleable .CircularProgressButton_cpb_colorIndicator, blue); } finally { attr.recycle(); } } protected int getColor(int id) { return getResources().getColor(id); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (mProgress > 0 && mState == State.PROGRESS && !mMorphingInProgress) { drawIndeterminateProgress(canvas); } } private void drawIndeterminateProgress(Canvas canvas) { if (mAnimatedDrawable == null) { int offset = (getWidth() - getHeight()) / 2; mAnimatedDrawable = new CircularAnimatedDrawable(mColorIndicator, mStrokeWidth); int left = offset + mPaddingProgress; int right = getWidth() - offset - mPaddingProgress; int bottom = getHeight() - mPaddingProgress; int top = mPaddingProgress; mAnimatedDrawable.setBounds(left, top, right, bottom); mAnimatedDrawable.setCallback(this); mAnimatedDrawable.start(); } else { mAnimatedDrawable.draw(canvas); } } @Override protected boolean verifyDrawable(Drawable who) { return who == mAnimatedDrawable || super.verifyDrawable(who); } private void morphToProgress() { removeIcon(); mMorphingInProgress = false; mState = State.PROGRESS; mStateManager.checkState(CircularProgressButton.this); } private void morphProgressToIdle() { setImageResource(mDefaultSource); mMorphingInProgress = false; mState = State.IDLE; mStateManager.checkState(CircularProgressButton.this); } protected void removeIcon() { setImageDrawable(null); } public float getProgress() { return mProgress; } public void setProgress(float progress) { mProgress = progress; if (mMorphingInProgress || getWidth() == 0) { return; } mStateManager.saveProgress(this); if (mProgress > IDLE_STATE_PROGRESS) { if (mState == State.IDLE) { morphToProgress(); } else if (mState == State.PROGRESS) { invalidate(); } } else if (mProgress == IDLE_STATE_PROGRESS) { if (mState == State.PROGRESS) { morphProgressToIdle(); } } } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); if (changed) { setProgress(mProgress); } } @Override public Parcelable onSaveInstanceState() { Parcelable superState = super.onSaveInstanceState(); SavedState savedState = new SavedState(superState); savedState.mProgress = mProgress; return savedState; } @Override public void onRestoreInstanceState(Parcelable state) { if (state instanceof SavedState) { SavedState savedState = (SavedState) state; mProgress = savedState.mProgress; super.onRestoreInstanceState(savedState.getSuperState()); setProgress(mProgress); } else { super.onRestoreInstanceState(state); } } @Override public void setImageResource(final int defaultBackground) { mDefaultSource = defaultBackground; if (mState == State.IDLE) { super.setImageResource(mDefaultSource); } } private enum State { PROGRESS, IDLE } static class SavedState extends BaseSavedState { public static final Creator<SavedState> CREATOR = new Creator<SavedState>() { @Override public SavedState createFromParcel(Parcel in) { return new SavedState(in); } @Override public SavedState[] newArray(int size) { return new SavedState[size]; } }; private float mProgress; public SavedState(Parcelable parcel) { super(parcel); } private SavedState(Parcel in) { super(in); mProgress = in.readInt(); } @Override public void writeToParcel(Parcel out, int flags) { super.writeToParcel(out, flags); out.writeFloat(mProgress); } } }