Android APP 显示自定义圆弧进度条(可点击,可滑动)

效果图:

实现思路:

1.定义一个画外弧的画笔,使用画笔画出圆弧UI

2.定义一个画内圆(灰色)的画笔,使用画笔画出内圆UI

3.定义一个画圆点的画笔,使用画笔画出圆点UI

4.定义一个画文本的画笔,使用画笔画出文本的值

5.监听触摸事件,通过触摸事件计算和判断是否在圆弧上。


实现CustomVolumeProgressView自定义View,如下:

import android.content.Context;import android.graphics.Canvas;import android.graphics.Paint;import android.graphics.RectF;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.view.View;import androidx.annotation.NonNull;import androidx.annotation.Nullable;public class CustomVolumeProgressView extends View {    /**     * 进度条所占用的角度     */    private static final int ARC_FULL_DEGREE = 270;    /**     * 绘制进度条画笔     */    private Paint progressBarPaint;    /**     * 绘制内心园画笔     */    private Paint innerCirclePaint;    /**     * 绘制小圆的画笔     */    private Paint smallCirclePaint;    /**     * 绘制文字的画笔     */    private Paint textPaint;    /**     * 绘制文字大小     */    private int textSize = 60;    /**     * 圆弧进度条圆心位置     */    private int centerX, centerY;    /**     * 小圆的半径     */    private int smallCircleRadius ;    /**     * 小圆的宽度     */    private int smallCircleWidth = 7;    /**     * 圆弧进度条绘制区域     */    private RectF progressBarRectF ;    /**     * 圆弧进度值(0-100)     */    private int mProgress;    /**     * 圆弧进度最大值     */    private int mProgressMax = 100;    /**     * 圆弧进度条的宽度     */    private int progressBarWidth = 8;    /**     * 内心园的宽度     */    private int innerCircleWidth = 6;    /**     * 小圆圆心坐标     */    float smallX ,smallY;    /**     * 进度条后端的坐标     */    float progressX ,progressY;    /**     * 进度条半径     */    float progressRadius;    public CustomVolumeProgressView(Context context) {        super(context);        init();    }    public CustomVolumeProgressView(Context context, @Nullable AttributeSet attrs) {        super(context, attrs);        init();    }    public CustomVolumeProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        init();    }    private void  init(){        // 初始化圆弧进度画笔        progressBarPaint = new Paint();        progressBarPaint.setStyle(Paint.Style.STROKE);          // 只描边,不填充        progressBarPaint.setStrokeCap(Paint.Cap.ROUND);         // 设置圆角        progressBarPaint.setAntiAlias(true);                    // 设置抗锯齿        progressBarPaint.setDither(true);                       // 设置抖动        progressBarPaint.setStrokeWidth(progressBarWidth);        progressBarPaint.setColor(getResources().getColor(R.color.progress));        //初始化跟随进度条小圆的画笔        smallCirclePaint = new Paint();        smallCirclePaint.setStyle(Paint.Style.FILL);        // 填充        smallCirclePaint.setStrokeCap(Paint.Cap.ROUND);     // 设置圆角        smallCirclePaint.setAntiAlias(true);                // 设置抗锯齿        smallCirclePaint.setDither(true);                   // 设置抖动        smallCirclePaint.setStrokeWidth(smallCircleRadius);        smallCirclePaint.setColor(getResources().getColor(R.color.progress));        // 初始化内心圆画笔        innerCirclePaint = new Paint();        innerCirclePaint.setStyle(Paint.Style.STROKE);          // 只描边,不填充        innerCirclePaint.setStrokeCap(Paint.Cap.ROUND);         // 设置圆角        innerCirclePaint.setAntiAlias(true);                    // 设置抗锯齿        innerCirclePaint.setDither(true);                       // 设置抖动        innerCirclePaint.setStrokeWidth(innerCircleWidth);        innerCirclePaint.setColor(getResources().getColor(R.color.innerCircle));        //初始化音量值画笔        textPaint = new Paint();        textPaint.setAntiAlias(true);        textPaint.setColor(getResources().getColor(R.color.white));        textPaint.setFakeBoldText(true);        textPaint.setTextSize(textSize);    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        //获取圆弧进度的区域        int viewWide = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();        int viewHigh = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();        int mRectLength = (int) ((viewWide > viewHigh ? viewHigh : viewWide) - progressBarWidth);        int mRectL = getPaddingLeft() + (viewWide - mRectLength) / 2;        int mRectT = getPaddingTop() + (viewHigh - mRectLength) / 2;        progressBarRectF = new RectF(mRectL, mRectT, mRectL + mRectLength, mRectT + mRectLength );        //获取圆弧中心坐标        centerX = getMeasuredWidth() / 2;        centerY = getMeasuredHeight() / 2;        //计算小圆到圆弧进度圆心的半径(距离)        smallCircleRadius = Math.min(getMeasuredWidth(), getMeasuredHeight()) / 2;        progressRadius = smallCircleRadius;        smallCircleRadius -= 30;//适当调整    }    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        //绘制进度条        canvas.drawArc(progressBarRectF, 90 + ((360 - ARC_FULL_DEGREE) >> 1), ARC_FULL_DEGREE * mProgress / 100, false, progressBarPaint);        //绘制跟随进度条的小圆        float swipe = ARC_FULL_DEGREE * mProgress / mProgressMax;        float radians = (float) ((90 + ((360 - ARC_FULL_DEGREE) >> 1) + swipe) / 180  * Math.PI);        smallX = centerX + smallCircleRadius * (float) Math.cos(radians);        smallY = centerY + smallCircleRadius * (float) Math.sin(radians);        progressX = centerX + progressRadius * (float) Math.cos(radians);        progressY = centerY + progressRadius * (float) Math.sin(radians);        canvas.drawCircle(smallX, smallY, smallCircleWidth, smallCirclePaint);        //绘制内心圆        canvas.drawCircle(centerX, centerY, smallCircleRadius + 14, innerCirclePaint);        //绘制文字        float textWidth = textPaint.measureText(mProgress + "");        int textHeight = (int) (Math.ceil(textPaint.getFontMetrics().descent - textPaint.getFontMetrics().ascent) + 2);        canvas.drawText(mProgress + "", centerX - textWidth / 2, centerX + textHeight / 4, textPaint);    }    private boolean isDragging = false;    @Override    public boolean onTouchEvent(@NonNull MotionEvent event) {        //处理拖动事件        float currentX = event.getX();        float currentY = event.getY();        int action = event.getAction();        switch (action) {            case MotionEvent.ACTION_DOWN:                //判断是否在进度条thumb位置                if (checkOnArc(currentX, currentY)) {                    int newProgress = (int) (calDegreeByPosition(currentX, currentY) / ARC_FULL_DEGREE * mProgressMax);                    setProgressSync(newProgress);                    isDragging = true;                }                break;            case MotionEvent.ACTION_MOVE:                if (isDragging) {                    //判断拖动时是否移出去了                    if (checkOnArc(currentX, currentY)) {                        setProgressSync((int)(calDegreeByPosition(currentX, currentY) / ARC_FULL_DEGREE * mProgressMax));                    } else {                        isDragging = false;                    }                }                break;            case MotionEvent.ACTION_UP:                isDragging = false;                break;        }        return true;    }    /**     * 判断该点是否在弧线上(附近)     */    private boolean checkOnArc(float currentX, float currentY) {        float distance = calDistance(currentX, currentY, centerX, centerY);        float degree = calDegreeByPosition(currentX, currentY);        return distance > progressRadius - progressBarWidth * 4 && distance < progressRadius + progressBarWidth * 4                && (degree >= -30 && degree <= ARC_FULL_DEGREE + 30);    }    private float calDistance(float x1, float y1, float x2, float y2) {        return (float) Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));    }    /**     * 根据当前位置,计算出进度条已经转过的角度。     */    private float calDegreeByPosition(float currentX, float currentY) {        float a1 = (float) (Math.atan(1.0f * (centerX - currentX) / (currentY - centerY)) / Math.PI * 180);        if (currentY < centerY) {            a1 += 180;        } else if (currentY > centerY && currentX > centerX) {            a1 += 360;        }        return a1 - (360 - ARC_FULL_DEGREE) / 2;    }    public void setProgressSync(int progress) {        mProgress = checkProgress(progress);        volumeProgressInterface.updatVolumeProgress(progress);        invalidate();    }    private VolumeProgressInterface volumeProgressInterface;    public void setVolumeProgressInterface(VolumeProgressInterface volumeProgressInterface){        this.volumeProgressInterface = volumeProgressInterface;    }    //保证progress的值位于[0,max]    private int checkProgress(int progress) {        if (progress < 0) {            return 0;        }        return progress > mProgressMax ? mProgressMax : progress;    }    public interface VolumeProgressInterface{        //更新音量调节进度        void updatVolumeProgress(int index);    }}


Layout布局如下:

<?xml version="1.0" encoding="utf-8"?>                


MainActivity的主要操作如下:

 CustomVolumeProgressView customVolumeProgressView = findViewById(R.id.volume_progress);        customVolumeProgressView.setProgressSync(66);
展开阅读全文

页面更新:2024-05-11

标签:圆弧   小圆   圆心   画笔   半径   初始化   坐标   进度   内心   定义

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号

Top