码迷,mamicode.com
首页 > 其他好文 > 详细

酷炫进度条 自定义SeekBar

时间:2016-08-25 21:34:06      阅读:255      评论:0      收藏:0      [点我收藏+]

标签:


前些天一同学给了我一个ui图,是这样子的:

技术分享

需求:

1、看了ui图可以知道这类似android自带的seekbar控件,
2、一个水平进度条和一个圆形进度条;
3、圆形进度条显示环形刻度和当前进度值;
4、并且圆形进度可滑动操作;

最终实现效果:


技术分享

废话不多说上代码:

水平的进度条:HorizonalProgress.class
package com.totcy.magicprogress;

import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.DecelerateInterpolator;

/**
 * Description 酷炫水平进度条
 * Author: tu
 * Date: 2016-08-22
 * Time: 14:59
 */
public class HorizonalProgress extends View {
    private int viewWidth;//view的宽度
    private int viewHigth;//view的高度
    private Paint mPaint;//画笔  212 62 96
    private int colorSecondProgress = Color.argb(255,229,237,245);//背景圆颜色,进度条背景色
    private int colorProgress = Color.argb(255,19,146,255);//背景圆颜色,一级进度条颜色
    private int progressHeight = 30;//进度条的高度
    private RectF rectF = new RectF();
    private int curProgress = 0; //必须小于等于100 大于0
    private int oldProgress = 0;
    
    public void setColorSecondProgress(int colorSecondProgress) {
		this.colorSecondProgress = colorSecondProgress;
	}
	public void setColorProgress(int colorProgress) {
		this.colorProgress = colorProgress;
	}
	public void setProgressHeight(int progressHeight) {
		this.progressHeight = progressHeight;
	}
	public void setCurProgress(int curProgress) {
        this.curProgress = curProgress;
        invalidate();
    }
    public HorizonalProgress(Context context) {
        this(context,null);
    }

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

    public HorizonalProgress(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }
    private void init(){
        //初始化坐标画笔
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);//
        mPaint.setColor(colorSecondProgress);
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.STROKE);//空心
        curProgress = 0;
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int height;
        int width;

        //宽度测量
        if (widthMode == MeasureSpec.EXACTLY) {
            width = widthSize;
        } else {
            width = getMeasuredWidth();
        }
        viewWidth = width;
        //高度测量
        if (heightMode == MeasureSpec.EXACTLY) {
            height = heightSize;
        } else {
            height = getMeasuredHeight();
        }
        //进度条的高度根据
        viewHigth = progressHeight;

        setMeasuredDimension(width, viewHigth);
    }

    /**
     * 绘制进度
     * @param canvas
     */
    private  void drawProgress(Canvas canvas){
        rectF.left = 0;
        rectF.right = viewWidth;
        rectF.top = 0;
        rectF.bottom = viewHigth;
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setColor(colorSecondProgress);
        //灰色背景
        canvas.drawRoundRect(rectF,viewHigth/2,viewHigth/2,mPaint);

        //进度
        mPaint.setColor(colorProgress);
        rectF.right = curProgress * viewWidth / 100;
        canvas.drawRoundRect(rectF,viewHigth/2,viewHigth/2,mPaint);

    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawProgress(canvas);
    }
    public void setProgress(int progress){
        if (progress < 0 || progress > 100)
            return;
        ObjectAnimator o = ObjectAnimator.ofInt(this, "curProgress", oldProgress, progress);
        o.setDuration(1000);
        o.setInterpolator(new DecelerateInterpolator());
        o.start();
        oldProgress = progress;
    }
}

圆形进度条 CircleProgress.class
package com.totcy.magicprogress;

import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.DecelerateInterpolator;

/**
 * Description 圆形装逼进度条
 * Author: tu
 * Date: 2016-08-19
 * Time: 14:33
 */
public class CircleProgress extends View{

	private float textSize = getResources().getDimension(R.dimen.text_size_14);
    private float dotX, dotY;//圆点xy
    private int viewWidth;//view的宽度
    private int viewHigth;//view的高度
    private Paint mPaint,mPaintArc;//画笔  212 62 96
    private int colorBg = Color.argb(255,54,68,76);//背景圆颜色
    private int colorWhite = Color.argb(255,255,255,255);//文字颜色
    private int colorBlack = Color.argb(255,34,49,59);//第二刻度颜色
    private int colorBlue = Color.argb(255,94,248,249);//刻度颜色
    private int pandding = 10;
    private RectF rectF;
    private float radius = 10;//半径
    private float scaleLineLenth = 3;//刻度线长
    private int scaleAngle = 10;//刻度间隔
    private int scaleWidth = 5;//刻度宽度
    private int curProgress = 0;//0 ~ 100进度 当前进度
    private int oldProgress = 0;

	public void setColorBlue(int colorBlue) {
		this.colorBlue = colorBlue;
	}

	public void setTextSize(float textSize) {
		this.textSize = textSize;
	}

	public int getCurProgress() {
        return curProgress;
    }

    public void setCurProgress(int curProgress) {
        this.curProgress = curProgress;
        invalidate();
    }

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

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

    public CircleProgress(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    /**
     * 初始化画笔
     */
    private void init(Context context) {

        //初始化坐标画笔
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);//
        mPaintArc = new Paint(Paint.ANTI_ALIAS_FLAG);//
        mPaint.setColor(colorWhite);
        mPaintArc.setColor(colorBg);
        mPaint.setAntiAlias(true);
        mPaintArc.setAntiAlias(true);
        mPaint.setTextSize(15);
        mPaint.setStyle(Paint.Style.STROKE);//空心
        //当前进度

    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int height;
        int width;

        //宽度测量
        if (widthMode == MeasureSpec.EXACTLY) {
            width = widthSize;
        } else {
            width = getMeasuredWidth();
        }
        dotX = width / 2;
        viewWidth = width;
        //高度测量
        if (heightMode == MeasureSpec.EXACTLY) {
            height = heightSize;
        } else {
            height = getMeasuredHeight();
        }
        viewHigth = height;
        dotY = height / 2;
        radius = dotX-(getPaddingLeft() + getPaddingRight())/2;
        scaleLineLenth = radius/3;
        rectF = new RectF(dotX - radius, dotY - radius, dotX + radius, dotY + radius);
        setMeasuredDimension(width, height);
    }
    private void drawProgress(Canvas canvas){
    	if(mPaintArc == null){
    		return;
    	}
        //圆
        mPaintArc.setStyle(Paint.Style.FILL);
        canvas.drawCircle(dotX, dotY, radius, mPaintArc);
        //中心进度值
        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);//实心
        mPaint.setTextAlign(Paint.Align.CENTER);
        mPaint.setStrokeWidth(1);
        mPaint.setTextSize(textSize);
        mPaint.setColor(colorWhite);
        canvas.drawText(curProgress + "%",dotX,
                dotY+getResources().getDimension(R.dimen.text_size_14)/2
                ,mPaint);
        //黑色刻度  12点钟方向为起始点(-90°),正时针方法绘制
        for (int angle = -90; angle <= 270; angle += scaleAngle){
            float xY[] = caculCoordinate(angle);
            if(xY != null) {
                mPaint.setStrokeWidth(scaleWidth);
                mPaint.setColor(colorBlack);
                canvas.drawLine(xY[0], xY[1],xY[2],xY[3], mPaint);
            }
        }
        //进度算法
        //360 除与 scaleAngle(进度间隔10) = 36; 再拿进度总数100换算当前进度
        //算出当前进度占几个刻度
        int curProgressCount = curProgress * (360/scaleAngle) /100;
        int angleStart = -90;
        for (int count = 0; count < curProgressCount;count ++){
            float xY[] = caculCoordinate(angleStart);
            if(xY != null) {
                mPaint.setStrokeWidth(scaleWidth);
                mPaint.setColor(colorBlue);
                canvas.drawLine(xY[0], xY[1],xY[2],xY[3], mPaint);
            }
            angleStart += scaleAngle;
        }

    }

    /**
     * 根据圆心角 计算圆周上的坐标
     * @param angle
     * @return xY[0] startX; xY[1] startY; xY[2] endX; xY[3] endY;
     */
    private float[] caculCoordinate(int angle){
        //angle >180     angle = angle -180
        float xY[] = new float[4];
        //角度处理
        int tempAngle = Math.abs(angle);
        float tempScaleLineLenth = scaleLineLenth;

         if(270 > tempAngle && tempAngle >= 180) {
            tempAngle = tempAngle - 180;
            xY[0] = dotX - getCoordinateX(tempAngle,radius);
            xY[1] = dotY - getCoordinateY(tempAngle,radius);

            xY[2] = xY[0] + getCoordinateX(tempAngle,tempScaleLineLenth);
            xY[3] = xY[1] + getCoordinateY(tempAngle,tempScaleLineLenth);
        }else if(180 > tempAngle && tempAngle > 90){
            tempAngle = 180 - tempAngle;
            xY[0] = dotX - getCoordinateX(tempAngle,radius);
            xY[1] = dotY + getCoordinateY(tempAngle,radius);

            xY[2] = xY[0] + getCoordinateX(tempAngle,tempScaleLineLenth);
            xY[3] = xY[1] - getCoordinateY(tempAngle,tempScaleLineLenth);
        }else if(90 >= tempAngle && tempAngle >= 0){
            xY[0] = dotX + getCoordinateX(tempAngle,radius);
            xY[1] = angle < 0 ? dotY - getCoordinateY(tempAngle,radius) : dotY + getCoordinateY(tempAngle,radius);

            xY[2] = xY[0] - getCoordinateX(tempAngle,tempScaleLineLenth);
            xY[3] = angle < 0 ? xY[1] + getCoordinateY(tempAngle,tempScaleLineLenth) : xY[1] - getCoordinateY(tempAngle,tempScaleLineLenth);
        }

        return xY;
    }


    /**
     * 获取圆周上y值相对值
     * @param tempAngle
     * @param radius 算开始坐标是传半径,算结束坐标时传刻度线的长度
     * @return
     */
    private float getCoordinateY(int tempAngle,float radius){

        //利用正弦函数算出y坐标
        return (float) (Math.sin(tempAngle*Math.PI/180)*(radius - 15)); //10 是离圆弧的距离
    }
    /**
     * 获取圆周上X值相对值
     * @param tempAngle
     * @return
     */
    private float getCoordinateX(int tempAngle,float radius){

        //利用余弦函数算出y坐标
        return (float) (Math.cos(tempAngle*Math.PI/180)*(radius - 15));
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawProgress(canvas);
    }
    public void setProgress(int progress){
        if (progress < 0 || progress > 100)
            return;
        ObjectAnimator o = ObjectAnimator.ofInt(this, "curProgress", oldProgress, progress);
        o.setDuration(1000);
        o.setInterpolator(new DecelerateInterpolator());
        o.start();
        oldProgress = progress;
    }
}

组合起来使用:MyProgress.class
package com.totcy.magicprogress;

import android.R.dimen;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;

/**
 * Description 组合装逼进度
 * Author: tu
 * Date: 2016-08-22
 * Time: 15:36
 */
public class MyProgress extends RelativeLayout {
	
	private Context context;
	private float textProgressSize;//圆形进度条中间文字
	private float horizonalProgressHeight;//横条高度
	private float circleProgressRadus;//圆形半径
	private int colorProgress;//进度条颜色,圆盘刻度颜色
	private int colorSecondProgress;//进度条背景颜色
	
	private boolean flagPaint = true;//绘图标志
	int newProgress;
    private CircleProgress mCircleProgress;
    private HorizonalProgress mHorizonalProgress;
    //private int touchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();//最小滑动阀值

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

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

    public MyProgress(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context = context;
        init(attrs);
        ViewTreeObserver vto = getViewTreeObserver();
	    vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
	        @Override
	        public void onGlobalLayout() {
	        	if(flagPaint){
	        		flagPaint = false;
	        		initHorizonalProgress();
	        	}else{
	        		
	        	}
	        }
	  });
    }

    private void init(AttributeSet attrs){
    	flagPaint = true;
    	//获取自定义xml属性
    	TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.myMagicProgress);
    	int n = typedArray.getIndexCount();
    	for (int i = 0; i < n; i++) {
    		int attr = typedArray.getIndex(i);
			switch (attr) {
			case R.styleable.myMagicProgress_circleProgressRadus:
//				Log.e("tag", "typedArray.getDimension(attr, 0)="+typedArray.getDimension(attr, 0)+",typedArray.getDimension(i, 0)="+typedArray.getDimension(i, 0));
				circleProgressRadus = typedArray.getDimension(attr, 0);
				break;
			case R.styleable.myMagicProgress_horizonalProgressHeight:
				horizonalProgressHeight = typedArray.getDimension(attr, 0);
							break;
			case R.styleable.myMagicProgress_textProgressSize:
				textProgressSize = typedArray.getDimension(attr, 0);
				break;
			case R.styleable.myMagicProgress_colorProgress:
				colorProgress = typedArray.getColor(attr, Color.GRAY);
				break;
			case R.styleable.myMagicProgress_colorSecondProgress:
				colorSecondProgress = typedArray.getColor(attr, Color.GRAY);
				break;
			default:
				break;
			}
		}
    	
    	//横向进度条稍后设置参数,需要圆形进度条绘图完成,根据宽度绘制左右边距
        mHorizonalProgress = new HorizonalProgress(getContext());
        mHorizonalProgress.setProgressHeight((int) horizonalProgressHeight);
        mHorizonalProgress.setColorSecondProgress(colorSecondProgress);
        mHorizonalProgress.setColorProgress(colorProgress);
        
        int radus = (int) circleProgressRadus;
        mCircleProgress = new CircleProgress(getContext());
        mCircleProgress.setTextSize(textProgressSize);
        mCircleProgress.setColorBlue(colorProgress);
        LayoutParams cp_lp = new RelativeLayout.LayoutParams(radus,radus);
        cp_lp.addRule(RelativeLayout.CENTER_VERTICAL);
        mCircleProgress.setLayoutParams(cp_lp);

        addView(mHorizonalProgress);
        addView(mCircleProgress);

        initView();
        
    }
    private float mDownX;
    private void initView(){
        mCircleProgress.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        mDownX = event.getX();
//                      Log.d("Tag",event.getX() + ":" + event.getRawX());
                        break;
                    case MotionEvent.ACTION_MOVE:
//                      Log.d("Tag",event.getX() + ":" + event.getRawX());
                        float disX = event.getX() - mDownX;
                        float llX = mCircleProgress.getX() + disX;
//                      Log.e("tag", "disX="+disX+",llX="+llX+",mHorizonalProgress.getWidth()="+mHorizonalProgress.getWidth());
                        //校正边界,反正滑块划出
                        llX = checkoundary(llX);
                        mCircleProgress.setX(llX);
                        //计算进度条百分比
                        newProgress = getProgress(llX);
                        //更新进度条
                        updateProgress(newProgress);
                        break;
                    case MotionEvent.ACTION_UP:
                        break;
                    default:
                        break;
                }
                return true;
            }
        });
    }
    /**
     * 绘制横向进度条
     */
    public void initHorizonalProgress(){
//      Log.e("tag", "mCircleProgress.getWidth()="+mCircleProgress.getWidth());
    	//设置边距,左右空出滑块半径的距离
        LayoutParams hp_lp = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,(int) horizonalProgressHeight);
        hp_lp.leftMargin = mCircleProgress.getWidth()/2;
        hp_lp.rightMargin = mCircleProgress.getWidth()/2;
        hp_lp.addRule(RelativeLayout.CENTER_VERTICAL);
        mHorizonalProgress.setLayoutParams(hp_lp);
    }
    
    /**
     * 校正边界
     * @return
     */
    public float checkoundary(float llX){
    	if(llX<0){
        	llX = 0f;
        }else if(llX>mHorizonalProgress.getWidth()){
        	llX = mHorizonalProgress.getWidth();
        }
    	return llX;
    }
    
    /**
     * 换算百分比
     */
    public int getProgress(float llX){
    	return (int) ((llX/mHorizonalProgress.getWidth())*100);
    }
    
    /**
     * 更新进度
     * @param newProgress
     */
    public void updateProgress(int newProgress){
//    	Log.e("tag", "newProgress="+newProgress);
    	mCircleProgress.setProgress(newProgress);
    	mHorizonalProgress.setProgress(newProgress);
    }
}


总结:


整个控件的难点在于CircleProgress上环形刻度的绘制,圆周上取坐标的算法,具体算法代码中都有注释,下面结合这张草图分析可以更加透彻:
技术分享

酷炫进度条 自定义SeekBar

标签:

原文地址:http://blog.csdn.net/tl792814781/article/details/52289864

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!