酷炫进度条 自定义SeekBar
Posted Coding_the_world
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了酷炫进度条 自定义SeekBar相关的知识,希望对你有一定的参考价值。
原作者地址:http://blog.csdn.net/tl792814781/article/details/52289864
前些天一同学给了我一个ui图,是这样子的:
需求:
1、看了ui图可以知道这类似android自带的seekbar控件, 2、一个水平进度条和一个圆形进度条; 3、圆形进度条显示环形刻度和当前进度值; 4、并且圆形进度可滑动操作;最终实现效果:
废话不多说上代码:
水平的进度条: HorizonalProgress.class [java] view plain copy- 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 [java] view plain copy
- 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 [java] view plain copy
- 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上环形刻度的绘制,圆周上取坐标的算法 ,具体算法代码中都有注释,下面结合这张草图分析可以更加透彻:
源码下载猛戳 (提取码:2ea4) csdn下载
以上是关于酷炫进度条 自定义SeekBar的主要内容,如果未能解决你的问题,请参考以下文章