Android实现自定义进度条(源码+解析)

简介: Android实现自定义进度条(源码+解析)

.xml文件

属性介绍

style:进度条的样式
style="?android:attr/progressBarStyleHorizontal":水平样式的进度条
app:zpb_bg_color="#EEDB90":进度条背景颜色
app:zpb_max="100":进度条总进度
app:zpb_pb_color="#F3FF2C":进度条填充颜色
app:zpb_progress="0":进度条当前所处进度
<FrameLayout
  android:layout_width="match_parent"
  android:layout_height="15dp"
  android:layout_gravity="bottom">
  <com.mars.base.view.ZzHorizontalProgressBar
    android:id="@+id/classSchedule"
    style="?android:attr/progressBarStyleHorizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="center"
    android:background="@drawable/class_bg_img"
    app:zpb_bg_color="#EEDB90"
    app:zpb_max="100"
    app:zpb_pb_color="#F3FF2C"
    app:zpb_progress="0" />
  <TextView
    android:id="@+id/user_class_text"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom"
    android:text="1级"
    android:textSize="12sp"
    android:textColor="#640908"
    android:gravity="center"/>
</FrameLayout>

.java文件

package com.gaojc.activity;

import com.gaojc.R;
import com.gaojc.view.ZzHorizontalProgressBar;

public class MainActivity {
    private ZzHorizontalProgressBar classSchedule;//等级进度条

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        classSchedule= findViewById(R.id.classSchedule);
        // 设置进度百分比
        classSchedule.setProgress(GlobalData.getIns().userSchedule);
    }
}

效果图

ZzHorizontalProgressBar

package com.gaojc.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader;
import android.support.annotation.ColorInt;
import android.support.annotation.IntDef;
import android.util.AttributeSet;
import android.view.View;

import com.gaojc.view.R;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


/**
 * 水平进度条
 */
public class ZzHorizontalProgressBar extends View {

    public static final int SHOW_MODE_ROUND = 0;
    public static final int SHOW_MODE_RECT = 1;
    public static final int SHOW_MODE_ROUND_RECT = 2;

    public static final int SHAPE_POINT = 0;
    public static final int SHAPE_LINE = 1;

    private int mMax;
    private int mProgress;
    private int mBgColor;
    private int mProgressColor;
    private int mPadding;
    private boolean mOpenGradient;
    private int mGradientFrom;
    private int mGradientTo;
    private boolean mShowSecondProgress;
    private int mSecondProgress;
    private int mSecondProgressShape;
    private boolean mShowZeroPoint;

    private Paint mSecondProgressPaint;
    private Paint mSecondGradientPaint;
    private Paint mProgressPaint;
    private Paint mGradientPaint;
    private Paint mBgPaint;
    private boolean mOpenSecondGradient;
    private int mSecondGradientFrom;
    private int mSecondGradientTo;
    private int mSecondProgressColor;

    private int mRadius;
    private boolean mDrawBorder = false;
    private int mBorderColor;
    private int mBorderWidth;

    private int mShowMode = 0;
    private Paint mBorderPaint;

    @IntDef({SHOW_MODE_ROUND, SHOW_MODE_RECT, SHOW_MODE_ROUND_RECT})
    @Target({ElementType.PARAMETER, ElementType.METHOD})
    @Retention(RetentionPolicy.SOURCE)
    private @interface ShowMode {
    }

    @IntDef({SHAPE_POINT, SHAPE_LINE})
    @Target({ElementType.PARAMETER, ElementType.METHOD})
    @Retention(RetentionPolicy.SOURCE)
    private @interface SecondProgressShape {
    }

    private OnProgressChangedListener mOnProgressChangedListener;

    public interface OnProgressChangedListener {
        void onProgressChanged(ZzHorizontalProgressBar progressBar, int max, int progress);

        void onSecondProgressChanged(ZzHorizontalProgressBar progressBar, int max, int progress);
    }

    public ZzHorizontalProgressBar(Context context) {
        super(context);
        init(context, null);
    }

    public ZzHorizontalProgressBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public ZzHorizontalProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        initAttrs(context, attrs);
        initPaths();
    }

    private void initAttrs(Context context, AttributeSet attrs) {
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ZzHorizontalProgressBar);
        mMax = a.getInteger(R.styleable.ZzHorizontalProgressBar_zpb_max, 100);
        mProgress = a.getInteger(R.styleable.ZzHorizontalProgressBar_zpb_progress, 0);
        mBgColor = a.getColor(R.styleable.ZzHorizontalProgressBar_zpb_bg_color, 0xff3F51B5);
        mProgressColor = a.getColor(R.styleable.ZzHorizontalProgressBar_zpb_pb_color, 0xffFF4081);
        mSecondProgressColor = a.getColor(R.styleable.ZzHorizontalProgressBar_zpb_second_pb_color, 0xffFF4081);
        mPadding = a.getDimensionPixelSize(R.styleable.ZzHorizontalProgressBar_zpb_padding, 0);
        mShowZeroPoint = a.getBoolean(R.styleable.ZzHorizontalProgressBar_zpb_show_zero_point, false);
        mShowSecondProgress = a.getBoolean(R.styleable.ZzHorizontalProgressBar_zpb_show_second_progress, false);
        mSecondProgress = a.getInteger(R.styleable.ZzHorizontalProgressBar_zpb_second_progress, 0);
        mSecondProgressShape = a.getInteger(R.styleable.ZzHorizontalProgressBar_zpb_show_second_point_shape, SHAPE_POINT);
        mOpenGradient = a.getBoolean(R.styleable.ZzHorizontalProgressBar_zpb_open_gradient, false);
        mGradientFrom = a.getColor(R.styleable.ZzHorizontalProgressBar_zpb_gradient_from, 0xffFF4081);
        mGradientTo = a.getColor(R.styleable.ZzHorizontalProgressBar_zpb_gradient_to, 0xffFF4081);
        mOpenSecondGradient = a.getBoolean(R.styleable.ZzHorizontalProgressBar_zpb_open_second_gradient, false);
        mShowMode = a.getInt(R.styleable.ZzHorizontalProgressBar_zpb_show_mode, SHOW_MODE_ROUND);
        mSecondGradientFrom = a.getColor(R.styleable.ZzHorizontalProgressBar_zpb_second_gradient_from, 0xffFF4081);
        mSecondGradientTo = a.getColor(R.styleable.ZzHorizontalProgressBar_zpb_second_gradient_to, 0xffFF4081);
        mRadius = a.getDimensionPixelSize(R.styleable.ZzHorizontalProgressBar_zpb_round_rect_radius, 20);
        mDrawBorder = a.getBoolean(R.styleable.ZzHorizontalProgressBar_zpb_draw_border, false);
        mBorderWidth = a.getDimensionPixelSize(R.styleable.ZzHorizontalProgressBar_zpb_border_width, 1);
        mBorderColor = a.getColor(R.styleable.ZzHorizontalProgressBar_zpb_border_color, 0xffff001f);
        a.recycle();
    }

    private void initPaths() {
        mProgressPaint = new Paint();
        mProgressPaint.setColor(mProgressColor);
        mProgressPaint.setStyle(Paint.Style.FILL);
        mProgressPaint.setAntiAlias(true);

        mSecondProgressPaint = new Paint();
        mSecondProgressPaint.setColor(mSecondProgressColor);
        mSecondProgressPaint.setStyle(Paint.Style.FILL);
        mSecondProgressPaint.setAntiAlias(true);

        mGradientPaint = new Paint();
        mGradientPaint.setStyle(Paint.Style.FILL);
        mGradientPaint.setAntiAlias(true);

        mSecondGradientPaint = new Paint();
        mSecondGradientPaint.setStyle(Paint.Style.FILL);
        mSecondGradientPaint.setAntiAlias(true);

        mBgPaint = new Paint();
        mBgPaint.setColor(mBgColor);
        mBgPaint.setStyle(Paint.Style.FILL);
        mBgPaint.setAntiAlias(true);

        mBorderPaint = new Paint();
        mBorderPaint.setColor(mBorderColor);
        mBorderPaint.setStyle(Paint.Style.STROKE);
        mBorderPaint.setStrokeWidth(mBorderWidth);
        mBorderPaint.setAntiAlias(true);

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        switch (mShowMode) {
            case SHOW_MODE_ROUND:
                //half circle
                drawBackgroundCircleMode(canvas);
                drawProgressCircleMode(canvas);
                drawBorderCircleMode(canvas);
                break;
            case SHOW_MODE_RECT:
                //rect
                drawBackgroundRectMode(canvas);
                drawProgressRectMode(canvas);
                drawBorderRectMode(canvas);
                break;
            case SHOW_MODE_ROUND_RECT:
                //custom radius
                drawBackgroundRoundRectMode(canvas);
                drawProgressRoundRectMode(canvas);
                drawBorderRoundRect(canvas);
                break;
        }
    }

    /**
     * 绘制半圆形进度
     */
    private void drawProgressCircleMode(Canvas canvas) {
        int width = getWidth();
        float percent = 0;
        if (mMax != 0) {
            percent = mProgress * 1.0f / mMax;
        }
        int progressHeight = getHeight() - mPadding * 2;
        if (mOpenGradient) {
            int progressWidth = width - mPadding * 2;
            float dx = progressWidth * percent;

            int[] colors = new int[2];
            float[] positions = new float[2];
            //from color
            colors[0] = mGradientFrom;
            positions[0] = 0;
            //to color
            colors[1] = mGradientTo;
            positions[1] = 1;
            LinearGradient shader = new LinearGradient(
                    mPadding + progressHeight / 2.0f, mPadding, mPadding + progressHeight / 2.0f + dx, mPadding + progressHeight,
                    colors,
                    positions,
                    Shader.TileMode.MIRROR);
            //gradient
            mGradientPaint.setShader(shader);

            int radius = width > getHeight() ? getHeight() / 2 : width / 2;
            if (dx < getHeight()) {
                //left circle
                if (mProgress == 0) {
                    if (mShowZeroPoint) {
                        canvas.drawCircle(mPadding + progressHeight / 2.0f, mPadding + progressHeight / 2.0f, progressHeight / 2.0f, mGradientPaint);
                    }
                } else {
                    canvas.drawCircle(mPadding + progressHeight / 2.0f, mPadding + progressHeight / 2.0f, progressHeight / 2.0f, mGradientPaint);
                }

            } else {
                //progress line
                RectF rectF = new RectF(mPadding, mPadding, mPadding + dx, mPadding + progressHeight);
                canvas.drawRoundRect(rectF, radius, radius, mGradientPaint);
            }

        } else {
            int progressWidth = width - mPadding * 2 - progressHeight;
            float dx = progressWidth * percent;
            mProgressPaint.setColor(mProgressColor);
            float left = mPadding + progressHeight / 2.0f;
            //left circle
            if (mProgress == 0) {
                if (mShowZeroPoint) {
                    canvas.drawCircle(left, left, progressHeight / 2.0f, mProgressPaint);
                }
            } else {
                canvas.drawCircle(left, left, progressHeight / 2.0f, mProgressPaint);
            }
            //right circle
            if (mProgress == 0) {
                if (mShowZeroPoint) {
                    canvas.drawCircle(left + dx, left, progressHeight / 2.0f, mProgressPaint);
                }
            } else {
                canvas.drawCircle(left + dx, left, progressHeight / 2.0f, mProgressPaint);
            }
            //middle line
            RectF rectF = new RectF(left, mPadding, left + dx, mPadding + progressHeight);
            canvas.drawRect(rectF, mProgressPaint);
        }

        //draw second progress
        if (mShowSecondProgress) {
            float secondPercent = 0;
            if (mMax != 0) {
                secondPercent = mSecondProgress * 1.0f / mMax;
            }
            int secondProgressHeight = getHeight() - mPadding * 2;
            if (mOpenSecondGradient) {
                int secondProgressWidth = width - mPadding * 2;
                float secondDx = secondProgressWidth * secondPercent;

                int[] secondColors = new int[2];
                float[] secondPositions = new float[2];
                //from color
                secondColors[0] = mSecondGradientFrom;
                secondPositions[0] = 0;
                //to color
                secondColors[1] = mSecondGradientTo;
                secondPositions[1] = 1;
                LinearGradient secondShader = new LinearGradient(
                        mPadding + secondProgressHeight / 2.0f, mPadding, mPadding + secondProgressHeight / 2.0f + secondDx, mPadding + secondProgressHeight,
                        secondColors,
                        secondPositions,
                        Shader.TileMode.MIRROR);
                //gradient
                mSecondGradientPaint.setShader(secondShader);

                int secondRadius = width > getHeight() ? getHeight() / 2 : width / 2;
                if (secondDx < getHeight()) {
                    //left circle
                    if (mSecondProgress == 0) {
                        if (mShowZeroPoint) {
                            canvas.drawCircle(mPadding + secondProgressHeight / 2.0f, mPadding + secondProgressHeight / 2.0f, secondProgressHeight / 2.0f, mSecondGradientPaint);
                        }
                    } else {
                        canvas.drawCircle(mPadding + secondProgressHeight / 2.0f, mPadding + secondProgressHeight / 2.0f, secondProgressHeight / 2.0f, mSecondGradientPaint);
                    }
                } else {
                    //progress line
                    RectF rectF = new RectF(mPadding, mPadding, mPadding + secondDx, mPadding + secondProgressHeight);
                    canvas.drawRoundRect(rectF, secondRadius, secondRadius, mSecondGradientPaint);
                }
            } else {
                //no gradient
                if (mSecondProgressShape == 0) {
                    //point shape
                    int secondProgressWidth = width - mPadding * 2;
                    float secondDx = secondProgressWidth * secondPercent;
                    //progress line
                    float px = mPadding + secondProgressHeight / 2.0f + secondDx;
                    if (px < width - mPadding - secondProgressHeight / 2.0f) {
                        if (mSecondProgress == 0) {
                            if (mShowZeroPoint) {
                                canvas.drawCircle(px, mPadding + secondProgressHeight / 2.0f, secondProgressHeight / 2.0f, mSecondProgressPaint);
                            }
                        } else {
                            canvas.drawCircle(px, mPadding + secondProgressHeight / 2.0f, secondProgressHeight / 2.0f, mSecondProgressPaint);
                        }
                    } else {
                        canvas.drawCircle(px - secondProgressHeight, mPadding + secondProgressHeight / 2.0f, secondProgressHeight / 2.0f, mSecondProgressPaint);
                    }

                } else {
                    //line shape
                    int secondProgressWidth = width - mPadding * 2 - secondProgressHeight;
                    float dx = secondProgressWidth * secondPercent;
                    mSecondProgressPaint.setColor(mSecondProgressColor);
                    //left circle
                    if (mSecondProgress == 0) {
                        if (mShowZeroPoint) {
                            canvas.drawCircle(mPadding + secondProgressHeight / 2.0f, mPadding + secondProgressHeight / 2.0f, secondProgressHeight / 2.0f, mSecondProgressPaint);
                        }
                    } else {
                        canvas.drawCircle(mPadding + secondProgressHeight / 2.0f, mPadding + secondProgressHeight / 2.0f, secondProgressHeight / 2.0f, mSecondProgressPaint);
                    }
                    //right circle
                    if (mSecondProgress == 0) {
                        if (mShowZeroPoint) {
                            canvas.drawCircle(mPadding + secondProgressHeight / 2.0f + dx, mPadding + secondProgressHeight / 2.0f, secondProgressHeight / 2.0f, mSecondProgressPaint);
                        }
                    } else {
                        canvas.drawCircle(mPadding + secondProgressHeight / 2.0f + dx, mPadding + secondProgressHeight / 2.0f, secondProgressHeight / 2.0f, mSecondProgressPaint);
                    }
                    //middle line
                    RectF rectF = new RectF(mPadding + secondProgressHeight / 2.0f, mPadding, mPadding + secondProgressHeight / 2.0f + dx, mPadding + secondProgressHeight);
                    canvas.drawRect(rectF, mSecondProgressPaint);
                }
            }
        }

    }

    /**
     * 绘制方形进度
     */
    private void drawProgressRectMode(Canvas canvas) {
        int width = getWidth();
        float percent = 0;
        if (mMax != 0) {
            percent = mProgress * 1.0f / mMax;
        }
        int progressHeight = getHeight() - mPadding * 2;
        if (mOpenGradient) {
            int progressWidth = width - mPadding * 2;
            float mDx = progressWidth * percent;

            int[] colors = new int[2];
            float[] positions = new float[2];
            //from color
            colors[0] = mGradientFrom;
            positions[0] = 0;
            //to color
            colors[1] = mGradientTo;
            positions[1] = 1;
            LinearGradient shader = new LinearGradient(
                    mPadding + progressHeight / 2.0f, mPadding, mPadding + progressHeight / 2.0f + mDx, mPadding + progressHeight,
                    colors,
                    positions,
                    Shader.TileMode.MIRROR);
            //gradient
            mGradientPaint.setShader(shader);

            //progress line
            RectF rectF = new RectF(mPadding, mPadding, mPadding + mDx, mPadding + progressHeight);
            canvas.drawRect(rectF, mGradientPaint);

        } else {
            int progressWidth = width - mPadding * 2;
            float dx = progressWidth * percent;
            mProgressPaint.setColor(mProgressColor);
            RectF rectF = new RectF(mPadding, mPadding, mPadding + dx, mPadding + progressHeight);
            canvas.drawRect(rectF, mProgressPaint);
        }

        //draw second progress
        if (mShowSecondProgress) {
            float secondPercent = 0;
            if (mMax != 0) {
                secondPercent = mSecondProgress * 1.0f / mMax;
            }
            int secondProgressHeight = getHeight() - mPadding * 2;
            if (mOpenSecondGradient) {
                int secondProgressWidth = width - mPadding * 2;
                float secondDx = secondProgressWidth * secondPercent;

                int[] secondColors = new int[2];
                float[] secondPositions = new float[2];
                //from color
                secondColors[0] = mSecondGradientFrom;
                secondPositions[0] = 0;
                //to color
                secondColors[1] = mSecondGradientTo;
                secondPositions[1] = 1;
                LinearGradient secondShader = new LinearGradient(
                        mPadding + secondProgressHeight / 2.0f, mPadding, mPadding + secondProgressHeight / 2.0f + secondDx, mPadding + secondProgressHeight,
                        secondColors,
                        secondPositions,
                        Shader.TileMode.MIRROR);
                //gradient
                mSecondGradientPaint.setShader(secondShader);

                //progress line
                RectF rectF = new RectF(mPadding, mPadding, mPadding + secondDx, mPadding + secondProgressHeight);
                canvas.drawRect(rectF, mSecondGradientPaint);
            } else {
                //no gradient
                //line shape
                int secondProgressWidth = width - mPadding * 2;
                float dx = secondProgressWidth * secondPercent;
                mSecondProgressPaint.setColor(mSecondProgressColor);
                RectF rectF = new RectF(mPadding, mPadding, mPadding + dx, mPadding + secondProgressHeight);
                canvas.drawRect(rectF, mSecondProgressPaint);
            }
        }

    }

    /**
     * 绘制圆角矩形进度
     */
    private void drawProgressRoundRectMode(Canvas canvas) {
        int width = getWidth();
        float percent = 0;
        if (mMax != 0) {
            percent = mProgress * 1.0f / mMax;
        }
        int progressHeight = getHeight() - mPadding * 2;
        int progressWidth = width - mPadding * 2 - mBorderWidth;
        float dx = progressWidth * percent;
        if (mOpenGradient) {
            int[] colors = new int[2];
            float[] positions = new float[2];
            //from color
            colors[0] = mGradientFrom;
            positions[0] = 0;
            //to color
            colors[1] = mGradientTo;
            positions[1] = 1;
            float left = mPadding + progressHeight / 2.0f;
            LinearGradient shader = new LinearGradient(
                    left, mPadding, left + dx, mPadding + progressHeight,
                    colors,
                    positions,
                    Shader.TileMode.MIRROR);
            //gradient
            mGradientPaint.setShader(shader);
            //progress line
            float rectLeft = mPadding + mBorderWidth / 2.0f;
            float rectTop = mPadding + mBorderWidth / 2.0f;
            RectF rectF = new RectF(rectLeft, rectTop, rectLeft + dx, getHeight() - rectTop);
            canvas.drawRoundRect(rectF, mRadius, mRadius, mGradientPaint);
        } else {
            mProgressPaint.setColor(mProgressColor);
            float rectLeft = mPadding + mBorderWidth / 2.0f;
            float rectTop = mPadding + mBorderWidth / 2.0f;
            RectF rectF = new RectF(rectLeft, rectTop, rectLeft + dx, getHeight() - rectTop);
            canvas.drawRoundRect(rectF, mRadius, mRadius, mProgressPaint);
        }

        //draw second progress
        if (mShowSecondProgress) {
            float secondPercent = 0;
            if (mMax != 0) {
                secondPercent = mSecondProgress * 1.0f / mMax;
            }
            int secondProgressHeight = getHeight() - mPadding * 2;
            int secondProgressWidth = width - mPadding * 2 - mBorderWidth;
            float secondDx = secondProgressWidth * secondPercent;
            if (mOpenSecondGradient) {
                int[] secondColors = new int[2];
                float[] secondPositions = new float[2];
                //from color
                secondColors[0] = mSecondGradientFrom;
                secondPositions[0] = 0;
                //to color
                secondColors[1] = mSecondGradientTo;
                secondPositions[1] = 1;
                float left = mPadding + secondProgressHeight / 2.0f;
                LinearGradient secondShader = new LinearGradient(
                        left, mPadding, left + secondDx, mPadding + secondProgressHeight,
                        secondColors,
                        secondPositions,
                        Shader.TileMode.MIRROR);
                //gradient
                mSecondGradientPaint.setShader(secondShader);

                //progress line
                float rectLeft = mPadding + mBorderWidth / 2.0f;
                float rectTop = mPadding + mBorderWidth / 2.0f;
                RectF rectF = new RectF(rectLeft, rectTop, rectLeft + secondDx, getHeight() - rectTop);
                canvas.drawRoundRect(rectF, mRadius, mRadius, mSecondGradientPaint);
            } else {
                //no gradient
                //line shape
                mSecondProgressPaint.setColor(mSecondProgressColor);
                float rectLeft = mPadding + mBorderWidth / 2.0f;
                float rectTop = mPadding + mBorderWidth / 2.0f;
                RectF rectF = new RectF(rectLeft, rectTop, rectLeft + secondDx, getHeight() - rectTop);
                canvas.drawRoundRect(rectF, mRadius, mRadius, mSecondProgressPaint);
            }
        }

    }

    /**
     * 绘制半圆形背景
     */
    private void drawBackgroundCircleMode(Canvas canvas) {
        int bgHeight = getHeight();
        int width = getWidth();
        //left circle
        canvas.drawCircle(bgHeight / 2.0f, bgHeight / 2.0f, bgHeight / 2.0f, mBgPaint);
        //right circle
        canvas.drawCircle(width - bgHeight / 2.0f, bgHeight / 2.0f, bgHeight / 2.0f, mBgPaint);
        //middle line
        RectF rectF = new RectF(bgHeight / 2.0f, 0, width - bgHeight / 2.0f, bgHeight);
        canvas.drawRect(rectF, mBgPaint);
    }

    /**
     * 绘制半圆形边框
     */
    private void drawBorderCircleMode(Canvas canvas) {
        if (mDrawBorder) {
            int bgHeight = getHeight();
            int width = getWidth();
            RectF rect = new RectF(0, 0, width, bgHeight);
            canvas.drawRoundRect(rect, bgHeight / 2.0f, bgHeight / 2.0f, mBorderPaint);
        }
    }

    /**
     * 绘制半方形边框
     */
    private void drawBorderRectMode(Canvas canvas) {
        if (mDrawBorder) {
            int bgHeight = getHeight();
            int width = getWidth();
            RectF rect = new RectF(0, 0, width, bgHeight);
            canvas.drawRect(rect, mBorderPaint);
        }
    }

    /**
     * 绘制圆角矩形边框
     */
    private void drawBorderRoundRect(Canvas canvas) {
        if (mDrawBorder) {
            int bgHeight = getHeight();
            int width = getWidth();
            RectF rect = new RectF(mBorderWidth / 2.0f, mBorderWidth / 2.0f, width - mBorderWidth / 2.0f, bgHeight - mBorderWidth / 2.0f);
            canvas.drawRoundRect(rect, mRadius, mRadius, mBorderPaint);
        }
    }

    /**
     * 绘制方形背景
     */
    private void drawBackgroundRectMode(Canvas canvas) {
        int bgHeight = getHeight();
        int width = getWidth();
        RectF rectF = new RectF(0, 0, width, bgHeight);
        canvas.drawRect(rectF, mBgPaint);
    }

    /**
     * 绘制圆角矩形背景
     */
    private void drawBackgroundRoundRectMode(Canvas canvas) {
        int bgHeight = getHeight();
        int width = getWidth();
        RectF rectF = new RectF(mBorderWidth / 2.0f, mBorderWidth / 2.0f, width - mBorderWidth / 2.0f, bgHeight - mBorderWidth / 2.0f);
        canvas.drawRoundRect(rectF, mRadius, mRadius, mBgPaint);
    }

    /**
     * 获取最大值
     *
     * @return 最大值
     */
    public int getMax() {
        return mMax;
    }

    /**
     * 设置最大值
     *
     * @param max 最大值
     */
    public void setMax(int max) {
        this.mMax = max;
        invalidate();
    }

    /**
     * 获取一级进度值
     *
     * @return 进度值
     */
    public int getProgress() {
        return mProgress;
    }

    /**
     * 设置一级进度值
     *
     * @param progress 进度值
     */
    public void setProgress(int progress) {
        if (progress < 0) {
            this.mProgress = 0;
        } else if (progress > mMax) {
            this.mProgress = mMax;
        } else {
            this.mProgress = progress;
        }
        invalidate();
        if (mOnProgressChangedListener != null) {
            mOnProgressChangedListener.onProgressChanged(this, mMax, this.mProgress);
        }
    }

    /**
     * 是否显示二级进度条
     *
     * @return 是/否
     */
    public boolean isShowSecondProgress() {
        return mShowSecondProgress;
    }

    /**
     * 设置是否显示二级进度条
     *
     * @param showSecondProgress 是/否
     */
    public void setShowSecondProgress(boolean showSecondProgress) {
        this.mShowSecondProgress = showSecondProgress;
        invalidate();
    }

    /**
     * 获取二级进度条进度
     *
     * @return 进度值
     */
    public int getSecondProgress() {
        return mSecondProgress;
    }

    /**
     * 设置二级进度条进度
     *
     * @param secondProgress 进度值
     */
    public void setSecondProgress(int secondProgress) {
        if (secondProgress < 0) {
            this.mSecondProgress = 0;
        } else if (secondProgress > mMax) {
            this.mSecondProgress = mMax;
        } else {
            this.mSecondProgress = secondProgress;
        }
        invalidate();
        if (mOnProgressChangedListener != null) {
            mOnProgressChangedListener.onSecondProgressChanged(this, mMax, this.mSecondProgress);
        }
    }

    /**
     * 获取二级进度条形状
     *
     * @return 形状,点:{@link #SHAPE_POINT} 线:{@link #SHAPE_LINE}
     */
    public int getSecondProgressShape() {
        return mSecondProgressShape;
    }

    /**
     * 设置二级进度条形状
     *
     * @param secondProgressShape 形状,点:{@link #SHAPE_POINT} 线:{@link #SHAPE_LINE}
     */
    public void setSecondProgressShape(@SecondProgressShape int secondProgressShape) {
        this.mSecondProgressShape = secondProgressShape;
        invalidate();
    }

    /**
     * 获取背景色
     *
     * @return 颜色值
     */
    public int getBgColor() {
        return mBgColor;
    }

    /**
     * 设置背景色
     *
     * @param bgColor 颜色值
     */
    public void setBgColor(@ColorInt int bgColor) {
        this.mBgColor = bgColor;
        mBgPaint.setColor(bgColor);
        invalidate();
    }

    /**
     * 获取二级渐变是否启用
     *
     * @return 是/否
     */
    public boolean isOpenSecondGradient() {
        return mOpenSecondGradient;
    }

    /**
     * 设置二级渐变是否启用
     *
     * @param openSecondGradient 是/否
     */
    public void setOpenSecondGradient(boolean openSecondGradient) {
        this.mOpenSecondGradient = openSecondGradient;
        invalidate();
    }

    public int getSecondGradientFrom() {
        return mSecondGradientFrom;
    }

    public int getSecondGradientTo() {
        return mSecondGradientTo;
    }

    /**
     * 获取二级进度条颜色
     *
     * @return 颜色值
     */
    public int getSecondProgressColor() {
        return mSecondProgressColor;
    }

    /**
     * 设置二级进度条颜色
     *
     * @param secondProgressColor 颜色值
     */
    public void setSecondProgressColor(@ColorInt int secondProgressColor) {
        this.mSecondProgressColor = secondProgressColor;
        mSecondProgressPaint.setColor(secondProgressColor);
        invalidate();
    }

    /**
     * 获取一级进度条颜色
     *
     * @return 颜色值
     */
    public int getProgressColor() {
        return mProgressColor;
    }

    /**
     * 设置一级进度条颜色
     *
     * @param progressColor 颜色值
     */
    public void setProgressColor(@ColorInt int progressColor) {
        this.mProgressColor = progressColor;
        mProgressPaint.setColor(progressColor);
        invalidate();
    }

    /**
     * 获取内边距
     *
     * @return 边距值
     */
    public int getPadding() {
        return mPadding;
    }

    /**
     * 设置内边距
     *
     * @param padding 边距值
     */
    public void setPadding(int padding) {
        this.mPadding = padding;
        invalidate();
    }

    /**
     * 设置显示模式
     *
     * @param showMode 显示模式,0:半圆,1:方形,2:圆角矩形
     */
    public void setShowMode(@ShowMode int showMode) {
        switch (showMode) {
            case SHOW_MODE_ROUND:
                this.mShowMode = 0;
                break;
            case SHOW_MODE_RECT:
                this.mShowMode = 1;
                break;
            case SHOW_MODE_ROUND_RECT:
                this.mShowMode = 2;
                break;
        }
        invalidate();
    }

    /**
     * 获取进度百分比,int类型
     *
     * @return percentage value
     */
    public int getPercentage() {
        if (mMax == 0) {
            return 0;
        }
        return (int) (mProgress * 100.0f / mMax + 0.5f);
    }

    /**
     * 获取进度百分比,float类型
     *
     * @return percentage value
     */
    public float getPercentageFloat() {
        if (mMax == 0) {
            return 0f;
        }
        return mProgress * 100.0f / mMax;
    }

    /**
     * 一级渐变色是否启用
     *
     * @return 是/否
     */
    public boolean isOpenGradient() {
        return mOpenGradient;
    }

    /**
     * 设置一级渐变色是否启用
     *
     * @param openGradient 是/否
     */
    public void setOpenGradient(boolean openGradient) {
        this.mOpenGradient = openGradient;
        invalidate();
    }

    public int getGradientFrom() {
        return mGradientFrom;
    }

    public int getGradientTo() {
        return mGradientTo;
    }

    /**
     * 设置边框颜色
     *
     * @param borderColor 颜色值
     */
    public void setBorderColor(@ColorInt int borderColor) {
        this.mBorderColor = borderColor;
        this.mBorderPaint.setColor(this.mBorderColor);
        invalidate();
    }

    /**
     * 设置一级进度条的渐变色
     *
     * @param from 起始颜色
     * @param to   结束颜色
     */
    public void setGradientColor(int from, int to) {
        this.mGradientFrom = from;
        this.mGradientTo = to;
        invalidate();
    }

    /**
     * 设置二级进度条的渐变色
     *
     * @param from 起始颜色
     * @param to   结束颜色
     */
    public void setSecondGradientColor(int from, int to) {
        this.mSecondGradientFrom = from;
        this.mSecondGradientTo = to;
        invalidate();
    }

    /**
     * 设置一级进度条的渐变色和边框颜色
     *
     * @param from        起始颜色
     * @param to          结束颜色
     * @param borderColor 边框颜色
     */
    public void setGradientColorAndBorderColor(int from, int to, int borderColor) {
        this.mGradientFrom = from;
        this.mGradientTo = to;
        this.mBorderColor = borderColor;
        this.mBorderPaint.setColor(this.mBorderColor);
        invalidate();
    }

    /**
     * 获取边框颜色
     *
     * @return 颜色值
     */
    public int getBorderColor() {
        return mBorderColor;
    }

    /**
     * 设置进度变化监听(包括一级和二级进度)
     *
     * @param onProgressChangedListener 进度值变化回调
     */
    public void setOnProgressChangedListener(OnProgressChangedListener onProgressChangedListener) {
        this.mOnProgressChangedListener = onProgressChangedListener;
    }
}
目录
相关文章
|
2月前
|
Android开发 UED 计算机视觉
Android自定义view之线条等待动画(灵感来源:金铲铲之战)
本文介绍了一款受游戏“金铲铲之战”启发的Android自定义View——线条等待动画的实现过程。通过将布局分为10份,利用`onSizeChanged`测量最小长度,并借助画笔绘制动态线条,实现渐变伸缩效果。动画逻辑通过四个变量控制线条的增长与回退,最终形成流畅的等待动画。代码中详细展示了画笔初始化、线条绘制及动画更新的核心步骤,并提供完整源码供参考。此动画适用于加载场景,提升用户体验。
304 5
Android自定义view之线条等待动画(灵感来源:金铲铲之战)
|
2月前
|
Android开发
Android自定义view之利用PathEffect实现动态效果
本文介绍如何在Android自定义View中利用`PathEffect`实现动态效果。通过改变偏移量,结合`PathEffect`的子类(如`CornerPathEffect`、`DashPathEffect`、`PathDashPathEffect`等)实现路径绘制的动态变化。文章详细解析了各子类的功能与参数,并通过案例代码展示了如何使用`ComposePathEffect`组合效果,以及通过修改偏移量实现动画。最终效果为一个菱形图案沿路径运动,源码附于文末供参考。
|
2月前
|
XML Java Android开发
Android自定义view之网易云推荐歌单界面
本文详细介绍了如何通过自定义View实现网易云音乐推荐歌单界面的效果。首先,作者自定义了一个圆角图片控件`MellowImageView`,用于绘制圆角矩形图片。接着,通过将布局放入`HorizontalScrollView`中,实现了左右滑动功能,并使用`ViewFlipper`添加图片切换动画效果。文章提供了完整的代码示例,包括XML布局、动画文件和Java代码,最终展示了实现效果。此教程适合想了解自定义View和动画效果的开发者。
153 65
Android自定义view之网易云推荐歌单界面
|
2月前
|
XML 前端开发 Android开发
一篇文章带你走近Android自定义view
这是一篇关于Android自定义View的全面教程,涵盖从基础到进阶的知识点。文章首先讲解了自定义View的必要性及简单实现(如通过三个构造函数解决焦点问题),接着深入探讨Canvas绘图、自定义属性设置、动画实现等内容。还提供了具体案例,如跑马灯、折线图、太极图等。此外,文章详细解析了View绘制流程(measure、layout、draw)和事件分发机制。最后延伸至SurfaceView、GLSurfaceView、SVG动画等高级主题,并附带GitHub案例供实践。适合希望深入理解Android自定义View的开发者学习参考。
408 84
|
1月前
|
安全 Java Android开发
为什么大厂要求安卓开发者掌握Kotlin和Jetpack?深度解析现代Android开发生态优雅草卓伊凡
为什么大厂要求安卓开发者掌握Kotlin和Jetpack?深度解析现代Android开发生态优雅草卓伊凡
73 0
为什么大厂要求安卓开发者掌握Kotlin和Jetpack?深度解析现代Android开发生态优雅草卓伊凡
|
2月前
|
前端开发 Android开发 UED
讲讲Android为自定义view提供的SurfaceView
本文详细介绍了Android中自定义View时使用SurfaceView的必要性和实现方式。首先分析了在复杂绘制逻辑和高频界面更新场景下,传统View可能引发卡顿的问题,进而引出SurfaceView作为解决方案。文章通过Android官方Demo展示了SurfaceView的基本用法,包括实现`SurfaceHolder.Callback2`接口、与Activity生命周期绑定、子线程中使用`lockCanvas()`和`unlockCanvasAndPost()`方法完成绘图操作。
|
2月前
|
Android开发 开发者
Android自定义view之围棋动画(化繁为简)
本文介绍了Android自定义View的动画实现,通过两个案例拓展动态效果。第一个案例基于`drawArc`方法实现单次动画,借助布尔值控制动画流程。第二个案例以围棋动画为例,从简单的小球直线运动到双向变速运动,最终实现循环动画效果。代码结构清晰,逻辑简明,展示了如何化繁为简实现复杂动画,帮助读者拓展动态效果设计思路。文末提供完整源码,适合初学者和进阶开发者学习参考。
Android自定义view之围棋动画(化繁为简)
|
2月前
|
Java Android开发 开发者
Android自定义view之围棋动画
本文详细介绍了在Android中自定义View实现围棋动画的过程。从测量宽高、绘制棋盘背景,到创建固定棋子及动态棋子,最后通过属性动画实现棋子的移动效果。文章还讲解了如何通过自定义属性调整棋子和棋盘的颜色及动画时长,并优化视觉效果,如添加渐变色让白子更明显。最终效果既可作为围棋动画展示,也可用作加载等待动画。代码完整,适合进阶开发者学习参考。
|
4月前
|
算法 测试技术 C语言
深入理解HTTP/2:nghttp2库源码解析及客户端实现示例
通过解析nghttp2库的源码和实现一个简单的HTTP/2客户端示例,本文详细介绍了HTTP/2的关键特性和nghttp2的核心实现。了解这些内容可以帮助开发者更好地理解HTTP/2协议,提高Web应用的性能和用户体验。对于实际开发中的应用,可以根据需要进一步优化和扩展代码,以满足具体需求。
409 29
|
4月前
|
前端开发 数据安全/隐私保护 CDN
二次元聚合短视频解析去水印系统源码
二次元聚合短视频解析去水印系统源码
125 4

热门文章

最新文章

推荐镜像

更多