package com.mgw.member.ui.widget; import android.content.Context; import android.content.res.ColorStateList; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Paint.Align; import android.graphics.Paint.FontMetrics; import android.graphics.Rect; import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.graphics.drawable.DrawableContainer; import android.graphics.drawable.NinePatchDrawable; import android.os.Process; import android.view.View; import android.widget.RemoteViews.RemoteView; import com.mgw.member.uitls.StringUtils; import com.mgw.member.uitls.UIUtils; @RemoteView public class ProgressHorizontal extends View { private static final int MAX_SMOOTH_ANIM_DURATION = 2000; private long mThreadId; private int mResBackground; private Drawable mDrbBackground; private int mResProgress; private Drawable mDrbProgress; private int mProgressDrbMinWidth; private int mProgressTextSize; private ColorStateList mProgressTextColorStateList; private int mProgressTextColor; private Typeface mTypeface = Typeface.DEFAULT; private Paint mTextPaint; private boolean mProgressTextVisible = true; private int mMaxProgress = 100; private float mProgress; private float mSmoothProgress = 0; private float mStartProgress = 0; private long mProgressSetTime; private int mSmoothAnimDuration; private Rect mRawProgressBounds = new Rect(); private StringBuilder mSb = new StringBuilder(4); private String mText; private OnProgressChangeListener mOnProgressChangeListener; public ProgressHorizontal(Context context) { super(context); this.setFocusable(false); this.setClickable(false); this.setFocusableInTouchMode(false); mThreadId = Process.myTid(); mTextPaint = new Paint(); } public synchronized float getProgress() { return mProgress; } public void setProgressBackgroundResource(int resId) { if (mResBackground == resId) { return; } mResBackground = resId; try { mDrbBackground = UIUtils.getDrawable(resId); if (null != mDrbBackground) { mDrbBackground.setBounds(0, 0, getWidth(), getHeight()); } } catch (Exception e) { mDrbBackground = null; mResBackground = -1; } invalidate(); } public void setProgressDrawble(Drawable drawable) { if (mDrbProgress == drawable) { return; } mDrbProgress = drawable; invalidate(); } public void setProgressResource(int resId) { if (mResProgress == resId) { return; } mDrbProgress = UIUtils.getDrawable(resId); invalidate(); } public void setMinProgressWidth(int minWidth) { mProgressDrbMinWidth = minWidth; invalidateSafe(); } public void setMax(int max) { if (max > 0) { mMaxProgress = max; } } public void setProgress(int progress) { setProgress(progress, false); } public void setProgress(int progress, boolean smooth) { setProgress(progress / (float) mMaxProgress, smooth); } public void setProgress(float progress) { setProgress(progress, false); } public synchronized void setProgress(float progress, boolean smooth) { if (progress < 0) { progress = 0; } if (progress > 1) { progress = 1; } mProgress = progress; mProgressSetTime = System.currentTimeMillis(); if (smooth) { mSmoothAnimDuration = (int) (MAX_SMOOTH_ANIM_DURATION * (1 - mProgress)); } else { mSmoothAnimDuration = 0; mSmoothProgress = mProgress; } mStartProgress = mSmoothProgress; invalidateSafe(); } public void setProgressTextSize(int px) { mProgressTextSize = px; } public void setProgressTextColor(ColorStateList color) { mProgressTextColorStateList = color; mProgressTextColor = mProgressTextColorStateList.getColorForState(getDrawableState(), mProgressTextColor); } public void setProgressTextColor(int color) { mProgressTextColorStateList = null; mProgressTextColor = color; } public void setProgressTextVisible(boolean visible) { mProgressTextVisible = visible; } public void setCenterText(String text) { mText = text; invalidate(); } public void setOnProgressChangeListener(OnProgressChangeListener l) { mOnProgressChangeListener = l; } private void invalidateSafe() { if (mThreadId == Process.myTid()) { invalidate(); } else { postInvalidate(); } } private void notifyProgressChange(float smoothProgress, float targetProgress) { if (null != mOnProgressChangeListener) { mOnProgressChangeListener.onProgressChange(smoothProgress, targetProgress); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = 0; int height = 0; int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); if (widthMode == MeasureSpec.EXACTLY) { width = widthSize; } else { width = mDrbBackground == null ? 0 : mDrbBackground.getIntrinsicWidth(); if (widthMode == MeasureSpec.AT_MOST) { width = Math.min(width, widthSize); } } if (heightMode == MeasureSpec.EXACTLY) { height = heightSize; } else { height = mDrbBackground == null ? 0 : mDrbBackground.getIntrinsicHeight(); if (heightMode == MeasureSpec.AT_MOST) { height = Math.min(height, heightSize); } } if (null != mDrbBackground) { mDrbBackground.setBounds(0, 0, width, height); } mRawProgressBounds.set(getPaddingLeft(), getPaddingTop(), width - getPaddingRight(), height - getPaddingBottom()); setMeasuredDimension(width, height); } @Override protected void onDraw(Canvas canvas) { float factor; if (mProgress == 0 || mProgress == 1) { factor = 1; } else { long elapsed = System.currentTimeMillis() - mProgressSetTime; if (elapsed < 0) { factor = 0; } else if (elapsed > mSmoothAnimDuration) { factor = 1; } else { factor = elapsed / (float) mSmoothAnimDuration; } } mSmoothProgress = mStartProgress + factor * (mProgress - mStartProgress); // Draw background if (null != mDrbBackground) { mDrbBackground.draw(canvas); } // Draw progress if (null != mDrbProgress) { if (mDrbProgress instanceof NinePatchDrawable || (mDrbProgress instanceof DrawableContainer && ((DrawableContainer) mDrbProgress).getCurrent() instanceof NinePatchDrawable)) { if (mSmoothProgress == 0) { mDrbProgress.setBounds(0, 0, 0, 0); } else { mDrbProgress.setBounds(0, mRawProgressBounds.top, (int) (mRawProgressBounds.left + (mRawProgressBounds.width() - mProgressDrbMinWidth) * mSmoothProgress) + mProgressDrbMinWidth, mRawProgressBounds.bottom); } } mDrbProgress.draw(canvas); } // Draw progress text if (mProgressTextVisible) { mSb.delete(0, mSb.length()); if (StringUtils.isEmpty(mText)) { mSb.append((int) (mSmoothProgress * 100)); mSb.append('%'); } else { mSb.append(mText); } String text = mSb.toString(); mTextPaint.setAntiAlias(true); mTextPaint.setColor(mProgressTextColor); mTextPaint.setTextSize(mProgressTextSize); mTextPaint.setTypeface(mTypeface); mTextPaint.setTextAlign(Align.CENTER); FontMetrics fm = mTextPaint.getFontMetrics(); int fontH = (int) (Math.abs(fm.descent - fm.ascent)); canvas.drawText(text, getWidth() >> 1, ((getHeight() - getPaddingTop() - getPaddingBottom()) >> 1) + (fontH >> 1), mTextPaint); } if (factor != 1) { invalidate(); } notifyProgressChange(mSmoothProgress, mProgress); } @Override protected void drawableStateChanged() { int[] drawableState = getDrawableState(); if (mDrbBackground != null && mDrbBackground.isStateful()) { mDrbBackground.setState(drawableState); } if (mDrbProgress != null && mDrbProgress.isStateful()) { mDrbProgress.setState(drawableState); } if (mProgressTextColorStateList != null) { mProgressTextColor = mProgressTextColorStateList.getColorForState(drawableState, mProgressTextColor); } invalidate(); } public static interface OnProgressChangeListener { public void onProgressChange(float smoothProgress, float targetProgress); } }