自定义进度条

先看效果

play.gif

load.gif

网上开源的进度条很多,效果好,优化好,可是为了学习,还是自己写一个试试。
实习太忙,匆匆忙忙贴上代码,只为抛砖引玉。
在这里把代码分享出来,特别简单,入门自定义View的可以看看,如果有什么不好的请大家指正。

/**
 * auther : LiuJiakuo
 * e-mail : 
 * erp : 
 * date : 2018/8/29  18:49
 * desc :
 */
public class SeekBar extends View {
    private Context context;
    private Paint nonePaint;//播放进度
    private Paint progressPaint;//播放进度
    private Paint bufferPaint;//缓冲进度
    private Path path;
    private Paint bubblepaint;//气泡
    private int bufferColor;//缓冲颜色
    private int progressColor;//播放进度颜色
    private int noneColor;//未加载颜色
    private int barWidth;//进度条粗
    private Bitmap loadBitmap;
    private Matrix matrix;

    private Rect rect;//进度条可以点击的地方

    private int playProgress;
    private int bufferProgress;
    private float r;//气泡半径
    private float h;//三角高度
    private float lineR;//圆点
    private int loadImgDegrees = 0;

    private boolean isSeek = false;//是否在加载
    private ProgressListener listener;

    public SeekBar(Context context) {
        super(context);
        init(context);
    }

    public SeekBar(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public SeekBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    public void setListener(ProgressListener listener) {
        this.listener = listener;
    }

    /**
     * 设置播放进度
     *
     * @param playProgress 0-100
     */
    public void setPlayProgress(int playProgress) {
        if (playProgress < 0 || playProgress > 100 || this.playProgress == playProgress || isSeek)
            return;
        this.playProgress = playProgress;
        invalidate();
    }

    /**
     * 设置缓存进度
     *
     * @param bufferProgress 0-100
     */
    public void setBufferProgress(int bufferProgress) {
        if (bufferProgress < 0 || bufferProgress > 100 || this.bufferProgress == bufferProgress || isSeek)
            return;
        this.bufferProgress = bufferProgress;
        invalidate();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int width = widthSize;
        int height = heightSize;

        if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST) {
            width = getWidth();
            height = (int) (lineR * 2 + r + h + 4 + 1);
        } else if (widthMode == MeasureSpec.AT_MOST) {
            width = getWidth();
            height = heightSize;
        } else if (heightMode == MeasureSpec.AT_MOST) {
            width = widthSize;
            height = (int) (lineR * 2 + r + h + 4 + 1);
        }
        setMeasuredDimension(width, height);

    }

    private void init(Context context) {
        this.context = context;
        defaultSize();
        path = new Path();

        bufferPaint = new Paint();
        progressPaint = new Paint();
        nonePaint = new Paint();
        bubblepaint = new Paint();

        bufferPaint.setStyle(Paint.Style.FILL);
        bufferPaint.setStrokeCap(Paint.Cap.ROUND);
        progressPaint.setStyle(Paint.Style.FILL);
        progressPaint.setStrokeCap(Paint.Cap.ROUND);
        nonePaint.setStyle(Paint.Style.FILL);
        nonePaint.setStrokeCap(Paint.Cap.ROUND);
        bubblepaint.setStyle(Paint.Style.FILL);

        bufferPaint.setAntiAlias(true);
        progressPaint.setAntiAlias(true);
        nonePaint.setAntiAlias(true);
        bubblepaint.setAntiAlias(true);

        bufferPaint.setStrokeWidth(barWidth);
        progressPaint.setStrokeWidth(barWidth);
        nonePaint.setStrokeWidth(barWidth);

        bufferPaint.setColor(bufferColor);
        progressPaint.setColor(progressColor);
        nonePaint.setColor(noneColor);
        bubblepaint.setColor(Color.parseColor("#3A7EEC"));

    }

    public void setBufferColor(@ColorInt int bufferColor) {
        this.bufferColor = bufferColor;
    }

    public void setProgressColor(@ColorInt int progressColor) {
        this.progressColor = progressColor;
    }

    public void setNoneColor(@ColorInt int noneColor) {
        this.noneColor = noneColor;
    }

    private void defaultSize() {
        barWidth = 3;
        r = 14;
        h = 20;
        lineR = 8;
        noneColor = Color.parseColor("#999999");
        bufferColor = Color.parseColor("#CCCCCC");
        progressColor = Color.parseColor("#00EE00");
        matrix = new Matrix();
        loadBitmap = BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_load);
        matrix.setRotate(loadImgDegrees, loadBitmap.getWidth() >> 1, loadBitmap.getHeight() >> 1);
        post(new Runnable() {
            @Override
            public void run() {
                rect = new Rect(0, (int) (r + h), getMeasuredWidth(), (int) (r + h + lineR * 2 + 4));
            }
        });

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Log.d("TAGTAG", "onDraw: " + bufferProgress);
        Log.d("TAGTAG", "onDraw: " + playProgress);
        int width = getMeasuredWidth();
        float startY = r + h + 4 + lineR;
        canvas.drawLine(0, startY, width, startY, nonePaint);
        canvas.drawLine(0, startY, width * bufferProgress / 100, startY, bufferPaint);
        canvas.drawLine(0, startY, width * playProgress / 100, startY, progressPaint);
        bubblepaint.setColor(Color.parseColor("#993A7EEC"));
        canvas.drawCircle(width * playProgress / 100, startY, lineR, bubblepaint);
        drawBubble(canvas);
    }

    private void drawBubble(Canvas canvas) {
        bubblepaint.setColor(Color.parseColor("#CC3A7EEC"));
        int width = getMeasuredWidth();
        float startY = r + h;//-3比线高
        float pro = width * playProgress / 100;
        float sqrt = r / ((float) Math.sqrt(2));
        RectF rect = new RectF((pro - r), (startY - h - r), (pro + r), (startY - h + r));
        path.reset();
        path.moveTo(pro, startY);
        path.lineTo(pro + sqrt, sqrt + r);
        path.addArc(rect, 45, -270);
        path.lineTo(pro - sqrt, sqrt + r);
        path.lineTo(pro, startY);
        canvas.drawPath(path, bubblepaint);

        bubblepaint.setTextSize(14);
        bubblepaint.setColor(Color.WHITE);
        Paint.FontMetricsInt fontMetricsInt = bubblepaint.getFontMetricsInt();
        bubblepaint.setTextAlign(Paint.Align.CENTER);
        int baseline = (int) ((rect.bottom + rect.top - fontMetricsInt.bottom - fontMetricsInt.top) / 2);//文字居中,基线算法

        if (bufferProgress != 0 && bufferProgress <= playProgress && !isSeek) {
            //todo 内存抖动风险
            Bitmap bitmap = Bitmap.createBitmap(loadBitmap, 0, 0, loadBitmap.getWidth(), loadBitmap.getHeight(), matrix, true);
            canvas.drawBitmap(bitmap, null, rect, nonePaint);
            loadImgDegrees += 20;
            matrix.setRotate(loadImgDegrees, loadBitmap.getWidth() >> 1, loadBitmap.getHeight() >> 1);
            postInvalidateDelayed(160, (int) rect.left, (int) rect.top, (int) rect.right, (int) rect.bottom);
        } else {
            canvas.drawText(playProgress + "%", rect.centerX(), baseline, bubblepaint);
        }

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:

                if (isPointInRect(new PointF(event.getX(), event.getY()), rect)) {
                    int x = (int) (event.getX() * 100 / getMeasuredWidth());
                    seekTo(x);
                    if (listener != null && !isSeek) {
                        listener.onPause();
                    }
                    isSeek = true;
                }

                break;
            case MotionEvent.ACTION_UP:
                if (isSeek) {
                    isSeek = false;
                    if (listener != null)
                        listener.onResume();
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if (isSeek) {
                    int x = (int) (event.getX() * 100 / getMeasuredWidth());
                    seekTo(x);
                }
                break;
        }
        return true;
    }

    /**
     * @param x 0~100
     */
    private void seekTo(int x) {
        playProgress = x;
        invalidate();
        if (listener != null)
            listener.seekTo(x);
    }

    public interface ProgressListener {
        //0-100
        void seekTo(int seek);

        void onPause();

        void onResume();
    }

    /**
     * 判断这个点有没有在矩形内
     *
     * @param pointF
     * @param targetRect
     * @return
     */
    private boolean isPointInRect(PointF pointF, Rect targetRect) {
        if (pointF.x < targetRect.left) {
            return false;
        }
        if (pointF.x > targetRect.right) {
            return false;
        }
        if (pointF.y < targetRect.top) {
            return false;
        }
        if (pointF.y > targetRect.bottom) {
            return false;
        }
        return true;
    }
}

你可能感兴趣的:(自定义进度条)