android 自定义5.0版本 Progress效果-ProgressWheel(例如,淘宝加载)

来源:互联网 发布:淘宝一元云购网站搭建 编辑:程序博客网 时间:2024/05/06 12:43

在网上找到5.0Progress效果如下:

开源代码地址:https://github.com/pnikosis/materialish-progress

attr.xml
  <declare-styleable name="ProgressWheel">        <attr name="matProg_progressIndeterminate" format="boolean" />        <attr name="matProg_barColor" format="color" />        <attr name="matProg_rimColor" format="color" />        <attr name="matProg_rimWidth" format="dimension" />        <attr name="matProg_spinSpeed" format="float" />        <attr name="matProg_barSpinCycleTime" format="integer" />        <attr name="matProg_circleRadius" format="dimension" />        <attr name="matProg_fillRadius" format="boolean" />        <attr name="matProg_barWidth" format="dimension" />        <attr name="matProg_linearProgress" format="boolean" />    </declare-styleable>

代码:
import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Paint;import android.graphics.Paint.Style;import android.graphics.RectF;import android.os.Parcel;import android.os.Parcelable;import android.os.SystemClock;import android.support.annotation.NonNull;import android.util.AttributeSet;import android.util.DisplayMetrics;import android.util.TypedValue;import android.view.View;import com.base.R;/** * A Material style progress wheel, compatible up to 2.2. * Todd Davies' Progress Wheel https://github.com/Todd-Davies/ProgressWheel * * @author Nico Hormazábal *         <p/> *         Licensed under the Apache License 2.0 license see: *         http://www.apache.org/licenses/LICENSE-2.0 */public class ProgressWheel extends View {    /**     * *********     * DEFAULTS *     * **********     */    //Sizes (with defaults in DP)    private int circleRadius = 28;    private int barWidth = 4;    private int rimWidth = 4;    private final int barLength = 16;    private final int barMaxLength = 270;    private boolean fillRadius = false;    private double timeStartGrowing = 0;    private double barSpinCycleTime = 460;    private float barExtraLength = 0;    private boolean barGrowingFromFront = true;    private long pausedTimeWithoutGrowing = 0;    private final long pauseGrowingTime = 200;    //Colors (with defaults)    private int barColor = 0xAA000000;    private int rimColor = 0x00FFFFFF;    //Paints    private Paint barPaint = new Paint();    private Paint rimPaint = new Paint();    //Rectangles    private RectF circleBounds = new RectF();    //Animation    //The amount of degrees per second    private float spinSpeed = 230.0f;    //private float spinSpeed = 120.0f;    // The last time the spinner was animated    private long lastTimeAnimated = 0;    private boolean linearProgress;    private float mProgress = 0.0f;    private float mTargetProgress = 0.0f;    private boolean isSpinning = false;    private ProgressCallback callback;    /**     * The constructor for the ProgressWheel     *     * @param context     * @param attrs     */    public ProgressWheel(Context context, AttributeSet attrs) {        super(context, attrs);        parseAttributes(context.obtainStyledAttributes(attrs, R.styleable.ProgressWheel));    }    /**     * The constructor for the ProgressWheel     *     * @param context     */    public ProgressWheel(Context context) {        super(context);    }    //----------------------------------    //Setting up stuff    //----------------------------------    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        int viewWidth = circleRadius + this.getPaddingLeft() + this.getPaddingRight();        int viewHeight = circleRadius + this.getPaddingTop() + this.getPaddingBottom();        int widthMode = MeasureSpec.getMode(widthMeasureSpec);        int widthSize = MeasureSpec.getSize(widthMeasureSpec);        int heightMode = MeasureSpec.getMode(heightMeasureSpec);        int heightSize = MeasureSpec.getSize(heightMeasureSpec);        int width;        int height;        //Measure Width        if (widthMode == MeasureSpec.EXACTLY) {            //Must be this size            width = widthSize;        } else if (widthMode == MeasureSpec.AT_MOST) {            //Can't be bigger than...            width = Math.min(viewWidth, widthSize);        } else {            //Be whatever you want            width = viewWidth;        }        //Measure Height        if (heightMode == MeasureSpec.EXACTLY || widthMode == MeasureSpec.EXACTLY) {            //Must be this size            height = heightSize;        } else if (heightMode == MeasureSpec.AT_MOST) {            //Can't be bigger than...            height = Math.min(viewHeight, heightSize);        } else {            //Be whatever you want            height = viewHeight;        }        setMeasuredDimension(width, height);    }    /**     * Use onSizeChanged instead of onAttachedToWindow to get the dimensions of the view,     * because this method is called after measuring the dimensions of MATCH_PARENT & WRAP_CONTENT.     * Use this dimensions to setup the bounds and paints.     */    @Override    protected void onSizeChanged(int w, int h, int oldw, int oldh) {        super.onSizeChanged(w, h, oldw, oldh);        setupBounds(w, h);        setupPaints();        invalidate();    }    /**     * Set the properties of the paints we're using to     * draw the progress wheel     */    private void setupPaints() {        barPaint.setColor(barColor);        barPaint.setAntiAlias(true);        barPaint.setStyle(Style.STROKE);        barPaint.setStrokeWidth(barWidth);        rimPaint.setColor(rimColor);        rimPaint.setAntiAlias(true);        rimPaint.setStyle(Style.STROKE);        rimPaint.setStrokeWidth(rimWidth);    }    /**     * Set the bounds of the component     */    private void setupBounds(int layout_width, int layout_height) {        int paddingTop = getPaddingTop();        int paddingBottom = getPaddingBottom();        int paddingLeft = getPaddingLeft();        int paddingRight = getPaddingRight();        if (!fillRadius) {            // Width should equal to Height, find the min value to setup the circle            int minValue = Math.min(layout_width - paddingLeft - paddingRight,                    layout_height - paddingBottom - paddingTop);            int circleDiameter = Math.min(minValue, circleRadius * 2 - barWidth * 2);            // Calc the Offset if needed for centering the wheel in the available space            int xOffset = (layout_width - paddingLeft - paddingRight - circleDiameter) / 2 + paddingLeft;            int yOffset = (layout_height - paddingTop - paddingBottom - circleDiameter) / 2 + paddingTop;            circleBounds = new RectF(xOffset + barWidth,                    yOffset + barWidth,                    xOffset + circleDiameter - barWidth,                    yOffset + circleDiameter - barWidth);        } else {            circleBounds = new RectF(paddingLeft + barWidth,                    paddingTop + barWidth,                    layout_width - paddingRight - barWidth,                    layout_height - paddingBottom - barWidth);        }    }    /**     * Parse the attributes passed to the view from the XML     *     * @param a the attributes to parse     */    private void parseAttributes(TypedArray a) {        // We transform the default values from DIP to pixels        DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();        barWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, barWidth, metrics);        rimWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, rimWidth, metrics);        circleRadius = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, circleRadius, metrics);        circleRadius = (int) a.getDimension(R.styleable.ProgressWheel_matProg_circleRadius, circleRadius);        fillRadius = a.getBoolean(R.styleable.ProgressWheel_matProg_fillRadius, false);        barWidth = (int) a.getDimension(R.styleable.ProgressWheel_matProg_barWidth, barWidth);        rimWidth = (int) a.getDimension(R.styleable.ProgressWheel_matProg_rimWidth, rimWidth);        float baseSpinSpeed = a.getFloat(R.styleable.ProgressWheel_matProg_spinSpeed, spinSpeed / 360.0f);        spinSpeed = baseSpinSpeed * 360;        barSpinCycleTime = a.getInt(R.styleable.ProgressWheel_matProg_barSpinCycleTime, (int) barSpinCycleTime);        barColor = a.getColor(R.styleable.ProgressWheel_matProg_barColor, barColor);        rimColor = a.getColor(R.styleable.ProgressWheel_matProg_rimColor, rimColor);        linearProgress = a.getBoolean(R.styleable.ProgressWheel_matProg_linearProgress, false);        if (a.getBoolean(R.styleable.ProgressWheel_matProg_progressIndeterminate, false)) {            spin();        }        // Recycle        a.recycle();    }    public void setCallback(ProgressCallback progressCallback) {        callback = progressCallback;        if (!isSpinning) {            runCallback();        }    }    //----------------------------------    //Animation stuff    //----------------------------------    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        canvas.drawArc(circleBounds, 360, 360, false, rimPaint);        boolean mustInvalidate = false;        if (isSpinning) {            //Draw the spinning bar            mustInvalidate = true;            long deltaTime = (SystemClock.uptimeMillis() - lastTimeAnimated);            float deltaNormalized = deltaTime * spinSpeed / 1000.0f;            updateBarLength(deltaTime);            mProgress += deltaNormalized;            if (mProgress > 360) {                mProgress -= 360f;                // A full turn has been completed                // we run the callback with -1 in case we want to                // do something, like changing the color                runCallback(-1.0f);            }            lastTimeAnimated = SystemClock.uptimeMillis();            float from = mProgress - 90;            float length = barLength + barExtraLength;            if (isInEditMode()) {                from = 0;                length = 135;            }            canvas.drawArc(circleBounds, from, length, false,                    barPaint);        } else {            float oldProgress = mProgress;            if (mProgress != mTargetProgress) {                //We smoothly increase the progress bar                mustInvalidate = true;                float deltaTime = (float) (SystemClock.uptimeMillis() - lastTimeAnimated) / 1000;                float deltaNormalized = deltaTime * spinSpeed;                mProgress = Math.min(mProgress + deltaNormalized, mTargetProgress);                lastTimeAnimated = SystemClock.uptimeMillis();            }            if (oldProgress != mProgress) {                runCallback();            }            float offset = 0.0f;            float progress = mProgress;            if (!linearProgress) {                float factor = 2.0f;                offset = (float) (1.0f - Math.pow(1.0f - mProgress / 360.0f, 2.0f * factor)) * 360.0f;                progress = (float) (1.0f - Math.pow(1.0f - mProgress / 360.0f, factor)) * 360.0f;            }            if (isInEditMode()) {                progress = 360;            }            canvas.drawArc(circleBounds, offset - 90, progress, false, barPaint);        }        if (mustInvalidate) {            invalidate();        }    }@Override    protected void onVisibilityChanged(@NonNull View changedView, int visibility) {        super.onVisibilityChanged(changedView, visibility);        if (visibility == VISIBLE) {            lastTimeAnimated = SystemClock.uptimeMillis();        }    }    private void updateBarLength(long deltaTimeInMilliSeconds) {        if (pausedTimeWithoutGrowing >= pauseGrowingTime) {            timeStartGrowing += deltaTimeInMilliSeconds;            if (timeStartGrowing > barSpinCycleTime) {                // We completed a size change cycle                // (growing or shrinking)                timeStartGrowing -= barSpinCycleTime;                //if(barGrowingFromFront) {                pausedTimeWithoutGrowing = 0;                //}                barGrowingFromFront = !barGrowingFromFront;            }            float distance = (float) Math.cos((timeStartGrowing / barSpinCycleTime + 1) * Math.PI) / 2 + 0.5f;            float destLength = (barMaxLength - barLength);            if (barGrowingFromFront) {                barExtraLength = distance * destLength;            } else {                float newLength = destLength * (1 - distance);                mProgress += (barExtraLength - newLength);                barExtraLength = newLength;            }        } else {            pausedTimeWithoutGrowing += deltaTimeInMilliSeconds;        }    }    /**     * Check if the wheel is currently spinning     */    public boolean isSpinning() {        return isSpinning;    }    /**     * Reset the count (in increment mode)     */    public void resetCount() {        mProgress = 0.0f;        mTargetProgress = 0.0f;        invalidate();    }    /**     * Turn off spin mode     */    public void stopSpinning() {        isSpinning = false;        mProgress = 0.0f;        mTargetProgress = 0.0f;        invalidate();    }    /**     * Puts the view on spin mode     */    public void spin() {        lastTimeAnimated = SystemClock.uptimeMillis();        isSpinning = true;        invalidate();    }    private void runCallback(float value) {        if (callback != null) {            callback.onProgressUpdate(value);        }    }    private void runCallback() {        if (callback != null) {            float normalizedProgress = (float) Math.round(mProgress * 100 / 360.0f) / 100;            callback.onProgressUpdate(normalizedProgress);        }    }    /**     * Set the progress to a specific value,     * the bar will smoothly animate until that value     *     * @param progress the progress between 0 and 1     */    public void setProgress(float progress) {        if (isSpinning) {            mProgress = 0.0f;            isSpinning = false;            runCallback();        }        if (progress > 1.0f) {            progress -= 1.0f;        } else if (progress < 0) {            progress = 0;        }        if (progress == mTargetProgress) {            return;        }        // If we are currently in the right position        // we set again the last time animated so the        // animation starts smooth from here        if (mProgress == mTargetProgress) {            lastTimeAnimated = SystemClock.uptimeMillis();        }        mTargetProgress = Math.min(progress * 360.0f, 360.0f);        invalidate();    }    /**     * Set the progress to a specific value,     * the bar will be set instantly to that value     *     * @param progress the progress between 0 and 1     */    public void setInstantProgress(float progress) {        if (isSpinning) {            mProgress = 0.0f;            isSpinning = false;        }        if (progress > 1.0f) {            progress -= 1.0f;        } else if (progress < 0) {            progress = 0;        }        if (progress == mTargetProgress) {            return;        }        mTargetProgress = Math.min(progress * 360.0f, 360.0f);        mProgress = mTargetProgress;        lastTimeAnimated = SystemClock.uptimeMillis();        invalidate();    }    // Great way to save a view's state http://stackoverflow.com/a/7089687/1991053    @Override    public Parcelable onSaveInstanceState() {        Parcelable superState = super.onSaveInstanceState();        WheelSavedState ss = new WheelSavedState(superState);        // We save everything that can be changed at runtime        ss.mProgress = this.mProgress;        ss.mTargetProgress = this.mTargetProgress;        ss.isSpinning = this.isSpinning;        ss.spinSpeed = this.spinSpeed;        ss.barWidth = this.barWidth;        ss.barColor = this.barColor;        ss.rimWidth = this.rimWidth;        ss.rimColor = this.rimColor;        ss.circleRadius = this.circleRadius;        ss.linearProgress = this.linearProgress;        ss.fillRadius = this.fillRadius;        return ss;    }    @Override    public void onRestoreInstanceState(Parcelable state) {        if (!(state instanceof WheelSavedState)) {            super.onRestoreInstanceState(state);            return;        }        WheelSavedState ss = (WheelSavedState) state;        super.onRestoreInstanceState(ss.getSuperState());        this.mProgress = ss.mProgress;        this.mTargetProgress = ss.mTargetProgress;        this.isSpinning = ss.isSpinning;        this.spinSpeed = ss.spinSpeed;        this.barWidth = ss.barWidth;        this.barColor = ss.barColor;        this.rimWidth = ss.rimWidth;        this.rimColor = ss.rimColor;        this.circleRadius = ss.circleRadius;        this.linearProgress = ss.linearProgress;        this.fillRadius = ss.fillRadius;        this.lastTimeAnimated = SystemClock.uptimeMillis();    }    //----------------------------------    //Getters + setters    //----------------------------------    /**     * @return the current progress between 0.0 and 1.0,     * if the wheel is indeterminate, then the result is -1     */    public float getProgress() {        return isSpinning ? -1 : mProgress / 360.0f;    }    /**     * Sets the determinate progress mode     *     * @param isLinear if the progress should increase linearly     */    public void setLinearProgress(boolean isLinear) {        linearProgress = isLinear;        if (!isSpinning) {            invalidate();        }    }    /**     * @return the radius of the wheel in pixels     */    public int getCircleRadius() {        return circleRadius;    }    /**     * Sets the radius of the wheel     *     * @param circleRadius the expected radius, in pixels     */    public void setCircleRadius(int circleRadius) {        this.circleRadius = circleRadius;        if (!isSpinning) {            invalidate();        }    }    /**     * @return the width of the spinning bar     */    public int getBarWidth() {        return barWidth;    }    /**     * Sets the width of the spinning bar     *     * @param barWidth the spinning bar width in pixels     */    public void setBarWidth(int barWidth) {        this.barWidth = barWidth;        if (!isSpinning) {            invalidate();        }    }    /**     * @return the color of the spinning bar     */    public int getBarColor() {        return barColor;    }    /**     * Sets the color of the spinning bar     *     * @param barColor The spinning bar color     */    public void setBarColor(int barColor) {        this.barColor = barColor;        setupPaints();        if (!isSpinning) {            invalidate();        }    }    /**     * @return the color of the wheel's contour     */    public int getRimColor() {        return rimColor;    }    /**     * Sets the color of the wheel's contour     *     * @param rimColor the color for the wheel     */    public void setRimColor(int rimColor) {        this.rimColor = rimColor;        setupPaints();        if (!isSpinning) {            invalidate();        }    }    /**     * @return the base spinning speed, in full circle turns per second     * (1.0 equals on full turn in one second), this value also is applied for     * the smoothness when setting a progress     */    public float getSpinSpeed() {        return spinSpeed / 360.0f;    }    /**     * Sets the base spinning speed, in full circle turns per second     * (1.0 equals on full turn in one second), this value also is applied for     * the smoothness when setting a progress     *     * @param spinSpeed the desired base speed in full turns per second     */    public void setSpinSpeed(float spinSpeed) {        this.spinSpeed = spinSpeed * 360.0f;    }    /**     * @return the width of the wheel's contour in pixels     */    public int getRimWidth() {        return rimWidth;    }    /**     * Sets the width of the wheel's contour     *     * @param rimWidth the width in pixels     */    public void setRimWidth(int rimWidth) {        this.rimWidth = rimWidth;        if (!isSpinning) {            invalidate();        }    }    static class WheelSavedState extends BaseSavedState {        float mProgress;        float mTargetProgress;        boolean isSpinning;        float spinSpeed;        int barWidth;        int barColor;        int rimWidth;        int rimColor;        int circleRadius;        boolean linearProgress;        boolean fillRadius;        WheelSavedState(Parcelable superState) {            super(superState);        }        private WheelSavedState(Parcel in) {            super(in);            this.mProgress = in.readFloat();            this.mTargetProgress = in.readFloat();            this.isSpinning = in.readByte() != 0;            this.spinSpeed = in.readFloat();            this.barWidth = in.readInt();            this.barColor = in.readInt();            this.rimWidth = in.readInt();            this.rimColor = in.readInt();            this.circleRadius = in.readInt();            this.linearProgress = in.readByte() != 0;            this.fillRadius = in.readByte() != 0;        }        @Override        public void writeToParcel(Parcel out, int flags) {            super.writeToParcel(out, flags);            out.writeFloat(this.mProgress);            out.writeFloat(this.mTargetProgress);            out.writeByte((byte) (isSpinning ? 1 : 0));            out.writeFloat(this.spinSpeed);            out.writeInt(this.barWidth);            out.writeInt(this.barColor);            out.writeInt(this.rimWidth);            out.writeInt(this.rimColor);            out.writeInt(this.circleRadius);            out.writeByte((byte) (linearProgress ? 1 : 0));            out.writeByte((byte) (fillRadius ? 1 : 0));        }        //required field that makes Parcelables from a Parcel        public static final Parcelable.Creator<WheelSavedState> CREATOR =                new Parcelable.Creator<WheelSavedState>() {                    public WheelSavedState createFromParcel(Parcel in) {                        return new WheelSavedState(in);                    }                    public WheelSavedState[] newArray(int size) {                        return new WheelSavedState[size];                    }                };    }    public interface ProgressCallback {        /**         * Method to call when the progress reaches a value         * in order to avoid float precision issues, the progress         * is rounded to a float with two decimals.         *         * In indeterminate mode, the callback is called each time         * the wheel completes an animation cycle, with, the progress value is -1.0f         *         * @param progress a double value between 0.00 and 1.00 both included         */        public void onProgressUpdate(float progress);    }}


0 0
原创粉丝点击