收藏2个常用的进度条

免积分下载代码

这里写图片描述这里写图片描述

activity_main.xml主页布局就2个button,分别弹出不同效果的2个进度条

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.dialog.MainActivity" >
    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />
      <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />
</LinearLayout>

MainActivity

package com.example.dialog;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.View;
public class MainActivity extends FragmentActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.button1).setOnClickListener(
                new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        MyloadDialog myloadDialog = new MyloadDialog(
                                MainActivity.this, 1);
                        myloadDialog.show();
                    }
                });

        findViewById(R.id.button2).setOnClickListener(
                new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        MyloadDialog myloadDialog = new MyloadDialog(
                                MainActivity.this, 2);
                        myloadDialog.show();
                    }
                });
    }
}

MyloadDialog

package com.example.dialog;

import android.app.Dialog;
import android.content.Context;
import android.graphics.Color;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

public class MyloadDialog extends Dialog{

    public MyloadDialog(Context context,int args) {
         super(context, R.style.PerfectDialog);  
          init(args);
    }
     private int barColor = Color.parseColor("#ff009688");

     private void init(int args) {  
         if (args == 1) {
            View contentView = View.inflate(getContext(),
                    R.layout.dialog_load_classic_layout, null);
            setContentView(contentView);
            LoadClassicView loadClassicView = (LoadClassicView) contentView
                    .findViewById(R.id.dialogLoadView);
            loadClassicView.startLoad();
        }else if (args == 2) {

            View contentView = View.inflate(getContext(),
                    R.layout.dialog_load_material_layout, null);
            setContentView(contentView);



             LoadMaterialView progressWheel = (LoadMaterialView) contentView.findViewById(R.id.dialogLoadView);
                progressWheel.setBarColor(barColor);
                progressWheel.spin();
        }

        }  
}
 </style>


       <style name="PerfectDialog" parent="@android:style/Theme.Dialog">
        <item name="android:windowIsFloating">true</item>//是否浮现在activity之上
        <item name="android:windowIsTranslucent">false</item>//是否半透明
        <item name="android:windowNoTitle">true</item>//是否显示title标题
        <item name="android:windowFrame">@null</item>//设置windowFrame框
        <item name="android:windowFullscreen">false</item>//是否全屏显示
        <item name="android:windowBackground">@android:color/transparent</item>//设置dialog的背景
        <item name="android:windowAnimationStyle">@style/DialogAnims</item>//设置窗口动画效果
        <item name="android:backgroundDimEnabled">true</item>//背景是否变暗
        <item name="android:backgroundDimAmount">0.5</item>//设置背景变暗程度
        <item name="android:windowCloseOnTouchOutside">false</item>
        <item name="android:background">@android:color/transparent</item>
    </style>

        <style name="DialogAnims">
        <item name="android:windowEnterAnimation">@anim/enter</item>//进入动画
        <item name="android:windowExitAnimation">@anim/exit</item>//退出动画
    </style>

enter.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <alpha
        android:duration="90"
        android:fromAlpha="0"
        android:toAlpha="1"/>
    <scale
        android:duration="135"
        android:fromXScale="0.8"
        android:toXScale="1.05"
        android:fromYScale="0.8"
        android:toYScale="1.05"
        android:pivotX="50%"
        android:pivotY="50%"/>
    <scale
        android:duration="105"
        android:fromXScale="1.05"
        android:toXScale="0.95"
        android:fromYScale="1.05"
        android:toYScale="0.95"
        android:startOffset="135"
        android:pivotX="50%"
        android:pivotY="50%"/>
    <scale
        android:duration="135"
        android:fromXScale="0.95"
        android:toXScale="1"
        android:fromYScale="0.95"
        android:toYScale="1"
        android:startOffset="240"
        android:pivotX="50%"
        android:pivotY="50%"/>
</set>

exit.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <alpha
        android:duration="200"
        android:fromAlpha="1"
        android:toAlpha="0"/>
    <scale
        android:duration="200"
        android:fromXScale="1"
        android:toXScale="0.1"
        android:fromYScale="1"
        android:toYScale="0.1"
        android:pivotX="50%"
        android:pivotY="50%"/>
</set>

首先看带第一个效果图的布局文件
dialog_load_classic_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/background_round_corner"
    android:padding="35dp">

    <com.example.dialog.LoadClassicView
        android:id="@+id/dialogLoadView"
        android:layout_width="45dp"
        android:layout_height="45dp" />

</LinearLayout>

背景圆角background_round_corner.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <corners android:radius="8dp"/>
    <solid android:color="#ffffff"/>
</shape>

LoadClassicView

package com.example.dialog;

import android.animation.ArgbEvaluator;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.View;

/**
 * Created by dandy on 2016/5/31.
 */
public class LoadClassicView extends View {

    private static final String TAG = "LoadingView";

    private static final long DELAY_DURATION = 65;

    private static final float SIZE = 22f;//默认大小

    private static final float RAIDUS = 18f;//内部圆半径

    private static final int START_COLOR = Color.parseColor("#5a5a5a");//起始颜色

    private static final int END_COLOR = Color.parseColor("#dddddd");//结束颜色

    private static final int COUNT = 12;//默认加载条个数

    private static final float STROKE_WIDTH = 6.0f;//加载条粗值

    private float size = SIZE;

    private float radius = RAIDUS;

    private int startColor = START_COLOR;

    private int endColor = END_COLOR;

    private int count = COUNT;

    private float strokeWidth = STROKE_WIDTH;

    private DisplayMetrics dm;

    private ArgbEvaluator colorEvaluator;

    private int [] colors;//加载条颜色

    private LoadingLine [] loadingLines;//加载条集合

    private Paint paint;

    private double startAngle = 0;

    private  int exactlySize;

    private int startIndex = 0;

    /**
     * 构造方法
     * @param context
     */
    public LoadClassicView(Context context){
        this(context, null);
    }

    public LoadClassicView(Context context, AttributeSet attributeSet){
        super(context, attributeSet);
        setUpInit(attributeSet);
    }

    private void setUpInit(AttributeSet set){
        dm = Resources.getSystem().getDisplayMetrics();
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setStrokeWidth(strokeWidth);
        paint.setStrokeCap(Paint.Cap.ROUND);
        initColor();
        initLoadingLines();
    }

    /*
     * 初始化每个的颜色
     */
    private void initColor(){
        colorEvaluator = new ArgbEvaluator();
        colors = new int[count];
        for(int i = 0;i < count;i++){
            colors[i] = (Integer)colorEvaluator.evaluate(i*1.0f/(count-1),startColor,endColor);

        }
    }

    /**
     * 为每个赋值颜色值
     */
    private void initLoadingLines(){
        loadingLines = new LoadingLine[count];
        for(int i = 0;i <count;i++){
            LoadingLine loadingLine = new LoadingLine();
            loadingLine.drawColor = colors[i];
            loadingLines[i] = loadingLine;
        }
    }

    /**
     * 设置显示颜色
     * @param index,线段颜色初始化位置
     */
    private void setColor(int index){
        int lineIndex;
        for(int i = 0;i < count;i++){
            lineIndex = index + i;
            loadingLines[lineIndex >= count?lineIndex - count:lineIndex].drawColor = colors[i];
        }
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        /**计算宽**/
        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int width = MeasureSpec.getSize(widthMeasureSpec);
        if(widthMode == MeasureSpec.UNSPECIFIED || widthMode == MeasureSpec.AT_MOST){
            width = applyDimension(size);
        }

        /**计算高**/
        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        if (heightMode == MeasureSpec.UNSPECIFIED || heightMode == MeasureSpec.AT_MOST) {
            height = applyDimension(size);
        }

        /**
         * 取小的值作为控件的大小
         */
        exactlySize = width >= height ? height:width;

        this.radius = 0.22f * exactlySize;

        setMeasuredDimension(exactlySize,exactlySize);

    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        float delayAngle = 360.0f / count;
        LoadingLine loadingLine;
        double value;
        for(int i = 0;i < count;i++){
            loadingLine = loadingLines[i];
            value = startAngle * Math.PI / 180;
            loadingLine.startX = (int) Math.round(radius * Math.cos(value));
            loadingLine.startY = (int) Math.round(radius * Math.sin(value));
            loadingLine.endX = (int) Math.round(exactlySize / 2.5f * Math.cos(value));
            loadingLine.endY = (int) Math.round(exactlySize / 2.5f * Math.sin(value));
            startAngle += delayAngle;
        }
        startAngle = 0;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.save();
        canvas.translate(exactlySize/2.0f,exactlySize/2.0f);
        for(int i = 0; i < count;i++){
            LoadingLine loadingLine = loadingLines[i];
            paint.setColor(loadingLine.drawColor);
            canvas.drawLine(loadingLine.startX, loadingLine.startY, loadingLine.endX, loadingLine.endY, paint);
        }
        canvas.restore();
    }

    public void startLoad(){
        postDelayed(runnable,100);
    }

    public void finishLoad(){
        removeCallbacks(runnable);
    }

    private Runnable runnable = new Runnable() {
        @Override
        public void run() {
            postInvalidate();
            removeCallbacks(runnable);
            setColor(startIndex % count);
            startIndex++;
            postDelayed(runnable,DELAY_DURATION);
        }
    };

    /**
     * px2dp
     * @param value
     */
    private int applyDimension(float value){
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, dm);
    }

    private static class LoadingLine{
        private int drawColor;
        private int startX;
        private int startY;
        private int endX;
        private int endY;
    }
}




接下来看第二个图片
dialog_load_material_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/background_round_corner"
    android:padding="35dp">
    <com.example.dialog.LoadMaterialView
        android:id="@id/dialogLoadView"
        android:layout_width="45dp"
        android:layout_height="45dp" />
</LinearLayout>

LoadMaterialView

package com.example.dialog;

/**
 * Created by Seeker on 2016/8/4.
 *
 * @copy https://github.com/pnikosis/materialish-progress
 */

import android.annotation.TargetApi;
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.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
import android.provider.Settings;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.View;



public class LoadMaterialView extends View {

    private static final String TAG = "ProgressWheel";

    private final int barLength = 16;
    private final int barMaxLength = 270;
    private final long pauseGrowingTime = 200;
    /**
     * *********
     * DEFAULTS *
     * **********
     */
    //Sizes (with defaults in DP)
    private int circleRadius = 28;
    private int barWidth = 4;
    private int rimWidth = 4;
    private boolean fillRadius = false;
    private double timeStartGrowing = 0;
    private double barSpinCycleTime = 460;
    private float barExtraLength = 0;
    private boolean barGrowingFromFront = true;
    private long pausedTimeWithoutGrowing = 0;
    //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;

    private boolean shouldAnimate;

    /**
     * The constructor for the ProgressWheel
     */
    public LoadMaterialView(Context context, AttributeSet attrs) {
        super(context, attrs);

        parseAttributes(context.obtainStyledAttributes(attrs, R.styleable.LoadMaterialView));

        setAnimationEnabled();
    }

    /**
     * The constructor for the ProgressWheel
     */
    public LoadMaterialView(Context context) {
        super(context);
        setAnimationEnabled();
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
    private void setAnimationEnabled() {
        int currentApiVersion = Build.VERSION.SDK_INT;

        float animationValue;
        if (currentApiVersion >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            animationValue = Settings.Global.getFloat(getContext().getContentResolver(),
                    Settings.Global.ANIMATOR_DURATION_SCALE, 1);
        } else {
            animationValue = Settings.System.getFloat(getContext().getContentResolver(),
                    Settings.System.ANIMATOR_DURATION_SCALE, 1);
        }

        shouldAnimate = animationValue != 0;
    }

    //----------------------------------
    //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.LoadMaterialView_matProg_circleRadius, circleRadius);

        fillRadius = a.getBoolean(R.styleable.LoadMaterialView_matProg_fillRadius, false);

        barWidth = (int) a.getDimension(R.styleable.LoadMaterialView_matProg_barWidth, barWidth);

        rimWidth = (int) a.getDimension(R.styleable.LoadMaterialView_matProg_rimWidth, rimWidth);

        float baseSpinSpeed =
                a.getFloat(R.styleable.LoadMaterialView_matProg_spinSpeed, spinSpeed / 360.0f);
        spinSpeed = baseSpinSpeed * 360;

        barSpinCycleTime =
                a.getInt(R.styleable.LoadMaterialView_matProg_barSpinCycleTime, (int) barSpinCycleTime);

        barColor = a.getColor(R.styleable.LoadMaterialView_matProg_barColor, barColor);

        rimColor = a.getColor(R.styleable.LoadMaterialView_matProg_rimColor, rimColor);

        linearProgress = a.getBoolean(R.styleable.LoadMaterialView_matProg_linearProgress, false);

        if (a.getBoolean(R.styleable.LoadMaterialView_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 (!shouldAnimate) {
            return;
        }

        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(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 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();
    }

    /**
     * @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;
    }

    //----------------------------------
    //Getters + setters
    //----------------------------------

    /**
     * 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();
    }

    /**
     * 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();
        }
    }

    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);
    }

    static class WheelSavedState extends BaseSavedState {
        //required field that makes Parcelables from a Parcel
        public static final Creator<WheelSavedState> CREATOR =
                new Creator<WheelSavedState>() {
                    public WheelSavedState createFromParcel(Parcel in) {
                        return new WheelSavedState(in);
                    }

                    public WheelSavedState[] newArray(int size) {
                        return new WheelSavedState[size];
                    }
                };
        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));
        }
    }
}

attrs_LoadMaterialView.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="LoadMaterialView">
        <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>
</resources>
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值