关键词:
前些天一同学给了我一个ui图,是这样子的:
需求:
1、看了ui图可以知道这类似android自带的seekbar控件, 2、一个水平进度条和一个圆形进度条; 3、圆形进度条显示环形刻度和当前进度值; 4、并且圆形进度可滑动操作;最终实现效果:
废话不多说上代码:
水平的进度条: HorizonalProgress.classpackage 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上环形刻度的绘制,圆周上取坐标的算法 ,具体算法代码中都有注释,下面结合这张草图分析可以更加透彻:
源码下载猛戳 (提取码:2ea4) csdn下载
android自定义进度值可拖动的seekbar(代码片段)
...坚持写。今天就简单的写一下我在项目中用到的算自定义seekbar的博客,需求是这样的,seekbar需要显示最左和最右值,进度要跟随进度块移动。看下效果图就明白了。其实实现起来很简单,主要是思路。自定义控... 查看详情
一个简单seekbar样式的例子(代码片段)
SeekBar在布局中的使用: <SeekBarandroid:layout_width="300px"android:layout_height="wrap_content"android:minHeight="10px"<!--定义进度条的高,不包括thumb的高-->android:maxHeight="10px"<!--定义进度条的高,不包括thumb的高 查看详情
Angular - 材质:进度条自定义颜色?
】Angular-材质:进度条自定义颜色?【英文标题】:Angular-Material:Progressbarcustomcolor?【发布时间】:2018-07-2921:49:34【问题描述】:我现在尝试了几个小时。我使用Material2,只是想更改进度条的颜色。我知道有这些主题(主要/重音/... 查看详情
一起talkandroid吧(第四百五十九回:seekbar补充用法二)(代码片段)
文章目录修改进度的步进值自定义SeekBar围魏救赵各位看官们大家好,上一回中咱们说的例子是"SeekBar补充用法",这一回中咱们继续说该例子。闲话休提,言归正转,让我们一起TalkAndroid吧!我们在上一章回中介绍了SeekBar补充用法... 查看详情
自定义垂直拖动的seekbar进度条
系统自定义的seekbar为横向拖动的样式,需要纵向的时则需要自己定义,网上很多说了重写系统SeekBar中onDraw()的方法,但是我使用的时候不知道为什么拖动条和点偏离了,不在一条直线上,好气。。。然后用了另一篇中改进之后... 查看详情
Seekbar进度drawable异常行为onPause
】Seekbar进度drawable异常行为onPause【英文标题】:SeekbarprogressdrawableabnormalbehavioronPause【发布时间】:2016-08-0918:51:14【问题描述】:我在片段中显示了一个搜索栏。搜索栏具有自定义拇指和进度可绘制对象。它们显示得很好,但是... 查看详情
android进度条(progressbar)和拖动条(seekbar)补充“自定义组件”(总结)(代码片段)
这周结束了,我也码了一周的字,感觉还是很有种脚踏实地的感觉的,有时间就可以看看自己的总结再查漏补缺,一步一个脚印,做出自己最理想的项目。 今天我们讲两点:1.ProgressBar: 其实前面也稍微提到过,但是只... 查看详情
进度部分上的 Seekbar 外阴影
】进度部分上的Seekbar外阴影【英文标题】:Seekbaroutershadowonprogresspart【发布时间】:2017-05-1012:07:45【问题描述】:我在Android中自定义了一个搜索栏,试图只获取填充部分的内部和外部阴影(底部)。我想要这样的结果:此刻,... 查看详情
seekbar(代码片段)
进度,音量等的拖动条。方法setMax设置SeekBar的最大数值setProgress设置SeekBar当前的数值setSecondaryProgress设置SeekBar的第二数值,即当前拖动条推荐的数值事件实现SeekBar的SeekBar.OnSeekBarChangeListener接口。监听三个事件数值改变... 查看详情
seekbar的简单使用
1SeekBar简介SeekBar是进度条。我们使用进度条时,可以使用系统默认的进度条;也可以自定义进度条的图片和滑块图片等。2SeekBar示例功能:手动拖动进度条,TextView中文字显示进度的改变。1publicclassMainActivityextendsAppCompatActivity{2pri... 查看详情
Seekbar 和 InsetDrawable 获取进度
】Seekbar和InsetDrawable获取进度【英文标题】:SeekbarandInsetDrawableforprogress【发布时间】:2011-04-0113:43:33【问题描述】:您好,我尝试自定义搜索栏。这是我的问题:main.xml...<SeekBarandroid:id="@+id/seekBar1"android:layout_android:layout_android:l... 查看详情
第三方开源库-->那些酷炫的seekbar&ratingbar&toast开源库整理
Seekbar1、RangeSeekBarGithub:https://github.com/Jay-Goo/RangeSeekBar简介:一款美观强大的支持单向、双向范围选择、分步、垂直、高度自定义的SeekBar。效果图:2、IndicatorSeekBarGithub:https://github.com/warkiz/IndicatorSeekBar简介 查看详情
自定义seekbar样式详解
...景android:thumb进度thumb(拖块)android:splitTrackthumb是否切割seekbar背景,默认true,会看到thumb周围区域被切割,效果如下(为了效果明显,背景高度特意改高了)seekbar_bg.xmlseekbar_thumb.xml可以不指定android:thumb指定android:thumbTint来改变th... 查看详情
java示例代码_将seekbar进度从10k更改为20L,增加1000
java示例代码_将seekbar进度从10k更改为20L,增加1000 查看详情
滚动时更新自定义列表视图失败(代码片段)
...();rowView=inflater.inflate(R.layout.voice_player_listview,null,true);finalSeekBarvoice_player_seekbar=(SeekBar)rowView.findViewById(R.id.voice_player_seekbar);finalImageViewicon=(ImageView)rowView.findViewById(R.id.download_play_icon);icon.setOnClickListener(newView.OnClickListener()@Overridepu 查看详情
Seekbar想要保存进度[重复]
】Seekbar想要保存进度[重复]【英文标题】:Seekbarwanttosaveprogress[duplicate]【发布时间】:2013-03-3121:05:50【问题描述】:我正在使用搜索栏,我想保存用户在搜索栏中所做的更改,并且应该在下次他打开应用程序时显示。我的代码是... 查看详情
一起talkandroid吧(第四百五十八回:seekbar补充用法一)(代码片段)
..."修改View的布局参数",这一回中咱们说的例子是"SeekBar补充用法"。闲话休提,言归正转,让我们一起TalkAndroid吧!我们在之前的博客中介绍过SeekBar的用法,如果有看官忘记了可以点击这里查看 查看详情
带文字的seekbar:自定义progressdrawable/thumb:解决显示不全(代码片段)
自定义viewimportandroid.content.Context;importandroid.graphics.Canvas;importandroid.graphics.Paint;importandroid.graphics.Rect;importandroid.graphics.drawable.Drawable;importandroid.text.TextPaint;import 查看详情