zoukankan      html  css  js  c++  java
  • Android 圆弧形进度条 自定义View

    前段时间一个项目需要做类似360扫描 圆弧形进度条

    闲言碎语不要将-->

    1.首先重写View 在XML layout中应用,我们需要在Value 文件夹下新建attrs.xml

    在attrs.xml 里定义我们所需要的属性,然后就可以像Android自带的各种控件一

    样在布局文件中一一引用。

    attrs.xml

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
    
        <declare-styleable name="CircleProgressBar">  
            <attr name="circleColor" format="color"/>
            <attr name="circleProgressColor" format="color"/>
            <attr name="circleWidth" format="dimension"></attr>
            <attr name="textColor" format="color" />  
            <attr name="textSize" format="dimension" /> 
            <attr name="max" format="integer"></attr> 
            <attr name="textIsDisplayable" format="boolean"></attr>
            <attr name="style">
                <enum name="STROKE" value="0"></enum>
                <enum name="FILL" value="1"></enum>
            </attr>
        </declare-styleable> 
    
    </resources>

    2.接着新建一个类CircleProgressBar extends View

    我们需要在CircleProgressBar 的构造方法中获取 自己定义的属性。

    TypedArray mTypedArray = context.obtainStyledAttributes(attrs,
    R.styleable.CircleProgressBar);

    先获取到TypedArray ,然后在通过TypedArray 获取到定义的各个属性。

    circleColor = mTypedArray.getColor(R.styleable.CircleProgressBar_circleColor, 0xff47d8af);

    mTypedArray.getColor() ,方法里的第一个参数是我们在attrs.xml 中定义的值,第二个参数是默认获取不到时的默认值(即我们没在布局文件中设置CircleProgressBar 的Color属性)

    TypedArray mTypedArray = context.obtainStyledAttributes(attrs,
                    R.styleable.CircleProgressBar);
            
            //获取自定义属性和默认值
            circleColor = mTypedArray.getColor(R.styleable.CircleProgressBar_circleColor, 0xff47d8af);
            circleProgressColor = mTypedArray.getColor(R.styleable.CircleProgressBar_circleProgressColor, Color.WHITE);
            textColor = mTypedArray.getColor(R.styleable.CircleProgressBar_textColor, Color.WHITE);
            textSize = mTypedArray.getDimension(R.styleable.CircleProgressBar_textSize, 40);
            roundWidth = mTypedArray.getDimension(R.styleable.CircleProgressBar_circleWidth, 3);
            max = mTypedArray.getInteger(R.styleable.CircleProgressBar_max, 100);
            textIsDisplayable = mTypedArray.getBoolean(R.styleable.CircleProgressBar_textIsDisplayable, true);
            style = mTypedArray.getInt(R.styleable.CircleProgressBar_style, 0);
            
            mTypedArray.recycle();

    3.下面是CircleProgressBar 的全部代码

    import android.content.Context;
    import android.content.res.TypedArray;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.PaintFlagsDrawFilter;
    import android.graphics.RectF;
    import android.graphics.Typeface;
    import android.util.AttributeSet;
    import android.view.View;
    
    public class CircleProgressBar extends View {
    
        private Paint paint;
        private int circleColor;
        private int circleProgressColor;
        private int textColor;
        private float textSize;
        private float roundWidth;
        private int max;
        private int progress;
        private boolean textIsDisplayable;
        private int style;
        public static final int STROKE = 0;
        public static final int FILL = 1;
        
        public CircleProgressBar(Context context) {
            this(context, null);
        }
    
        public CircleProgressBar(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
        
        public CircleProgressBar(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            
            paint = new Paint();
            TypedArray mTypedArray = context.obtainStyledAttributes(attrs,
                    R.styleable.CircleProgressBar);
            
            //获取自定义属性和默认值
            circleColor = mTypedArray.getColor(R.styleable.CircleProgressBar_circleColor, 0xff47d8af);
            circleProgressColor = mTypedArray.getColor(R.styleable.CircleProgressBar_circleProgressColor, Color.WHITE);
            textColor = mTypedArray.getColor(R.styleable.CircleProgressBar_textColor, Color.WHITE);
            textSize = mTypedArray.getDimension(R.styleable.CircleProgressBar_textSize, 40);
            roundWidth = mTypedArray.getDimension(R.styleable.CircleProgressBar_circleWidth, 3);
            max = mTypedArray.getInteger(R.styleable.CircleProgressBar_max, 100);
            textIsDisplayable = mTypedArray.getBoolean(R.styleable.CircleProgressBar_textIsDisplayable, true);
            style = mTypedArray.getInt(R.styleable.CircleProgressBar_style, 0);
            
            mTypedArray.recycle();
        }
        
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            
            /**
             * 画最外层的大圆环
             */
            int centre = getWidth()/2; //获取圆心的x坐标
            int radius = (int) (centre - roundWidth/2); //圆环的半径
            paint.setColor(circleColor); //设置圆环的颜色
            paint.setStyle(Paint.Style.STROKE); //设置空心
            paint.setStrokeWidth(roundWidth); //设置圆环的宽度
            paint.setAntiAlias(true);  //消除锯齿 
            canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG)); 
            canvas.drawCircle(centre, centre, radius, paint); //画出圆环
            
            
            /**
             * 画进度百分比
             */
            paint.setStrokeWidth(0); 
            paint.setColor(textColor);
            paint.setTextSize(textSize);
            paint.setTypeface(Typeface.DEFAULT_BOLD); //设置字体
            
            int percent = (int)(((float)progress / (float)max) * 100);  //中间的进度百分比,先转换成float在进行除法运算,不然都为0
            float textWidth = paint.measureText(percent + "%");   //测量字体宽度,我们需要根据字体的宽度设置在圆环中间
            
            if(textIsDisplayable && percent != 0 && style == STROKE){
                canvas.drawText(percent + "%", centre - textWidth / 2, centre + textSize/2, paint); //画出进度百分比
            }
            
            
            /**
             * 画圆弧 ,画圆环的进度
             */
            
            //设置进度是实心还是空心
            radius = (int) (centre - roundWidth*2);
            paint.setStrokeWidth(roundWidth*2); //设置圆环的宽度
            paint.setColor(circleProgressColor);  //设置进度的颜色
            RectF oval = new RectF(centre - radius, centre - radius, centre
                    + radius, centre + radius);  //用于定义的圆弧的形状和大小的界限
            
            switch (style) {
            case STROKE:{
                paint.setStyle(Paint.Style.STROKE);
                canvas.drawArc(oval, 0, 360 * progress / max, false, paint);  //根据进度画圆弧
                break;
            }
            case FILL:{
                paint.setStyle(Paint.Style.FILL_AND_STROKE);
                if(progress !=0)
                    canvas.drawArc(oval, 0, 360 * progress / max, true, paint);  //根据进度画圆弧
                break;
            }
            }
            
        }
        
        
        public synchronized int getMax() {
            return max;
        }
    
        /**
         * 设置进度的最大值
         * @param max
         */
        public synchronized void setMax(int max) {
            if(max < 0){
                throw new IllegalArgumentException("max not less than 0");
            }
            this.max = max;
        }
    
        /**
         * 获取进度.需要同步
         * @return
         */
        public synchronized int getProgress() {
            return progress;
        }
    
        /**
         * 设置进度,此为线程安全控件,由于考虑多线的问题,需要同步
         * 刷新界面调用postInvalidate()能在非UI线程刷新
         * @param progress
         */
        public synchronized void setProgress(int progress) {
            if(progress < 0){
                throw new IllegalArgumentException("progress not less than 0");
            }
            if(progress > max){
                progress = max;
            }
            if(progress <= max){
                this.progress = progress;
                postInvalidate();
            }
            
        }
        
        
        public int getCricleColor() {
            return circleColor;
        }
    
        public void setCricleColor(int cricleColor) {
            this.circleColor = cricleColor;
        }
    
        public int getCricleProgressColor() {
            return circleProgressColor;
        }
    
        public void setCricleProgressColor(int cricleProgressColor) {
            this.circleProgressColor = cricleProgressColor;
        }
    
        public int getTextColor() {
            return textColor;
        }
    
        public void setTextColor(int textColor) {
            this.textColor = textColor;
        }
    
        public float getTextSize() {
            return textSize;
        }
    
        public void setTextSize(float textSize) {
            this.textSize = textSize;
        }
    
        public float getRoundWidth() {
            return roundWidth;
        }
    
        public void setRoundWidth(float roundWidth) {
            this.roundWidth = roundWidth;
        }
    
    
    
    }

    4.最后说一下在布局文件中的使用

    需要在.xml 布局文件的最外面一层加上

    xmlns:android_custom="http://schemas.android.com/apk/res/com.example.circleprogress"这个即命名空间

    注意:上面绿色字体部分随意写,橙色字体是工程的包名,别写错哦!

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
        xmlns:android_custom="http://schemas.android.com/apk/res/com.example.circleprogress"
        xmlns:tools="http://schemas.android.com/tools"  
        android:layout_width="match_parent"  
        android:layout_height="match_parent" >  
      
      
        <com.example.circleprogress.CircleProgressBar  
            android:id="@+id/circleProgresBar"  
            android:layout_width="80dip"  
            android:layout_height="80dip"
    
            android_custom:circleColor="#47d8af"  
            android_custom:circleProgressColor="@android:color/white"  
            android_custom:textColor="@android:color/white"  
            android_custom:textIsDisplayable="true"  
            android_custom:roundWidth="2dp"  
            android_custom:textSize="40sp"/>  
    </RelativeLayout> 

    5.付效果图一张

  • 相关阅读:
    elemen-ui表格多选,分页保持勾选状态的实现
    element-ui中的change事件传递多个参数的方法
    vue中访问不存在路由默认跳转404页面实现方法
    IntelliJ IDEA 汉化包
    vue 移动端项目用手机预览调试
    vue 中使用 rem
    vue中配置axios.js文件,发送请求
    vue中axios的使用
    爬楼梯
    不同路径
  • 原文地址:https://www.cnblogs.com/yema/p/4702211.html
Copyright © 2011-2022 走看看