Android自定义View圆形进度条控件(三)

作者:猴菇先生 时间:2021-11-13 10:17:51 

继续练习自定义View,这次带来的圆形进度条控件与之前的圆形百分比控件大同小异,这次涉及到了渐变渲染以及画布旋转等知识点,效果如下:

Android自定义View圆形进度条控件(三)

虽然步骤类似,但是我还是要写,毕竟基础的东西就是要多练

1、在res/values文件夹下新建attrs.xml文件,编写自定义属性:


<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CircleProgressView">
<!-- 弧线宽度 -->
<attr name="arcWidth" format="dimension" />
<!-- 刻度个数 -->
<attr name="scaleCount" format="integer" />
<!-- 渐变起始颜色 -->
<attr name="startColor" format="color" />
<!-- 渐变终止颜色 -->
<attr name="endColor" format="color" />
<!-- 标签说明文本 -->
<attr name="labelText" format="string" />
<!-- 文本颜色 -->
<attr name="textColor" format="color" />
<!-- 百分比文本字体大小 -->
<attr name="progressTextSize" format="dimension" />
<!-- 标签说明字体大小 -->
<attr name="labelTextSize" format="dimension" />
</declare-styleable>
</resources>

2、新建CircleProgressView继承View,重写构造方法:


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

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

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

3、在第三个构造方法中获取自定义属性的值:


TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CircleProgressView, defStyleAttr, 0);
mArcWidth = ta.getDimension(R.styleable.CircleProgressView_arcWidth, DensityUtils.dp2px(context, 8));
mScaleCount = ta.getInteger(R.styleable.CircleProgressView_scaleCount, 24);
mStartColor = ta.getColor(R.styleable.CircleProgressView_startColor, Color.parseColor("#3FC199"));
mEndColor = ta.getColor(R.styleable.CircleProgressView_endColor, Color.parseColor("#3294C1"));
mColorArray = new int[]{mStartColor, mEndColor};
mLabelText = ta.getString(R.styleable.CircleProgressView_labelText);
mTextColor = ta.getColor(R.styleable.CircleProgressView_textColor, Color.parseColor("#4F5F6F"));
mProgressTextSize = ta.getDimension(R.styleable.CircleProgressView_progressTextSize, 160);
mLabelTextSize = ta.getDimension(R.styleable.CircleProgressView_labelTextSize, 64);
ta.recycle();

4、创建画图所使用的对象,如Paint、Rect、RectF:


mArcBackPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mArcBackPaint.setStyle(Paint.Style.STROKE);
mArcBackPaint.setStrokeWidth(mArcWidth);
mArcBackPaint.setColor(Color.LTGRAY);

mArcForePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mArcForePaint.setStyle(Paint.Style.STROKE);
mArcForePaint.setStrokeWidth(mArcWidth);

mArcRectF = new RectF();

mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mLinePaint.setStyle(Paint.Style.STROKE);
mLinePaint.setColor(Color.WHITE);
mLinePaint.setStrokeWidth(DensityUtils.dp2px(context, 2));

mProgressTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mProgressTextPaint.setStyle(Paint.Style.FILL);
mProgressTextPaint.setColor(mTextColor);
mProgressTextPaint.setTextSize(mProgressTextSize);

mLabelTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mLabelTextPaint.setStyle(Paint.Style.FILL);
mLabelTextPaint.setColor(mTextColor);
mLabelTextPaint.setTextSize(mLabelTextSize);

mTextRect = new Rect();

5、重写onMeasure()方法,计算自定义View的宽高:


@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(measuredDimension(widthMeasureSpec), measuredDimension(heightMeasureSpec));
}

private int measuredDimension(int measureSpec) {
int result;
int mode = MeasureSpec.getMode(measureSpec);
int size = MeasureSpec.getSize(measureSpec);
if (mode == MeasureSpec.EXACTLY) {
result = size;
} else {
result = 800;
if (mode == MeasureSpec.AT_MOST) {
result = Math.min(result, size);
}
}
return result;
}

6、重写onDraw()方法,绘制圆弧、刻度线和百分比文本、标签说明文本,注意坐标的计算:


@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mArcRectF.set(mArcWidth / 2, mArcWidth / 2, getWidth() - mArcWidth / 2, getHeight() - mArcWidth / 2);
//画背景弧线
canvas.drawArc(mArcRectF, -90, 360, false, mArcBackPaint);
//设置渐变渲染
LinearGradient linearGradient = new LinearGradient(getWidth() / 2, 0, getWidth() / 2, getHeight(), mColorArray, null, Shader.TileMode.CLAMP);
mArcForePaint.setShader(linearGradient);
//画百分比值弧线
canvas.drawArc(mArcRectF, -90, mSweepAngle, false, mArcForePaint);
//画刻度线
for (int i = 0; i < mScaleCount; i++) {
canvas.drawLine(getWidth() / 2, 0, getWidth() / 2, mArcWidth, mLinePaint);
//旋转画布
canvas.rotate(360 / mScaleCount, getWidth() / 2, getHeight() / 2);
}
//画百分比文本
String progressText = mProgress + "%";
mProgressTextPaint.getTextBounds(progressText, 0, progressText.length(), mTextRect);
float progressTextWidth = mTextRect.width();
float progressTextHeight = mTextRect.height();
canvas.drawText(progressText, getWidth() / 2 - progressTextWidth / 2,
getHeight() / 2 + progressTextHeight / 2, mProgressTextPaint);
//画标签说明文本
mLabelTextPaint.getTextBounds(mLabelText, 0, mLabelText.length(), mTextRect);
canvas.drawText(mLabelText, getWidth() / 2 - mTextRect.width() / 2,
getHeight() / 2 - progressTextHeight / 2 - mTextRect.height(), mLabelTextPaint);
}

7、暴露一个动态设置百分比的方法:


public void setProgress(float progress) {
Log.e("--> ", progress + "");
ValueAnimator anim = ValueAnimator.ofFloat(mProgress, progress);
anim.setDuration((long) (Math.abs(mProgress - progress) * 20));
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mProgress = (float) animation.getAnimatedValue();
mSweepAngle = mProgress * 360 / 100;
mProgress = (float) (Math.round(mProgress * 10)) / 10;//四舍五入保留到小数点后两位
invalidate();
}
});
anim.start();
}

8、在activity_main.xml布局文件中使用该View:


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:cpv="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity">

<com.monkey.circleprogressview.CircleProgressView
android:id="@+id/circle_progress_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
cpv:arcWidth="8dp"
cpv:endColor="#126b94"
cpv:labelText="学习进度"
cpv:labelTextSize="20sp"
cpv:progressTextSize="55sp"
cpv:scaleCount="24"
cpv:startColor="#12d699"
cpv:textColor="#4F5F6F" />
</RelativeLayout>

9、在MainActivity中设置监听,传入百分比:


final CircleProgressView view = (CircleProgressView) findViewById(R.id.circle_progress_view);
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
float progress = (float) (Math.random() * 100);
view.setProgress(progress);
}
});

代码下载地址

来源:http://blog.csdn.net/qq_31715429/article/details/54289705

标签:Android,进度条
0
投稿

猜你喜欢

  • Java实现调用对方http接口得到返回数据

    2023-02-27 22:36:29
  • Java编程实现提取文章中关键字的方法

    2022-10-10 22:08:42
  • 详解Java图形化编程中的鼠标事件设计

    2022-07-11 08:11:31
  • Java Stream流的常见生成和操作方法总结

    2023-08-26 12:06:21
  • Android 开发之Dialog,Toast,Snackbar提醒

    2021-05-31 14:27:20
  • SpringBoot2.0集成WebSocket实现后台向前端推送信息

    2023-08-22 18:50:39
  • Android实现自定义轮播图片控件示例

    2021-09-19 01:27:05
  • Android客户端实现图片轮播控件

    2023-08-12 17:01:57
  • Android实现拍照及图片裁剪(6.0以上权限处理及7.0以上文件管理)

    2022-05-19 09:18:14
  • 解决Android SDK下载和更新失败的方法详解

    2021-07-04 21:28:57
  • C#如何将Access中以时间段条件查询的数据添加到ListView中

    2022-02-22 22:15:18
  • 简单聊聊C#字符串构建利器StringBuilder

    2022-07-15 12:49:44
  • java使用jacob实现word转pdf

    2023-05-12 11:45:33
  • 详谈java中int和Integer的区别及自动装箱和自动拆箱

    2023-01-18 23:25:20
  • C#设计模式之Mediator中介者模式解决程序员的七夕缘分问题示例

    2021-10-05 16:28:14
  • 浅谈Java中ThreadLocal内存泄露的原因及处理方式

    2021-06-12 21:08:37
  • Android UI 实现老虎机详解及实例代码

    2022-06-09 05:01:30
  • 详解Java使用super和this来重载构造方法

    2023-04-20 08:34:47
  • Java Stopwatch类,性能与时间计时器案例详解

    2023-07-24 04:08:50
  • 常用json与javabean互转的方法实现

    2023-01-07 14:24:19
  • asp之家 软件编程 m.aspxhome.com