Android view自定义实现动态进度条
作者:danfengw 发布时间:2023-09-16 00:40:38
标签:进度条,Android,view,自定义
Android 自定义view实现动态进度条
效果图:
这个是看了梁肖的demo,根据他的思路自己写了一个,但是我写的这个貌似计算还是有些问题,从上面的图就可以看出来,左侧、顶部、右侧的线会有被截掉的部分,有懂得希望能给说一下,改进一下,这个过程还是有点曲折的,不过还是觉得收获挺多的。比如通动画来进行动态的展示(之前做的都是通过Handler进行更新的所以现在换一种思路觉得特别好),还有圆弧的起止角度,矩形区域的计算等!关于绘制我们可以循序渐进,比如最开始先画圆,然后再画周围的线,最后设置动画部分就可以了。不多说了,上代码了。
代码
自定义View
public class ColorProgressBar extends View{
//下面这两行在本demo中没什么用,只是前几天看别人的代码时学到的按一定尺寸,设置其他尺寸的方式,自动忽略或者学习一下也不错
// private int defaultStepIndicatorNum= (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,40,getResources().getDisplayMetrics());
// int mCircleRadius=0.28f*defaultStepIndicatorNum;
//布局的宽高
private int mWidth;
private int mHeight;
//直径
private int mDiameter=500;
//底层圆画笔
private Paint mPaintbg;
//顶层圆的画笔
private Paint mPaintft;
//周围线的画笔
private Paint mPaintLine;
//外层线条的长度
private int mLongItem=dip2px(20);
//线条与圆的间距
private int mDistanceItem=dip2px(10);
//进度条的最大宽度(取底层进度条与顶层进度条宽度最大的)
private int mProgressWidth;
//底层圆的颜色
private int mBackColor;
//顶层圆的颜色
private int mFrontColor;
//底层圆、顶层圆的宽度
private float mBackWidth;
private float mFrontWidth;
//设置进度
private float currentvalue;
//通过动画演示进度
private ValueAnimator animator;
private int curvalue;
public ColorProgressBar(Context context) {
this(context,null,0);
}
public ColorProgressBar(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public ColorProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray ta=context.obtainStyledAttributes(attrs, R.styleable.ColorProgressBar);
mBackColor= ta.getColor(R.styleable.ColorProgressBar_back_color, Color.BLACK);
mFrontColor=ta.getColor(R.styleable.ColorProgressBar_front_color,mBackColor);
mBackWidth=ta.getDimension(R.styleable.ColorProgressBar_back_width,dip2px(10));
mFrontWidth=ta.getDimension(R.styleable.ColorProgressBar_front_width,dip2px(10));
mProgressWidth=mBackWidth>mFrontWidth?(int)mBackWidth:(int)mFrontWidth;
//注意释放资源
ta.recycle();
init();
}
/**
* 都是画笔初始化
*/
private void init() {
mPaintbg=new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintbg.setStrokeWidth(mProgressWidth);
mPaintbg.setColor(mBackColor);
mPaintbg.setStrokeCap(Paint.Cap.ROUND);
mPaintbg.setStyle(Paint.Style.STROKE);
mPaintft=new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintft.setColor(mFrontColor);
mPaintft.setStyle(Paint.Style.STROKE);
mPaintft.setStrokeWidth(mFrontWidth);
mPaintft.setStrokeCap(Paint.Cap.ROUND);
mPaintLine=new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintLine.setColor(Color.BLACK);
mPaintLine.setStrokeWidth(5);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 宽度=高度=(长指针+指针与圆盘的间距+进度条的粗细+半径)*2
Log.e("测量数据","LongItem:"+mLongItem+"mDistanceItem:"+mDistanceItem+"mProgressWidth:"+mProgressWidth+"mDiameter:"+mDiameter/2);
mWidth=(int)2*(mLongItem+mDistanceItem+mProgressWidth*2+mDiameter/2);
mHeight=(int)2*(mLongItem+mDistanceItem+mProgressWidth*2+mDiameter/2);
Log.e("自定义View","高度"+mHeight+"宽度"+mWidth);
setMeasuredDimension(mWidth,mHeight);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//绘制底层圆弧,矩形的具体计算见图片
canvas.drawArc(new RectF(mProgressWidth/2+mDistanceItem+mLongItem,mProgressWidth/2+mDistanceItem+mLongItem,mWidth-mProgressWidth/2-mDistanceItem-mLongItem,mHeight-mProgressWidth/2-mDistanceItem-mLongItem),0,360,true,mPaintbg);
// SweepGradient gradient=new SweepGradient();
//绘制边缘线
canvas.save();
canvas.rotate(144,mWidth/2,mHeight/2);
for(int i=0;i<=30;i++){
canvas.rotate(-9,mWidth/2,mHeight/2);
if(i%5==0){
canvas.drawLine(mWidth/2,5,mWidth/2,mLongItem,mPaintbg);
}else {
canvas.drawLine(mWidth/2,25,mWidth/2,mLongItem,mPaintLine);
}
}
canvas.restore();
//给画笔设置渐变
SweepGradient sweepGradient=new SweepGradient(mWidth/2,mHeight/2,Color.RED,Color.YELLOW);
mPaintft.setShader(sweepGradient);
//绘制顶层圆弧,currentvalue在改变时呈现动态效果
canvas.drawArc(new RectF(mProgressWidth/2+mDistanceItem+mLongItem,mProgressWidth/2+mDistanceItem+mLongItem,mWidth-mProgressWidth/2-mDistanceItem-mLongItem,mHeight-mProgressWidth/2-mDistanceItem-mLongItem),135,currentvalue,false,mPaintft);
mPaintft.setTextSize(100);
mPaintft.setTextAlign(Paint.Align.CENTER);
//绘制文本
canvas.drawText(String.format("%.0f",currentvalue),mWidth/2,mHeight/2+50,mPaintft);
invalidate();
}
/**
* 设置动画
* @param value
*/
public void setCurrentValue(float value){
// currentvalue=value;
animator=ValueAnimator.ofFloat(currentvalue,value);
animator.setDuration(3000);
animator.setTarget(currentvalue);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
currentvalue= (float) valueAnimator.getAnimatedValue();
curvalue=curvalue/10;
}
});
animator.start();
}
private int dip2px(float dip){
float density=getContext().getResources().getDisplayMetrics().density;
return (int)(dip*density+0.5f);
}
}
矩形计算
Activity调用
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.colorprogressbar);
mBtStart1= (Button) findViewById(R.id.bt1);
bar1= (ColorProgressBar) findViewById(R.id.cp1);
mBtStart1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
bar1.setCurrentValue(270);
}
});
}
自定义属性
<declare-styleable name="ColorProgressBar">
<attr name="back_color" format="color"></attr>
<attr name="front_color" format="color"></attr>
<attr name="back_width" format="dimension"></attr>
<attr name="front_width" format="dimension"></attr>
</declare-styleable>
布局
注意:为了使用自定义属性需要添加一行代码(AS)
xmlns:app=http://schemas.android.com/apk/res-auto
布局
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<Button
android:id="@+id/bt1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="start1"/>
<com.demo.demo.networkdemo.colorprogressbar.widget.ColorProgressBar
android:id="@+id/cp1"
android:layout_width="232dp"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
app:back_color="@color/colorPrimary"
app:front_color="@color/colorAccent"
android:background="@mipmap/ic_launcher"/>
</LinearLayout>
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
来源:http://blog.csdn.net/danfengw/article/details/53691083


猜你喜欢
- 为什么使用Kotlin项目一期在收尾了终于有时间折腾了,一个多月以来Kotlin从入门到现在,坚持用来开发的切身感受。因为语法与Java的区
- 如果你还不是很了解restful,或者认为restful只是一种规范不具有实际意义,推荐一篇osc两年前的文章:RESTful API 设计
- 最近的项目在做socket通信报文解析的时候,用到了结构体与字节数组的转换;由于客户端采用C++开发,服务端采用C#开发,所以双方必须保证各
- 前言日常开发中,缓存是解决数据库压力的一种方案,通常用于频繁查询的数据,例如新闻中的热点新闻,本文记录springboot中使用cache缓
- 1.Java运行环境搭建,对于初学者来说,主要下载安装jdk即可,windows操作系统再配合记事本,即可进行java程序开发。后续的学习以
- 前言消息推送功能可以说移动APP不可缺少的功能之一,一般简单的推送我们可以使用第三方推送的SDK,比如极光推送、信鸽推送等,但是对于消息聊天
- 本文主要介绍的是一个球形水波的百分比控件,市面上有各种形形色色的百分比控件,我一直觉得水波是最炫的,UI给了我这个机会,然而网上搜了一大堆,
- 本文汇总了Spring的常用注解,以方便大家查询和使用,具体如下:使用注解之前要开启自动扫描功能其中base-package为需要扫描的包(
- 最近项目需要在浏览器中通过URL预览图片。但发现浏览器始终默认下载,而不是预览。研究了一下,发现了问题:// 设置response的Head
- 原理解析:利用RandomAccessFile在本地创建一个随机访问文件,文件大小和服务器要下载的文件大小相同。 根据线程的数量(假设有三个
- 1.封装分页Page类package com.framework.common.page.impl;import java.io.Seria
- 大家好,好久不见了,最近由于工作特别繁忙,已经有一个多月的时间没写博客了,我也是深感惭愧。那么今天的这篇既然是阔别了一个多月的文章,当然要带
- json是种常用的数据传输格式,在android开发中,如何借助java语言实现对json数组对象的解析呢,请参阅下面的关键代码:impor
- 背景:最近需要做一个任务:C# PDF文件需要传输为JPG图片。一开始没有头绪,最后去github找到了现在我用的PdfiumViewer组
- 核心思想:“分”与“合”。主体流程先将一个序列分成很多个不能再分割的子序列,将各个子序列分别排序后再将子序列合并。其实就是重复两个步骤:【1
- 在处理网络请求时,有一部分功能是需要抽出来统一处理的,与业务隔开。登录校验可以利用spring mvc的 * Interceptor,实现H
- 如果我们的程序是在单线程下运行,或者是不必考虑到线程同步问题,我们应该优先使用StringBuilder类;如果要保证线程安全,自然是Str
- 一、内部存储内部存储,位于data/data/包名/路径下是否需要用户权限:否是否能被其他应用访问:否卸载应用数据是否被删除:是内部存储控件
- 申请百度地图密钥以及查看百度API网址:http://lbsyun.baidu.com/apiconsole/key#/home网址:htt
- 有经验的开发人员都知道在开发.NET应用时可以利用配置文件保存一些常用并且有可能变化的信息,例如日志文件的保存路径、数据库连接信息等等,这样