可拖动的圆形进度条

效果图如下:



1,通过继承View,重写onDraw(Canvas canvas)方法,实现界面进度显示

2,重写onTouchEvent(MotionEvent event)方法,监听拖动事件

3,在监听位置改变时,计算角度,重新调用onDraw()方法进行绘制


关键代码如下:

<span style="font-size:18px;">public class MusicProgressBar extends View {
	/**
	 * 画笔对象的引用
	 */
	private Paint paint;

	/**
	 * 圆环的颜色
	 */
	private int roundColor;

	/**
	 * 圆环进度的颜色
	 */
	private int roundProgressColor;

	/**
	 * 圆环的宽度
	 */
	private float roundWidth;

	/**
	 * 最大进度
	 */
	private int max;

	/**
	 * 当前进度
	 */
	private int progress;

	/**
	 * 中间进度百分比的字符串的颜色
	 */
	private int textColor;

	/**
	 * 中间进度百分比的字符串的字体
	 */
	private float textSize;

	/**
	 * 点的半径
	 */
	private float pointRadius;
	
	/**
	 * 空心点的宽度
	 */
	private float pointWidth;
	
    private Drawable mThumb, mThumbPress;

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

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

	public MusicProgressBar(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.RED);
		roundProgressColor = mTypedArray.getColor(R.styleable.RoundProgressBar_roundProgressColor, Color.GREEN);
		roundWidth = mTypedArray.getDimension(R.styleable.RoundProgressBar_roundWidth, 3);
		textColor = mTypedArray.getColor(R.styleable.RoundProgressBar_textColor, Color.GREEN);  
        textSize = mTypedArray.getDimension(R.styleable.RoundProgressBar_textSize, 15);  
		max = mTypedArray.getInteger(R.styleable.RoundProgressBar_imageMax, 100);
		
		pointRadius = mTypedArray.getDimension(R.styleable.RoundProgressBar_pointRadius, 3);  
		pointWidth = mTypedArray.getDimension(R.styleable.RoundProgressBar_pointWidth, 2);  

		mTypedArray.recycle();
		
		// 加载拖动图标
        mThumb = getResources().getDrawable(R.drawable.btn_lamp_plate_nor);// 圆点图片
        int thumbHalfheight = mThumb.getIntrinsicHeight() / 2;
        int thumbHalfWidth = mThumb.getIntrinsicWidth() / 2;
        mThumb.setBounds(-thumbHalfWidth, -thumbHalfheight, thumbHalfWidth, thumbHalfheight);
        
        mThumbPress = getResources().getDrawable(R.drawable.btn_lamp_plate_down);// 圆点图片
        thumbHalfheight = mThumbPress.getIntrinsicHeight() / 2;
        thumbHalfWidth = mThumbPress.getIntrinsicWidth() / 2;
        mThumbPress.setBounds(-thumbHalfWidth, -thumbHalfheight, thumbHalfWidth, thumbHalfheight);
        paddingOuterThumb = thumbHalfheight;
	}

	@Override
	public void onDraw(Canvas canvas) {
		/**
		 * 画最外层的大圆环
		 */
		paint.setColor(roundColor); //设置圆环的颜色
		paint.setStyle(Paint.Style.STROKE); //设置空心
		paint.setStrokeWidth(roundWidth); //设置圆环的宽度
		paint.setAntiAlias(true);  //消除锯齿 
		canvas.drawCircle(centerX, centerY, radius, paint); //画出圆环

		/**
		 * 画文字
		 */
		paint.setStrokeWidth(0);   
        paint.setColor(textColor);  
        paint.setTextSize(textSize);  
        // paint.setTypeface(Typeface.DEFAULT); //设置字体  
        String textTime = getTimeText(progress);
        float textWidth = paint.measureText(textTime);   //测量字体宽度,我们需要根据字体的宽度设置在圆环中间  
          
        canvas.drawText(textTime, centerX - textWidth / 2, centerY + textSize/2, paint);

		/**
		 * 画圆弧 ,画圆环的进度
		 */
		paint.setStrokeWidth(roundWidth); //设置圆环的宽度
		paint.setColor(roundProgressColor);  //设置进度的颜色
		RectF oval = new RectF(centerX - radius, centerY - radius, centerX + radius, centerY + radius);  //用于定义的圆弧的形状和大小的界限

		paint.setStyle(Paint.Style.STROKE);
		canvas.drawArc(oval, 270, 360 * progress / max, false, paint);  //根据进度画圆弧
		
		// 画圆上的两个点
		paint.setStrokeWidth(pointWidth);
		PointF startPoint = ChartUtil.calcArcEndPointXY(centerX, centerY, radius, 0, 270); 
		canvas.drawCircle(startPoint.x, startPoint.y, pointRadius, paint);
		
		//paint.setStyle(Paint.Style.FILL_AND_STROKE);
		PointF progressPoint = ChartUtil.calcArcEndPointXY(centerX, centerY, radius, 360 * progress / max, 270); 
		//canvas.drawCircle(progressPoint.x, progressPoint.y, pointRadius, paint);
		// 画Thumb
        canvas.save();
        canvas.translate(progressPoint.x, progressPoint.y);
        if (downOnArc) {
			mThumbPress.draw(canvas);
		} else {
			mThumb.draw(canvas);
		}
        canvas.restore();
	} 

	private boolean downOnArc = false;
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		int action = event.getAction();
		int x = (int) event.getX();
		int y = (int) event.getY();
		switch (action) {
		case MotionEvent.ACTION_DOWN:
			if (isTouchArc(x, y)) {
				downOnArc = true;
				updateArc(x, y);
				return true;
			}
			break;
		case MotionEvent.ACTION_MOVE:
			if (downOnArc) {
				updateArc(x, y);
				return true;
			}
			break;
		case MotionEvent.ACTION_UP:
			downOnArc = false;
			invalidate();
			if (changeListener != null) {
				changeListener.onProgressChangeEnd(max, progress);
			}
			break;
		}
		return super.onTouchEvent(event);
	}
	
	 private int centerX, centerY;
	 private int radius;
	 private int paddingOuterThumb;
	
	@Override
	protected void onSizeChanged(int width, int height, int oldw, int oldh) {
		centerX = width / 2;
        centerY = height / 2;
        int minCenter = Math.min(centerX, centerY);
        
		radius = (int) (minCenter - roundWidth/2 - paddingOuterThumb); //圆环的半径
		minValidateTouchArcRadius = (int) (radius - paddingOuterThumb*1.5f);
		maxValidateTouchArcRadius = (int) (radius + paddingOuterThumb*1.5f);
		super.onSizeChanged(width, height, oldw, oldh);
	}

	// 根据点的位置,更新进度
	private void updateArc(int x, int y) {
		int cx = x - getWidth() / 2;
	    int cy = y - getHeight() / 2;
	    // 计算角度,得出(-1->1)之间的数据,等同于(-180°->180°)
	    double angle = Math.atan2(cy, cx)/Math.PI;
	    // 将角度转换成(0->2)之间的值,然后加上90°的偏移量
	    angle = ((2 + angle)%2 + (90/180f))%2;
	    // 用(0->2)之间的角度值乘以总进度,等于当前进度 
	    progress = (int) (angle * max/2);
	    if (changeListener != null) {
			changeListener.onProgressChange(max, progress);
		}
		invalidate();
	}

	private int minValidateTouchArcRadius; // 最小有效点击半径
	private int maxValidateTouchArcRadius; // 最大有效点击半径
	// 判断是否按在圆边上
	private boolean isTouchArc(int x, int y) {
		double d = getTouchRadius(x, y);
		if (d >= minValidateTouchArcRadius && d <= maxValidateTouchArcRadius) {
			return true;
		}
		return false;
	}
	
	// 计算某点到圆点的距离
	private double getTouchRadius(int x, int y) {
		int cx = x - getWidth() / 2;
		int cy = y - getHeight() / 2;
		return Math.hypot(cx, cy);
	}

	private String getTimeText(int progress) {
		int minute = progress / 60;
		int second = progress % 60;
		String result = (minute < 10 ? "0" : "") + minute + ":" + (second < 10 ? "0" : "") + second;
		return result;
	}

	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 float getRoundWidth() {
		return roundWidth;
	}

	public void setRoundWidth(float roundWidth) {
		this.roundWidth = roundWidth;
	}
	
	public static class ChartUtil {
	    
	    /**
	     * 依圆心坐标,半径,扇形角度,计算出扇形终射线与圆弧交叉点的xy坐标  
	     * @param cirX
	     * @param cirY
	     * @param radius
	     * @param cirAngle
	     * @return
	     */
	    public static PointF calcArcEndPointXY(float cirX, float cirY, float radius, float cirAngle){  
	    	float posX = 0.0f;  
	        float posY = 0.0f;  
	        //将角度转换为弧度        
	        float arcAngle = (float) (Math.PI * cirAngle / 180.0);  
	        if (cirAngle < 90)  
	        {  
	            posX = cirX + (float)(Math.cos(arcAngle)) * radius;  
	            posY = cirY + (float)(Math.sin(arcAngle)) * radius;  
	        }  
	        else if (cirAngle == 90)  
	        {  
	            posX = cirX;  
	            posY = cirY + radius;  
	        }  
	        else if (cirAngle > 90 && cirAngle < 180)  
	        {  
	            arcAngle = (float) (Math.PI * (180 - cirAngle) / 180.0);  
	            posX = cirX - (float)(Math.cos(arcAngle)) * radius;  
	            posY = cirY + (float)(Math.sin(arcAngle)) * radius;  
	        }  
	        else if (cirAngle == 180)  
	        {  
	            posX = cirX - radius;  
	            posY = cirY;  
	        }  
	        else if (cirAngle > 180 && cirAngle < 270)  
	        {  
	            arcAngle = (float) (Math.PI * (cirAngle - 180) / 180.0);  
	            posX = cirX - (float)(Math.cos(arcAngle)) * radius;  
	            posY = cirY - (float)(Math.sin(arcAngle)) * radius;  
	        }  
	        else if (cirAngle == 270)  
	        {  
	            posX = cirX;  
	            posY = cirY - radius;  
	        }  
	        else 
	        {  
	            arcAngle = (float) (Math.PI * (360 - cirAngle) / 180.0);  
	            posX = cirX + (float)(Math.cos(arcAngle)) * radius;  
	            posY = cirY - (float)(Math.sin(arcAngle)) * radius;  
	        }  
	        return new PointF(posX, posY);        
	    }  
	    
	    public static PointF calcArcEndPointXY(float cirX, float cirY, float radius, float cirAngle, float orginAngle){
	    	cirAngle = (orginAngle + cirAngle) % 360;
	    	return calcArcEndPointXY(cirX, cirY, radius, cirAngle);
	    }
	}
	
	private OnProgressChangeListener changeListener;

	public void setChangeListener(OnProgressChangeListener changeListener) {
		this.changeListener = changeListener;
	}

	public interface OnProgressChangeListener {
		void onProgressChange(int duration, int progress);

		void onProgressChangeEnd(int duration, int progress);
	}
}</span>


下载地址:http://download.csdn.net/detail/u010134293/9196313


  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值