android 自定义八边形进度条

自定义八边形动画效果图如下

绘制步骤:

1.先绘制橙色底部八边形实心

2.黑色画笔绘制第二层,让最外层显示一条线条宽度即可

3.再用黄色画笔绘制黄色部分

4.使用渐变画笔根据当前进度绘制覆盖黄色部分

5.使用黑色画笔根据当前进度绘制刻度条

6.黑色画笔绘制第三层留出黄色部分的宽度

完整代码

javascript 复制代码
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RadialGradient;
import android.graphics.RectF;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.view.View;

public class EightView extends View {
    private Paint mPaint;
    private Paint roundPaint;
    private Paint bgPaint;
    private float mR, mCx, mCy,mR1,mR2;
    private static final int mN = 8;
    private static final float DEGREES_UNIT = 360 / mN; //正N边形每个角  360/mN能整除
    private int width = 0;
    private int height = 0;


    //外部描边色:#d06d38

    private int[] colors = new int[]{
            Color.parseColor("#e3682f"),
            Color.parseColor("#e3682f"),
            Color.parseColor("#e59f3a"),
            Color.parseColor("#e59f3a"),
    };

    public EightView(Context context) {
        this(context, null);
    }

    public EightView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public EightView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        //   PorterDuffXfermode porterDuffXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
        //绘制8边形外环
        mPaint = new Paint();
        mPaint.setColor(Color.parseColor("#e3682f"));
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeCap(Paint.Cap.ROUND); // 设置转弯处为圆角
        // 当绘图样式为 STROKE 时,该方法用于指定线条连接处的拐角样式,能使绘制的图形更加平滑
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeWidth(50F);
        //  mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST));
        mPaint.setAntiAlias(true);

        //绘制刻度圆,然后进行裁剪,按照外环的大小
        roundPaint=new Paint();
        roundPaint.setStyle(Paint.Style.FILL);
        roundPaint.setAntiAlias(true);
        roundPaint.setStrokeWidth(8);
        //  roundPaint.setXfermode(porterDuffXfermode);

        //绘制黑色背景,bgPaint


        bgPaint=new Paint();
        bgPaint.setColor(Color.YELLOW);
        bgPaint.setStyle(Paint.Style.FILL);
        bgPaint.setAntiAlias(true);
        //    bgPaint.setXfermode(porterDuffXfermode);
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        width = getSize(widthMeasureSpec);
        height = getSize(heightMeasureSpec);
        if (width < height) {
            height = width;
        } else {
            width = height;
        }
        setMeasuredDimension(width, height);
    }

    private int getSize(int measureSpec) {
        int mySize = 100;
        int mode = MeasureSpec.getMode(measureSpec);
        int size = MeasureSpec.getSize(measureSpec);
        switch (mode) {
            case MeasureSpec.UNSPECIFIED: {//如果没有指定大小:就设置为默认大小
                mySize = 100;
                break;
            }
            case MeasureSpec.AT_MOST: //如果测里模式是最大取值为size,我们将大小取最大值,你也可以取其他值
            case MeasureSpec.EXACTLY: {//如果是固定的大小,那就不要去改变它
                mySize = size;
                break;
            }
        }
        return mySize;
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        float mW = getMeasuredWidth();
        float mH = getMeasuredHeight();

        if (mW < mH) {
            mH = mW;
        } else {
            mW = mH;
        }
        //----mCx-230.0---mCy-230.0---mR-172.5
        mCx = mW / 2;
        mCy = mH / 2;
        //mCx和mCy中的较小者
        mR = Math.min(mCx, mCy) / 4 * 3;

        mR1 = mW/7*3;
        mR2=mR1-5;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.rotate(23, mCx, mCy);
//        canvas.rotate(-45, mCx, mCy);
        canvas.drawColor(bgColor);
        mPaint.setColor(Color.parseColor("#e3682f"));
        float d1 = (float) (2 * mR1 * Math.sin(Math.toRadians(DEGREES_UNIT / 2)));
        float c1 = mCy - mR1;
        float y1 = (d1 * d1 + mCy * mCy - c1 * c1 - mR1 * mR1) / (2 * (mCy - c1));
        float x1 = (float) (mCx + Math.sqrt(-1 * c1 * c1 + 2 * c1 * y1 + d1 * d1 - y1 * y1));
        for (int i = 0; i < 8; i++) {
            canvas.save();
            canvas.rotate(DEGREES_UNIT * i, mCx, mCy);
            canvas.drawLine(mCx, c1, x1, y1, mPaint);
            canvas.restore();
        }

        mPaint.setColor(bgColor);
        float d2 = (float) (2 * mR2 * Math.sin(Math.toRadians(DEGREES_UNIT / 2)));
        float c2 = mCy - mR2;
        float y2 = (d2 * d2 + mCy * mCy - c2 * c2 - mR2 * mR2) / (2 * (mCy - c2));
        float x2 = (float) (mCx + Math.sqrt(-1 * c2 * c2 + 2 * c2 * y2 + d2 * d2 - y2 * y2));
        for (int i = 0; i < 8; i++) {
            canvas.save();
            canvas.rotate(DEGREES_UNIT * i, mCx, mCy);
            // canvas.drawLine(mCx, mCy, mCx, c, mPaint);//中间的连接线
            canvas.drawLine(mCx, c2, x2, y2, mPaint);
            canvas.restore();
        }
        //离屏绘制
        int layer1 = canvas.saveLayer(0, 0, width, height, mPaint);
        int layer2 = canvas.saveLayer(0, 0, width, height, bgPaint);
        int layer3 = canvas.saveLayer(0, 0, width, height, roundPaint);

        mPaint.setColor(Color.parseColor("#e59f3a"));
        float d = (float) (2 * mR * Math.sin(Math.toRadians(DEGREES_UNIT / 2)));
        float c = mCy - mR;
        float y = (d * d + mCy * mCy - c * c - mR * mR) / (2 * (mCy - c));
        float x = (float) (mCx + Math.sqrt(-1 * c * c + 2 * c * y + d * d - y * y));
        for (int i = 0; i < 8; i++) {
            canvas.save();
            canvas.rotate(DEGREES_UNIT * i, mCx, mCy);
            canvas.drawLine(mCx, c, x, y, mPaint);
            canvas.restore();
        }
        if (gradient==null){
            gradient =new RadialGradient(mCx,mCy, mCx/5,
                    colors,null, Shader.TileMode.MIRROR);
        }
        bgPaint.setShader(gradient);
        /**
         * left--矩形左侧的X坐标
         * top--矩形顶部的Y坐标
         * right--矩形右侧的X坐标
         * bottom--矩形底部的Y坐标
         */
        if (rectF==null){
            rectF = new RectF(0, 0, width, height);
        }
        bgPaint.setXfermode(mode);
        canvas.drawArc(rectF, 67, indexCircle, true, bgPaint);//底部圆
        //最后将画笔去除Xfermode
        bgPaint.setXfermode(null);

        //绘制刻度线
        canvas.translate(width / 2, height / 2);
        roundPaint.setXfermode(mode);
        roundPaint.setColor(bgColor);
        //90度12根,360度48根 270度36  //90度8根,360度30根
        int index=indexCircle*46/360;
        for (int i = 0; i < index; i++) {//共48等分,根据绘制的角度更改
            canvas.save();//画布保存
            int degress=i * 8+67;
            if (degress>360){
                degress=degress-360;
            }
            canvas.rotate(degress);//绘制图标的旋转360 + i * 36
//            int alpha = (int) ((i / 60f * 255 + circleAlpha) % 255);
//            mPaint.setAlpha(alpha);//设置画笔的透明度[0-255],0是完全透明,255是完全不透明
            canvas.translate(width/2-mCircleWidth, 0);//绘图坐标的平移。
            canvas.drawLine(0, 0, mCircleWidth, 0, roundPaint);//绘制线.drawLine,drawLines绘制多条线
            canvas.restore();//合并保存后的图层
        }
        //最后将画笔去除Xfermode
        roundPaint.setXfermode(null);

        //恢复图层
        canvas.restoreToCount(layer1);
        canvas.restoreToCount(layer2);
        canvas.restoreToCount(layer3);
    }
    private  RadialGradient gradient;
    private  RectF rectF;
    private PorterDuffXfermode mode=new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP);

    private int mCircleWidth = 120;//圆弧的长度
    private int indexCircle=0;
    private int bgColor=Color.BLACK;

    public void setBgColor(int BgColor){
        bgColor=BgColor;
    }

    public void setAngle(int mStepNum) {
        mStepNum=360-mStepNum;
        if (mStepNum > 360) {
            mStepNum = 360;
        }
        if (mStepNum < 0) {
            mStepNum = 0;
        }
        this.indexCircle = mStepNum;
        invalidate();
    }
}
相关推荐
幻雨様4 小时前
UE5多人MOBA+GAS 45、制作冲刺技能
android·ue5
Jerry说前后端6 小时前
Android 数据可视化开发:从技术选型到性能优化
android·信息可视化·性能优化
Meteors.6 小时前
Android约束布局(ConstraintLayout)常用属性
android
alexhilton7 小时前
玩转Shader之学会如何变形画布
android·kotlin·android jetpack
whysqwhw11 小时前
安卓图片性能优化技巧
android
风往哪边走11 小时前
自定义底部筛选弹框
android
Yyyy48212 小时前
MyCAT基础概念
android
Android轮子哥12 小时前
尝试解决 Android 适配最后一公里
android
雨白13 小时前
OkHttp 源码解析:enqueue 非同步流程与 Dispatcher 调度
android
风往哪边走14 小时前
自定义仿日历组件弹框
android