自定义View | 仿QQ运动步数进度效果
时间:2022-07-24
本文章向大家介绍自定义View | 仿QQ运动步数进度效果,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
思路
- 固定不动的蓝色大圆弧
- 动画变动的红色小圆弧
- 中间的步数文字显示
-
相关的
自定义属性
比如固定不动的大圆弧
, 我们不能写死他的蓝色颜色属性, 要提供一个颜色的自定义属性
给用户自定义配置
;圆弧的宽度
也是要可以自定义的;
自定义属性
<?xml version="1.0" encoding="utf-8"?>
<resources>
...
<declare-styleable name="QQStepView">
<attr name="outerColor" format="color"/>
<attr name="innerColor" format="color"/>
<attr name="borderWidth" format="dimension"/>
<attr name="stepTextSize" format="dimension"/>
<attr name="stepTextColor" format="color"/>
</declare-styleable>
</resources>
布局使用
<com.lwp.customviewtest.CustomViews.QQStepView
android:id="@+id/step_view"
app:outerColor="@color/colorPrimary"
app:innerColor="@color/colorAccent"
app:borderWidth="15dp"
app:stepTextColor="@color/colorAccent"
app:stepTextSize="16sp"
android:layout_width="match_parent"
android:layout_height="match_parent" />
自定义View逻辑
public class QQStepView extends View {
//初始化 自定义属性变量 并给 默认值
private int mOuterColor = Color.RED;//默认红色
private int mInnerColor = Color.BLUE;//默认蓝色
private int mBorderWidth = 20;//20px
private int mStepTextSize = 20;
private int mStepTextColor = Color.RED;
private Paint mPaint;
private int mStartAngle = 135;
private int mSweepAngle = 270;
private int mStepMax = 0;
private int mCurrentStep = 0;
public QQStepView(Context context) {
this(context, null);
}
public QQStepView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public QQStepView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//获取自定义属性
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.QQStepView);
mOuterColor = array.getColor(R.styleable.QQStepView_outerColor, mOuterColor);
mInnerColor = array.getColor(R.styleable.QQStepView_innerColor, mInnerColor);
mBorderWidth = (int) array.getDimension(R.styleable.QQStepView_borderWidth, mBorderWidth);
mStepTextSize = array.getDimensionPixelSize(R.styleable.QQStepView_stepTextSize, mStepTextSize);
mStepTextColor = array.getColor(R.styleable.QQStepView_stepTextColor, mStepTextColor);
array.recycle();
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStrokeWidth(mBorderWidth);
mPaint.setColor(mOuterColor);
mPaint.setStyle(Paint.Style.STROKE);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 调用者在布局文件中可能是 wrap_content 要做判断
//获取宽高
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
//设置宽高
// 宽高不一致 取最小值、确保是个正方形
setMeasuredDimension(widthSize > heightSize ? heightSize : widthSize,
widthSize > heightSize ? heightSize : widthSize);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//画外圆弧==============================
//拿到View的中心点
int centerX = getWidth() / 2;
int centerY = getHeight() / 2;
// 半径
int radius = (int) (centerX - mBorderWidth);
// 设置圆弧画笔的宽度
mPaint.setStrokeWidth(mBorderWidth);
// 设置弧线的 首端 和 尾端 为 圆弧
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeJoin(Paint.Join.ROUND);
// 设置画笔颜色
mPaint.setColor(mOuterColor);
mPaint.setStyle(Paint.Style.STROKE);
//圆弧 内边缘的弧线的 外切矩形
RectF oval = new RectF(mBorderWidth, mBorderWidth, centerX + radius, centerY + radius);
// 画背景圆弧
canvas.drawArc(oval, mStartAngle, mSweepAngle, false, mPaint);
//画内圆弧==============================
// 提供百分比 给用户自己配置 【自定义属性】
mPaint.setColor(mInnerColor);
// 计算当前百分比
float percent = (float) mCurrentStep / mStepMax;
if (mStepMax != 0) {
// 根据当前百分比计算圆弧扫描的角度
canvas.drawArc(oval, mStartAngle, percent * mSweepAngle, false, mPaint);
}
//画文字==============================
// 重置画笔
mPaint.reset();
mPaint.setAntiAlias(true);
mPaint.setTextSize(mStepTextSize);
mPaint.setColor(mStepTextColor);
//文本内容
// String mStep = ((int) (percent * mStepMax)) + "";
String mStep = mCurrentStep + "";
// 测量文字的宽高
Rect textBounds = new Rect();
mPaint.getTextBounds(mStep, 0, mStep.length(), textBounds);
//文字的x轴起始点
int dx = (getWidth() - textBounds.width()) / 2;
// 获取画笔的FontMetrics
Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
// 计算文字的基线
int baseLine = (int) (getHeight() / 2 + (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom);
// 绘制步数文字
canvas.drawText(mStep, dx, baseLine, mPaint);
}
// 设置当前最大步数
public synchronized void setMaxStep(int maxStep) {
if (maxStep < 0) {
throw new IllegalArgumentException("max 不能小于0!");
}
this.mStepMax = maxStep;
}
public synchronized int getMaxStep() {
return mStepMax;
}
// 设置进度
public synchronized void setProgress(int progress) {
if (progress < 0) {
throw new IllegalArgumentException("progress 不能小于0!");
}
this.mCurrentStep = progress;
// 重新刷新绘制 -> onDraw()
invalidate();
}
public synchronized int getProgress() {
return mCurrentStep;
}
}
在Activity中使用自定义View和动画
final QQStepView qqStepView = (QQStepView) findViewById(R.id.step_view);
qqStepView.setMaxStep(6000);
//属性动画
ValueAnimator valueAnimator = ObjectAnimator.ofFloat(0, 5678);
valueAnimator.setDuration(1000);
valueAnimator.setInterpolator(new DecelerateInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float currentStep = (float) animation.getAnimatedValue();
qqStepView.setProgress((int)currentStep);
}
});
valueAnimator.start();
break;
效果:
- Scrapy-Redis分布式爬虫源码解析
- scala 隐式详解(implicit关键字)
- scala的option和some
- PEP8规则及Pycharm应用
- (四) 如何将socket设置为非阻塞模式
- Scala Collections集合的几个重要概念
- (五)如何编写高性能日志
- Scala之偏函数Partial Function
- (六)关于网络编程的一些实用技巧和细节
- 快学Scala习题答案汇总
- (八)高性能服务器架构设计总结1——以flamigo服务器代码为例
- (八)高性能服务器架构设计总结2——以flamigo服务器代码为例
- Scala集合练习题
- 机器学习(10)之趣味案例理解朴素贝叶斯
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- JVM系列之:JIT中的Virtual Call接口
- 重新构建711的Android项目(二),架构的选择与实现
- Android的配置文件操作封装,摒弃SharedPreference操作配置漫天乱飞
- java实现PBOC的TLV格式解析,超简单的解析(全互联网最简单)
- 链表总计
- Spring整合MongoDb
- 正确使用Qt多线程
- Spring与hibernate与mybatis
- scala 模式匹配的几个模式
- Spring Security 认证
- Spring Security 简单配置用户存储
- 我的小工具-nodejs串口转TCP调试通信
- Spring Web Folw配置
- Spring Aop支持
- 贪心思想