• Android 高手进阶,自己定义圆形进度条


    背景介绍

    在Android 开发中,我们常常遇到各种各样绚丽的控件,所以,依靠我们Android本身所带的控件是远远不够的,许多时候须要我们自定义控件,在开发的过程中。我们公司遇到了一种须要自己写的一个自定义带进度的圆形进度条,看起来很的绚丽,当然另一些其它的。比方:水纹形的圆形进度条等效果都是很nice的。假设哪位朋友有实现,希望分享出来,我也好学习学习。

    好了多的不说。接下来,我们就来看看来怎样实现圆形进度条。

    原文地址:http://blog.csdn.net/xiaanming/article/details/10298163


    一:先上效果图

                                


    二:实例代码

    1.自己定义属性

    <span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?>
    <resources>
    
        <declare-styleable name="RoundProgressBar">
            <attr name="roundColor" format="color" />
            <attr name="roundProgressColor" format="color" />
            <attr name="roundWidth" 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></span>

    ps:自己定义属性呢。事实上大家也许不是非常明确,有些小伙伴们也许知道,我这样用。能够调用它的一个值。能够获取值,或者说赋予值。比方:你用Android 系统本身所带的控件,textview其它等,你知道他有height。width,textsize,textcolor等,这些属性。你能赋值。可是有去理解过如何去获取值么。假设不了解,没关系,我这有一篇鸿洋写的比較具体。推荐给你:http://blog.csdn.net/lmj623565791/article/details/45022631,还在等什么。赶紧戳进去,带你装逼带你飞。


    2.自己定义控件

    源代码1:

    <span style="font-size:14px;">package com.example.testdemo.view;
    
    import android.annotation.SuppressLint;
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.RectF;
    import android.graphics.Typeface;
    import android.util.AttributeSet;
    import android.view.View;
    
    import com.example.testdemo.R;
    
    /**
     * 仿iphone带进度的进度条。线程安全的View,可直接在线程中更新进度
     * 
     * @author zengtao 2015年5月12日下午7:43:32
     *
     *
     */
    @SuppressLint("DrawAllocation")
    public class RoundProgressBar extends View {
    	/**
    	 * 画笔对象的引用
    	 */
    	private Paint paint;
    
    	/**
    	 * 圆环的颜色
    	 */
    	private int roundColor;
    
    	/**
    	 * 圆环进度的颜色
    	 */
    	private int roundProgressColor;
    
    	/**
    	 * 中间进度百分比的字符串的颜色
    	 */
    	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 RoundProgressBar(Context context) {
    		this(context, null);
    	}
    
    	public RoundProgressBar(Context context, AttributeSet attrs) {
    		this(context, attrs, 0);
    	}
    
    	public RoundProgressBar(Context context, AttributeSet attrs, int defStyle) {
    		super(context, attrs, defStyle);
    
    		paint = new Paint();
    
    		TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundProgressBar);
    
    		// 获取自己定义属性和默认值
    		roundColor = mTypedArray.getColor(R.styleable.RoundProgressBar_roundColor, Color.rgb(228, 232, 237));
    		roundProgressColor = mTypedArray.getColor(R.styleable.RoundProgressBar_roundProgressColor, Color.rgb(216, 6, 7));
    		textColor = mTypedArray.getColor(R.styleable.RoundProgressBar_textColor, Color.rgb(216, 6, 7));
    		textSize = mTypedArray.getDimension(R.styleable.RoundProgressBar_textSize, 18);
    		roundWidth = mTypedArray.getDimension(R.styleable.RoundProgressBar_roundWidth, 3);
    		max = mTypedArray.getInteger(R.styleable.RoundProgressBar_max, 100);
    		textIsDisplayable = mTypedArray.getBoolean(R.styleable.RoundProgressBar_textIsDisplayable, true);
    		style = mTypedArray.getInt(R.styleable.RoundProgressBar_style, 0);
    
    		mTypedArray.recycle();
    	}
    
    	@Override
    	protected void onDraw(Canvas canvas) {
    		super.onDraw(canvas);
    
    		/**
    		 * 1.画最外层的大圆环
    		 */
    		int centre = getWidth() / 2; // 获取圆心的x坐标
    		int radius = (int) (centre - roundWidth / 2); // 圆环的半径
    		paint.setColor(roundColor); // 设置圆环的颜色
    		paint.setStyle(Paint.Style.STROKE); // 设置空心
    		paint.setStrokeWidth(roundWidth); // 设置圆环的宽度
    		paint.setAntiAlias(true); // 消除锯齿
    		canvas.drawCircle(centre, centre, radius, paint); // 画出圆环
    
    		/**
    		 * 2.画进度百分比
    		 */
    		paint.setStrokeWidth(0);
    		paint.setColor(textColor);
    		paint.setTextSize(textSize);
    		paint.setTypeface(Typeface.DEFAULT); // 设置字体
    		// 中间的进度百分比,先转换成float在进行除法运算,不然都为0
    		int percent = (int) (((float) progress / (float) max) * 100);
    
    		float textWidth = paint.measureText(percent + "%"); // 測量字体宽度,我们须要依据字体的宽度设置在圆环中间
    
    		if (textIsDisplayable && style == STROKE) {
    			 canvas.drawText(percent + "%", centre - textWidth / 2, centre + textSize/2, paint); //画出进度百分比  
    		}
    
    		/**
    		 * 3.画圆弧 。画圆环的进度
    		 */
    
    		// 设置进度是实心还是空心
    		paint.setStrokeWidth(roundWidth); // 设置圆环的宽度
    		paint.setColor(roundProgressColor); // 设置进度的颜色
    		RectF oval = new RectF(centre - radius, centre - radius, centre + radius, centre + radius); // 用于定义的圆弧的形状和大小的界限
    
    		switch (style) {
    		case STROKE: {
    			paint.setStyle(Paint.Style.STROKE);
    			canvas.drawArc(oval, -90, 360 * progress / max, false, paint); // 依据进度画圆弧
    			break;
    		}
    		case FILL: {
    			paint.setStyle(Paint.Style.FILL_AND_STROKE);
    			if (progress != 0)
    				canvas.drawArc(oval, -90, 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 roundColor;
    	}
    
    	public void setCricleColor(int cricleColor) {
    		this.roundColor = cricleColor;
    	}
    
    	public int getCricleProgressColor() {
    		return roundProgressColor;
    	}
    
    	public void setCricleProgressColor(int cricleProgressColor) {
    		this.roundProgressColor = 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;
    	}
    
    	public int getStyle() {
    		return style;
    	}
    	
    	public void setStyle(int style) {
    		this.style = style;
    	}
    }
    </span>

    源代码2:

    <span style="font-size:14px;">package com.example.testdemo.view;
    
    import android.annotation.SuppressLint;
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.RectF;
    import android.graphics.Typeface;
    import android.util.AttributeSet;
    import android.view.View;
    
    import com.example.testdemo.R;
    
    /**
     * 仿iphone带进度的进度条,线程安全的View,可直接在线程中更新进度
     * 
     * @author zengtao 2015年5月12日下午7:43:32
     *
     *
     */
    @SuppressLint("DrawAllocation")
    public class RoundProgressBar2 extends View {
    	/**
    	 * 画笔对象的引用
    	 */
    	private Paint paint;
    
    	/**
    	 * 圆环的颜色
    	 */
    	private int roundColor;
    
    	/**
    	 * 圆环进度的颜色
    	 */
    	private int roundProgressColor;
    
    	/**
    	 * 中间进度百分比的字符串的颜色
    	 */
    	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 RoundProgressBar2(Context context) {
    		this(context, null);
    	}
    
    	public RoundProgressBar2(Context context, AttributeSet attrs) {
    		this(context, attrs, 0);
    	}
    
    	public RoundProgressBar2(Context context, AttributeSet attrs, int defStyle) {
    		super(context, attrs, defStyle);
    
    		paint = new Paint();
    
    		TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundProgressBar);
    
    		// 获取自己定义属性和默认值
    		roundColor = mTypedArray.getColor(R.styleable.RoundProgressBar_roundColor, Color.rgb(228, 232, 237));
    		roundProgressColor = mTypedArray.getColor(R.styleable.RoundProgressBar_roundProgressColor, Color.rgb(216, 6, 7));
    		textColor = mTypedArray.getColor(R.styleable.RoundProgressBar_textColor, Color.rgb(216, 6, 7));
    		textSize = mTypedArray.getDimension(R.styleable.RoundProgressBar_textSize, 18);
    		roundWidth = mTypedArray.getDimension(R.styleable.RoundProgressBar_roundWidth, 3);
    		max = mTypedArray.getInteger(R.styleable.RoundProgressBar_max, 100);
    		textIsDisplayable = mTypedArray.getBoolean(R.styleable.RoundProgressBar_textIsDisplayable, true);
    		style = mTypedArray.getInt(R.styleable.RoundProgressBar_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(roundColor); // 设置圆环的颜色
    		paint.setStyle(Paint.Style.STROKE); // 设置空心
    		paint.setStrokeWidth(roundWidth); // 设置圆环的宽度
    		paint.setAntiAlias(true); // 消除锯齿
    		canvas.drawCircle(centre, centre, radius, paint); // 画出圆环
    
    		/**
    		 * 画进度百分比
    		 */
    		paint.setStrokeWidth(0);
    		paint.setColor(textColor);
    		paint.setTextSize(textSize);
    		paint.setTypeface(Typeface.DEFAULT); // 设置字体
    		// int percent = (int) (((float) progress / (float) max) * 100); //
    		// 中间的进度百分比,先转换成float在进行除法运算,不然都为0
    
    		float textWidth = paint.measureText("抢"); // 測量字体宽度。我们须要依据字体的宽度设置在圆环中间
    
    		if (textIsDisplayable && style == STROKE) {
    			canvas.drawText("抢", centre - textWidth / 2, centre + textSize / 2 - 4, paint); // 画出进度百分比
    		}
    
    		/**
    		 * 画圆弧 ,画圆环的进度
    		 */
    
    		// 设置进度是实心还是空心
    		paint.setStrokeWidth(roundWidth); // 设置圆环的宽度
    		paint.setColor(roundProgressColor); // 设置进度的颜色
    		RectF oval = new RectF(centre - radius, centre - radius, centre + radius, centre + radius); // 用于定义的圆弧的形状和大小的界限
    
    		switch (style) {
    		case STROKE: {
    			paint.setStyle(Paint.Style.STROKE);
    			canvas.drawArc(oval, -90, 360 * progress / max, false, paint); // 依据进度画圆弧
    			break;
    		}
    		case FILL: {
    			paint.setStyle(Paint.Style.FILL_AND_STROKE);
    			if (progress != 0)
    				canvas.drawArc(oval, -90, 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 roundColor;
    	}
    
    	public void setCricleColor(int cricleColor) {
    		this.roundColor = cricleColor;
    	}
    
    	public int getCricleProgressColor() {
    		return roundProgressColor;
    	}
    
    	public void setCricleProgressColor(int cricleProgressColor) {
    		this.roundProgressColor = 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;
    	}
    
    }
    </span>


    ps:以上两份自己定义源代码。事实上你细致看。区别不是非常大,就改变了一个地方,这个更改的地方,事实上是在我们如今的项目中所遇到的,所以,发不这个圆形控件,我想你以后会用到的,值得收藏。

    三.详细调用

    <span style="font-size:14px;">package com.example.testdemo;
    
    import android.annotation.SuppressLint;
    import android.app.Activity;
    import android.graphics.Color;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Message;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    
    import com.example.testdemo.view.RoundProgressBar;
    import com.example.testdemo.view.RoundProgressBar2;
    
    /**
     * 主界面
     * @author zengtao 2015年6月10日 下午4:02:13
     *
     */
    public class MainActivity extends Activity {
    	private RoundProgressBar2 r3;
    	private RoundProgressBar r1, r2, r4, r5;
    	private int pro1 = 80; // 想要显示的进度值:如项目中。从server返回的数据
    	private int progress = 0;
    	private boolean flag = false;
    	private MyThread thread1;
    	private MyThread2 thread2;
    	private Button start;
    
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.activity_main);
    
    		initView();
    		setRoundAttribute(); // 可设置可不设置
    	}
    
    	/**
    	 * 開始方法
    	 */
    	private void start() {
    		// 线程1
    		thread1 = new MyThread();
    		thread1.start();
    
    		// 线程2
    		thread2 = new MyThread2();
    		thread2.start();
    	}
    
    	/**
    	 * 初始化控件
    	 */
    	private void initView() {
    		r1 = (RoundProgressBar) findViewById(R.id.prpgress1);
    		r2 = (RoundProgressBar) findViewById(R.id.prpgress2);
    		r3 = (RoundProgressBar2) findViewById(R.id.prpgress3);
    		r4 = (RoundProgressBar) findViewById(R.id.prpgress4);
    		r5 = (RoundProgressBar) findViewById(R.id.prpgress5);
    
    		start = (Button) findViewById(R.id.start);
    		start.setOnClickListener(listener);
    	}
    
    	/**
    	 * 设置圆的属性
    	 */
    	private void setRoundAttribute() {
    		r1.setRoundWidth(10);
    		r1.setTextColor(Color.parseColor("#00ff00"));
    		r1.setCricleColor(Color.parseColor("#ff0000"));
    
    		r2.setRoundWidth(20);
    		r2.setTextColor(Color.parseColor("#0000ff"));
    		r2.setCricleColor(Color.parseColor("#ff00ff"));
    
    		r4.setRoundWidth(20);
    		r4.setTextColor(Color.parseColor("#ff00ff"));
    		r4.setCricleColor(Color.parseColor("#ff0000"));
    		r4.setStyle(0);
    
    		r4.setRoundWidth(20);
    		r4.setTextColor(Color.parseColor("#000000"));
    		r4.setCricleColor(Color.parseColor("#ffff00"));
    		r4.setStyle(1);
    	}
    
    	/**
    	 * 点击事件
    	 */
    	OnClickListener listener = new OnClickListener() {
    
    		@Override
    		public void onClick(View v) {
    			if (v == start) {
    				start();
    			}
    		}
    	};
    
    	/**
    	 * 用于更新ui
    	 */
    	@SuppressLint("HandlerLeak")
    	private Handler mHandler = new Handler() {
    		public void handleMessage(android.os.Message msg) {
    			final int x = msg.what;
    			final int temp = (int) msg.obj;
    			if (x == 0 * 1) {
    				if (pro1 - temp > 0) {
    					r1.setProgress(temp);
    					r2.setProgress(temp);
    					r3.setProgress(temp);
    					r4.setProgress(temp);
    					r5.setProgress(temp);
    				} else {
    					r1.setProgress(pro1);
    					r2.setProgress(pro1);
    					r3.setProgress(pro1);
    					r4.setProgress(pro1);
    					r5.setProgress(pro1);
    					thread1.stopThread();
    				}
    			} else if (x == 0 * 2) {
    				if (pro1 - temp > 0) {
    					r1.setProgress(temp);
    					r2.setProgress(temp);
    					r3.setProgress(temp);
    					r4.setProgress(temp);
    					r5.setProgress(temp);
    				} else {
    					r1.setProgress(pro1);
    					r2.setProgress(pro1);
    					r3.setProgress(pro1);
    					r4.setProgress(pro1);
    					r5.setProgress(pro1);
    					thread2.stopThread();
    				}
    			}
    		};
    	};
    
    	/**
    	 * 线程,控制进度动画
    	 * @author zengtao 2015年6月10日 下午4:31:11
    	 *
    	 */
    	class MyThread extends Thread {
    
    		@Override
    		public void run() {
    			while (!flag) {
    				try {
    					progress += 1;
    					Message msg = new Message();
    					msg.what = 0 * 1;
    					msg.obj = progress;
    					Thread.sleep(100);
    					mHandler.sendMessage(msg);
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    			}
    		}
    
    		public void stopThread() {
    			flag = true;
    		}
    	}
    
    	/**
    	 * 线程。控制进度动画
    	 * @author zengtao 2015年6月10日 下午4:31:11
    	 *
    	 */
    	class MyThread2 extends Thread {
    
    		@Override
    		public void run() {
    			while (!flag) {
    				try {
    					progress += 2;
    					Message msg = new Message();
    					msg.what = 0 * 2;
    					msg.obj = progress;
    					Thread.sleep(200);
    					mHandler.sendMessage(msg);
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    			}
    		}
    
    		public void stopThread() {
    			flag = true;
    		}
    	}
    
    	@Override
    	protected void onDestroy() {
    		super.onDestroy();
    		if (thread1 != null) {
    			thread1.stopThread();
    		}
    		if (thread2 != null) {
    			thread2.stopThread();
    		}
    	}
    }
    </span>


    四.总结

    实现以上步骤,就实现了一个安全可靠的自己定义控件的实现。看起来简简单单,不说分分钟,可是略微花点时间这就是你的。






  • 相关阅读:
    22-Camping野营-露营
    node留言板
    js中const,var,let区别
    app消息推送
    Vue + Mui
    七牛云图片存储---Java
    springboot---发送邮件
    SSM简易版
    Hibernate---快速入门
    Vue---mock.js 使用
  • 原文地址:https://www.cnblogs.com/bhlsheji/p/5179474.html
Copyright © 2020-2023  润新知