編輯:關於Android編程
public class CircularProgressDrawable extends Drawable { private float mSweepAngle; private float mStartAngle; private int mSize; private int mStrokeWidth; private int mStrokeColor; public CircularProgressDrawable(int size, int strokeWidth, int strokeColor) { mSize = size; mStrokeWidth = strokeWidth; mStrokeColor = strokeColor; mStartAngle = -90; mSweepAngle = 0; } public void setSweepAngle(float sweepAngle) { mSweepAngle = sweepAngle; } public int getSize() { return mSize; } @Override public void draw(Canvas canvas) { final Rect bounds = getBounds(); if (mPath == null) { mPath = new Path(); } mPath.reset(); mPath.addArc(getRect(), mStartAngle, mSweepAngle); mPath.offset(bounds.left, bounds.top); canvas.drawPath(mPath, createPaint()); } @Override public void setAlpha(int alpha) { } @Override public void setColorFilter(ColorFilter cf) { } @Override public int getOpacity() { return 1; } private RectF mRectF; private Paint mPaint; private Path mPath; private RectF getRect() { if (mRectF == null) { int index = mStrokeWidth / 2; mRectF = new RectF(index, index, getSize() - index, getSize() - 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(mStrokeColor); } return mPaint; } }
public class CircularAnimatedDrawable extends Drawable implements Animatable { private static final Interpolator ANGLE_INTERPOLATOR = new LinearInterpolator(); private static final Interpolator SWEEP_INTERPOLATOR = new DecelerateInterpolator(); private static final int ANGLE_ANIMATOR_DURATION = 2000; private static final int SWEEP_ANIMATOR_DURATION = 600; public static final int MIN_SWEEP_ANGLE = 30; private final RectF fBounds = new RectF(); private ObjectAnimator mObjectAnimatorSweep; private ObjectAnimator mObjectAnimatorAngle; private boolean mModeAppearing; private Paint mPaint; private float mCurrentGlobalAngleOffset; private float mCurrentGlobalAngle; private float mCurrentSweepAngle; private float mBorderWidth; private boolean mRunning; public CircularAnimatedDrawable(int color, float borderWidth) { mBorderWidth = borderWidth; mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(borderWidth); mPaint.setColor(color); setupAnimations(); } @Override public void draw(Canvas canvas) { float startAngle = mCurrentGlobalAngle - mCurrentGlobalAngleOffset; float sweepAngle = mCurrentSweepAngle; if (!mModeAppearing) { startAngle = startAngle + sweepAngle; sweepAngle = 360 - sweepAngle - MIN_SWEEP_ANGLE; } else { sweepAngle += MIN_SWEEP_ANGLE; } canvas.drawArc(fBounds, startAngle, sweepAngle, false, mPaint); } @Override public void setAlpha(int alpha) { mPaint.setAlpha(alpha); } @Override public void setColorFilter(ColorFilter cf) { mPaint.setColorFilter(cf); } @Override public int getOpacity() { return PixelFormat.TRANSPARENT; } private void toggleAppearingMode() { mModeAppearing = !mModeAppearing; if (mModeAppearing) { mCurrentGlobalAngleOffset = (mCurrentGlobalAngleOffset + MIN_SWEEP_ANGLE * 2) % 360; } } @Override protected void onBoundsChange(Rect bounds) { super.onBoundsChange(bounds); fBounds.left = bounds.left + mBorderWidth / 2f + .5f; fBounds.right = bounds.right - mBorderWidth / 2f - .5f; fBounds.top = bounds.top + mBorderWidth / 2f + .5f; fBounds.bottom = bounds.bottom - mBorderWidth / 2f - .5f; } private PropertymAngleProperty = new Property (Float.class, "angle") { @Override public Float get(CircularAnimatedDrawable object) { return object.getCurrentGlobalAngle(); } @Override public void set(CircularAnimatedDrawable object, Float value) { object.setCurrentGlobalAngle(value); } }; private Property mSweepProperty = new Property (Float.class, "arc") { @Override public Float get(CircularAnimatedDrawable object) { return object.getCurrentSweepAngle(); } @Override public void set(CircularAnimatedDrawable object, Float value) { object.setCurrentSweepAngle(value); } }; private void setupAnimations() { mObjectAnimatorAngle = ObjectAnimator.ofFloat(this, mAngleProperty, 360f); mObjectAnimatorAngle.setInterpolator(ANGLE_INTERPOLATOR); mObjectAnimatorAngle.setDuration(ANGLE_ANIMATOR_DURATION); mObjectAnimatorAngle.setRepeatMode(ValueAnimator.RESTART); mObjectAnimatorAngle.setRepeatCount(ValueAnimator.INFINITE); mObjectAnimatorSweep = ObjectAnimator.ofFloat(this, mSweepProperty, 360f - MIN_SWEEP_ANGLE * 2); mObjectAnimatorSweep.setInterpolator(SWEEP_INTERPOLATOR); mObjectAnimatorSweep.setDuration(SWEEP_ANIMATOR_DURATION); mObjectAnimatorSweep.setRepeatMode(ValueAnimator.RESTART); mObjectAnimatorSweep.setRepeatCount(ValueAnimator.INFINITE); mObjectAnimatorSweep.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { toggleAppearingMode(); } }); } @Override public void start() { if (isRunning()) { return; } mRunning = true; mObjectAnimatorAngle.start(); mObjectAnimatorSweep.start(); invalidateSelf(); } @Override public void stop() { if (!isRunning()) { return; } mRunning = false; mObjectAnimatorAngle.cancel(); mObjectAnimatorSweep.cancel(); invalidateSelf(); } @Override public boolean isRunning() { return mRunning; } public void setCurrentGlobalAngle(float currentGlobalAngle) { mCurrentGlobalAngle = currentGlobalAngle; invalidateSelf(); } public float getCurrentGlobalAngle() { return mCurrentGlobalAngle; } public void setCurrentSweepAngle(float currentSweepAngle) { mCurrentSweepAngle = currentSweepAngle; invalidateSelf(); } public float getCurrentSweepAngle() { return mCurrentSweepAngle; } }
public class CircularProgressButton extends Button { //Button的狀態值 public static final int IDLE_STATE_PROGRESS = 0; public static final int ERROR_STATE_PROGRESS = -1; public static final int SUCCESS_STATE_PROGRESS = 100; public static final int INDETERMINATE_STATE_PROGRESS = 50; private StrokeGradientDrawable background; //切換的兩個Drawable private CircularAnimatedDrawable mAnimatedDrawable; private CircularProgressDrawable mProgressDrawable; //定義不同狀態下的字體顏色ColorStateList private ColorStateList mIdleColorState; private ColorStateList mCompleteColorState; private ColorStateList mErrorColorState; //Button對應的不同狀態的Drawable private StateListDrawable mIdleStateDrawable; private StateListDrawable mCompleteStateDrawable; private StateListDrawable mErrorStateDrawable; //狀態管理器 private StateManager mStateManager; private State mState; //狀態 private String mIdleText; //Idle狀態下的文字 private String mCompleteText; //Complete時的文字 private String mErrorText; //Error時的文字 private String mProgressText; //進度條文字 private int mColorProgress; private int mColorIndicator; private int mColorIndicatorBackground; private int mIconComplete; private int mIconError; private int mStrokeWidth; private int mPaddingProgress; private float mCornerRadius; private boolean mIndeterminateProgressMode; private boolean mConfigurationChanged; //枚舉類型的狀態 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.cpb_stroke_width); initAttributes(context, attributeSet); mMaxProgress = 100; mState = State.IDLE; mStateManager = new StateManager(this); setText(mIdleText); //狀態初始化為Idle靜止狀態 initIdleStateDrawable(); setBackgroundCompat(mIdleStateDrawable); } //設置為Error狀態 private void initErrorStateDrawable() { int colorPressed = getPressedColor(mErrorColorState); StrokeGradientDrawable drawablePressed = createDrawable(colorPressed); mErrorStateDrawable = new StateListDrawable(); //給ErrorStateDrawable添加狀態。 mErrorStateDrawable.addState(new int[]{android.R.attr.state_pressed}, drawablePressed.getGradientDrawable()); mErrorStateDrawable.addState(StateSet.WILD_CARD, background.getGradientDrawable()); } //初始化Complete狀態的StateListDrawable private void initCompleteStateDrawable() { int colorPressed = getPressedColor(mCompleteColorState); StrokeGradientDrawable drawablePressed = createDrawable(colorPressed); mCompleteStateDrawable = new StateListDrawable(); mCompleteStateDrawable.addState(new int[]{android.R.attr.state_pressed}, drawablePressed.getGradientDrawable()); mCompleteStateDrawable.addState(StateSet.WILD_CARD, background.getGradientDrawable()); } private void initIdleStateDrawable() { int colorNormal = getNormalColor(mIdleColorState); int colorPressed = getPressedColor(mIdleColorState); int colorFocused = getFocusedColor(mIdleColorState); int colorDisabled = getDisabledColor(mIdleColorState); if (background == null) { background = createDrawable(colorNormal); } StrokeGradientDrawable drawableDisabled = createDrawable(colorDisabled); StrokeGradientDrawable drawableFocused = createDrawable(colorFocused); StrokeGradientDrawable drawablePressed = createDrawable(colorPressed); mIdleStateDrawable = new StateListDrawable(); mIdleStateDrawable.addState(new int[]{android.R.attr.state_pressed}, drawablePressed.getGradientDrawable()); mIdleStateDrawable.addState(new int[]{android.R.attr.state_focused}, drawableFocused.getGradientDrawable()); mIdleStateDrawable.addState(new int[]{-android.R.attr.state_enabled}, drawableDisabled.getGradientDrawable()); mIdleStateDrawable.addState(StateSet.WILD_CARD, background.getGradientDrawable()); } //獲取正常狀態下的ColorStateList private int getNormalColor(ColorStateList colorStateList) { return colorStateList.getColorForState(new int[]{android.R.attr.state_enabled}, 0); } private int getPressedColor(ColorStateList colorStateList) { return colorStateList.getColorForState(new int[]{android.R.attr.state_pressed}, 0); } private int getFocusedColor(ColorStateList colorStateList) { return colorStateList.getColorForState(new int[]{android.R.attr.state_focused}, 0); } private int getDisabledColor(ColorStateList colorStateList) { return colorStateList.getColorForState(new int[]{-android.R.attr.state_enabled}, 0); } private StrokeGradientDrawable createDrawable(int color) { GradientDrawable drawable = (GradientDrawable) getResources().getDrawable(R.drawable.cpb_background).mutate(); drawable.setColor(color); drawable.setCornerRadius(mCornerRadius); StrokeGradientDrawable strokeGradientDrawable = new StrokeGradientDrawable(drawable); strokeGradientDrawable.setStrokeColor(color); strokeGradientDrawable.setStrokeWidth(mStrokeWidth); return strokeGradientDrawable; } //關鍵點,重寫drawableStateChanged方法,判斷改變的狀態,然後進行不同狀態的切換 @Override protected void drawableStateChanged() { if (mState == State.COMPLETE) { initCompleteStateDrawable(); setBackgroundCompat(mCompleteStateDrawable); } else if (mState == State.IDLE) { initIdleStateDrawable(); setBackgroundCompat(mIdleStateDrawable); } else if (mState == State.ERROR) { initErrorStateDrawable(); setBackgroundCompat(mErrorStateDrawable); } if (mState != State.PROGRESS) { super.drawableStateChanged(); } } 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_cpb_textIdle); mCompleteText = attr.getString(R.styleable.CircularProgressButton_cpb_textComplete); mErrorText = attr.getString(R.styleable.CircularProgressButton_cpb_textError); mProgressText = attr.getString(R.styleable.CircularProgressButton_cpb_textProgress); mIconComplete = attr.getResourceId(R.styleable.CircularProgressButton_cpb_iconComplete, 0); mIconError = attr.getResourceId(R.styleable.CircularProgressButton_cpb_iconError, 0); mCornerRadius = attr.getDimension(R.styleable.CircularProgressButton_cpb_cornerRadius, 0); mPaddingProgress = attr.getDimensionPixelSize(R.styleable.CircularProgressButton_cpb_paddingProgress, 0); int blue = getColor(R.color.cpb_blue); int white = getColor(R.color.cpb_white); int grey = getColor(R.color.cpb_grey); int idleStateSelector = attr.getResourceId(R.styleable.CircularProgressButton_cpb_selectorIdle, R.color.cpb_idle_state_selector); mIdleColorState = getResources().getColorStateList(idleStateSelector); int completeStateSelector = attr.getResourceId(R.styleable.CircularProgressButton_cpb_selectorComplete, R.color.cpb_complete_state_selector); mCompleteColorState = getResources().getColorStateList(completeStateSelector); int errorStateSelector = attr.getResourceId(R.styleable.CircularProgressButton_cpb_selectorError, R.color.cpb_error_state_selector); mErrorColorState = getResources().getColorStateList(errorStateSelector); mColorProgress = attr.getColor(R.styleable.CircularProgressButton_cpb_colorProgress, white); mColorIndicator = attr.getColor(R.styleable.CircularProgressButton_cpb_colorIndicator, blue); mColorIndicatorBackground = attr.getColor(R.styleable.CircularProgressButton_cpb_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) { if (mIndeterminateProgressMode) {//繪制可變弧長形式 drawIndeterminateProgress(canvas); } else {//繪制純進度條形式 drawProgress(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); } } private void drawProgress(Canvas canvas) { if (mProgressDrawable == null) { int offset = (getWidth() - getHeight()) / 2; int size = getHeight() - mPaddingProgress * 2; mProgressDrawable = new CircularProgressDrawable(size, mStrokeWidth, mColorIndicator); int left = offset + mPaddingProgress; mProgressDrawable.setBounds(left, mPaddingProgress, left, mPaddingProgress); } float sweepAngle = (360f / mMaxProgress) * mProgress; mProgressDrawable.setSweepAngle(sweepAngle); mProgressDrawable.draw(canvas); } public boolean isIndeterminateProgressMode() { return mIndeterminateProgressMode; } public void setIndeterminateProgressMode(boolean indeterminateProgressMode) { this.mIndeterminateProgressMode = indeterminateProgressMode; } @Override protected boolean verifyDrawable(Drawable who) { return who == mAnimatedDrawable || super.verifyDrawable(who); } private MorphingAnimation createMorphing() { mMorphingInProgress = true; MorphingAnimation animation = new MorphingAnimation(this, background); animation.setFromCornerRadius(mCornerRadius); animation.setToCornerRadius(mCornerRadius); animation.setFromWidth(getWidth()); animation.setToWidth(getWidth()); if (mConfigurationChanged) { animation.setDuration(MorphingAnimation.DURATION_INSTANT); } else { animation.setDuration(MorphingAnimation.DURATION_NORMAL); } mConfigurationChanged = false; return animation; } private MorphingAnimation createProgressMorphing(float fromCorner, float toCorner, int fromWidth, int toWidth) { mMorphingInProgress = true; MorphingAnimation animation = new MorphingAnimation(this, background); animation.setFromCornerRadius(fromCorner); animation.setToCornerRadius(toCorner); animation.setPadding(mPaddingProgress); animation.setFromWidth(fromWidth); animation.setToWidth(toWidth); if (mConfigurationChanged) { animation.setDuration(MorphingAnimation.DURATION_INSTANT); } else { animation.setDuration(MorphingAnimation.DURATION_NORMAL); } mConfigurationChanged = false; return animation; } //切換到進度條形式 private void morphToProgress() { setWidth(getWidth()); setText(mProgressText); MorphingAnimation animation = createProgressMorphing(mCornerRadius, getHeight(), getWidth(), getHeight()); animation.setFromColor(getNormalColor(mIdleColorState)); animation.setToColor(mColorProgress); animation.setFromStrokeColor(getNormalColor(mIdleColorState)); animation.setToStrokeColor(mColorIndicatorBackground); animation.setListener(mProgressStateListener); animation.start(); } private OnAnimationEndListener mProgressStateListener = new OnAnimationEndListener() { @Override public void onAnimationEnd() { mMorphingInProgress = false; mState = State.PROGRESS; mStateManager.checkState(CircularProgressButton.this); } }; private void morphProgressToComplete() { MorphingAnimation animation = createProgressMorphing(getHeight(), mCornerRadius, getHeight(), getWidth()); animation.setFromColor(mColorProgress); animation.setToColor(getNormalColor(mCompleteColorState)); animation.setFromStrokeColor(mColorIndicator); animation.setToStrokeColor(getNormalColor(mCompleteColorState)); animation.setListener(mCompleteStateListener); animation.start(); } //idle狀態切換為complete狀態 private void morphIdleToComplete() { MorphingAnimation animation = createMorphing(); animation.setFromColor(getNormalColor(mIdleColorState)); animation.setToColor(getNormalColor(mCompleteColorState)); animation.setFromStrokeColor(getNormalColor(mIdleColorState)); animation.setToStrokeColor(getNormalColor(mCompleteColorState)); animation.setListener(mCompleteStateListener); animation.start(); } private OnAnimationEndListener mCompleteStateListener = new OnAnimationEndListener() { @Override public void onAnimationEnd() { if (mIconComplete != 0) { setText(null); setIcon(mIconComplete); } else { setText(mCompleteText); } mMorphingInProgress = false; mState = State.COMPLETE; mStateManager.checkState(CircularProgressButton.this); } }; private void morphCompleteToIdle() { MorphingAnimation animation = createMorphing(); animation.setFromColor(getNormalColor(mCompleteColorState)); animation.setToColor(getNormalColor(mIdleColorState)); animation.setFromStrokeColor(getNormalColor(mCompleteColorState)); animation.setToStrokeColor(getNormalColor(mIdleColorState)); animation.setListener(mIdleStateListener); animation.start(); } //error狀態切換到idle狀態 private void morphErrorToIdle() { MorphingAnimation animation = createMorphing(); animation.setFromColor(getNormalColor(mErrorColorState)); animation.setToColor(getNormalColor(mIdleColorState)); animation.setFromStrokeColor(getNormalColor(mErrorColorState)); animation.setToStrokeColor(getNormalColor(mIdleColorState)); animation.setListener(mIdleStateListener); animation.start(); } private OnAnimationEndListener mIdleStateListener = new OnAnimationEndListener() { @Override public void onAnimationEnd() { removeIcon(); setText(mIdleText); mMorphingInProgress = false; mState = State.IDLE; mStateManager.checkState(CircularProgressButton.this); } }; //idle狀態切換到error狀態 private void morphIdleToError() { MorphingAnimation animation = createMorphing(); animation.setFromColor(getNormalColor(mIdleColorState)); animation.setToColor(getNormalColor(mErrorColorState)); animation.setFromStrokeColor(getNormalColor(mIdleColorState)); animation.setToStrokeColor(getNormalColor(mErrorColorState)); animation.setListener(mErrorStateListener); animation.start(); } //進度條切換到error狀態 private void morphProgressToError() { MorphingAnimation animation = createProgressMorphing(getHeight(), mCornerRadius, getHeight(), getWidth()); animation.setFromColor(mColorProgress); animation.setToColor(getNormalColor(mErrorColorState)); animation.setFromStrokeColor(mColorIndicator); animation.setToStrokeColor(getNormalColor(mErrorColorState)); animation.setListener(mErrorStateListener); animation.start(); } private OnAnimationEndListener mErrorStateListener = new OnAnimationEndListener() { @Override public void onAnimationEnd() { if (mIconError != 0) { setText(null); setIcon(mIconError); } else { setText(mErrorText); } mMorphingInProgress = false; mState = State.ERROR; mStateManager.checkState(CircularProgressButton.this); } }; private void morphProgressToIdle() { MorphingAnimation animation = createProgressMorphing(getHeight(), mCornerRadius, getHeight(), getWidth()); animation.setFromColor(mColorProgress); animation.setToColor(getNormalColor(mIdleColorState)); animation.setFromStrokeColor(mColorIndicator); animation.setToStrokeColor(getNormalColor(mIdleColorState)); animation.setListener(new OnAnimationEndListener() { @Override public void onAnimationEnd() { removeIcon(); setText(mIdleText); mMorphingInProgress = false; mState = State.IDLE; mStateManager.checkState(CircularProgressButton.this); } }); animation.start(); } 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 || getWidth() == 0) { return; } mStateManager.saveProgress(this); if (mProgress >= mMaxProgress) { if (mState == State.PROGRESS) { morphProgressToComplete(); } else if (mState == State.IDLE) { morphIdleToComplete(); } } 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) { morphProgressToError(); } else if (mState == State.IDLE) { morphIdleToError(); } } else if (mProgress == IDLE_STATE_PROGRESS) { if (mState == State.COMPLETE) { morphCompleteToIdle(); } else if (mState == State.PROGRESS) { morphProgressToIdle(); } else if (mState == State.ERROR) { morphErrorToIdle(); } } } public int getProgress() { return mProgress; } public void setBackgroundColor(int color) { background.getGradientDrawable().setColor(color); } public void setStrokeColor(int color) { background.setStrokeColor(color); } public String getIdleText() { return mIdleText; } public String getCompleteText() { return mCompleteText; } public String getErrorText() { return mErrorText; } public void setIdleText(String text) { mIdleText = text; } public void setCompleteText(String text) { mCompleteText = text; } public void setErrorText(String text) { mErrorText = text; } @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; savedState.mIndeterminateProgressMode = mIndeterminateProgressMode; savedState.mConfigurationChanged = true; return savedState; } @Override public void onRestoreInstanceState(Parcelable state) { if (state instanceof SavedState) { SavedState savedState = (SavedState) state; mProgress = savedState.mProgress; mIndeterminateProgressMode = savedState.mIndeterminateProgressMode; mConfigurationChanged = savedState.mConfigurationChanged; super.onRestoreInstanceState(savedState.getSuperState()); setProgress(mProgress); } else { super.onRestoreInstanceState(state); } } static class SavedState extends BaseSavedState { private boolean mIndeterminateProgressMode; private boolean mConfigurationChanged; private int mProgress; public SavedState(Parcelable parcel) { super(parcel); } private SavedState(Parcel in) { super(in); mProgress = in.readInt(); mIndeterminateProgressMode = in.readInt() == 1; mConfigurationChanged = in.readInt() == 1; } @Override public void writeToParcel(Parcel out, int flags) { super.writeToParcel(out, flags); out.writeInt(mProgress); out.writeInt(mIndeterminateProgressMode ? 1 : 0); out.writeInt(mConfigurationChanged ? 1 : 0); } public static final CreatorCREATOR = new Creator () { @Override public SavedState createFromParcel(Parcel in) { return new SavedState(in); } @Override public SavedState[] newArray(int size) { return new SavedState[size]; } }; } }
這是作為上一篇Android 數據存儲 如何搞定SQLite Database的實例練習,之所以單獨列出來是因為除了數據庫方面的知識,還涉及其它方面的知識,
本文為大家分享一個非常簡單但又很常用的控件,跑馬燈狀態的TextView。當要顯示的文本長度太長,又不想換行時用它來顯示文本,一來可以完全的顯示出文本,二來效果也挺酷,實
一、簡述AXML即Android Binary XML,是Android應用程序APK包中保存xml文件數據的一種方式,可以減小xml文件的大小。resources.ar
微信群是我們經常聊天聊工作的地方,但是你需要離開的時候想要將這個微信群轉給一個人來管理該怎麼辦呢?那麼微信群怎麼轉讓群主呢?微信群怎麼轉讓給別人?微信群怎麼