自定义进度条

先看效果

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;
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,039评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,223评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,916评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,009评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,030评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,011评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,934评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,754评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,202评论 1 309
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,433评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,590评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,321评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,917评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,568评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,738评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,583评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,482评论 2 352

推荐阅读更多精彩内容