本篇文章主要记录本周学习的进度动画,一个特别有趣的例子,当我们点击的时候,会开始进度值变化,还会有圆环进度变化
演示:
image.png
下面让我们一起实现一下
activity_mian
界面布局
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<me.jrl.demo4.DownloadView
android:id="@+id/mDownLoadView"
android:layout_width="200dp"
android:layout_height="200dp"
app:bgColor="@color/colorAccent"
app:pgColor="@color/colorPrimary"
app:txColor="@android:color/black"
app:lineWidth="20dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
布局可以根据自己需要调整,这里为了好看,我就设置了屏幕居中了
DownloadView
自定义View
import android.animation.ValueAnimator
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.RectF
import android.text.TextPaint
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import android.view.View
import kotlin.math.log
import kotlin.math.min
class DownloadView : View {
/**
* 圆环画笔,绘制背景
* */
private val mBgPaint by lazy {
Paint().apply {
strokeWidth = mLineWidth
color = mBgColor
style = Paint.Style.STROKE
isAntiAlias = true
isDither = true
}
}
/**
* 背景颜色
* */
private var mBgColor = 0
/**
* 圆环画笔,绘制进度
* */
private val mPgPaint by lazy {
Paint().apply {
strokeWidth = mLineWidth
color = mPgColor
style = Paint.Style.STROKE
isAntiAlias = true
isDither = true
}
}
/**
* 进度颜色
* */
private var mPgColor = 0
/**
* 线宽
* */
private var mLineWidth = dp2px(0)
/**
* 画笔,绘制进度值
* */
private val mTxPaint by lazy {
TextPaint().apply {
strokeWidth = dp2px(2)
textSize = dp2px(20)
color = mTxColor
style = Paint.Style.STROKE
isAntiAlias = true
isDither = true
}
}
/**
* 文本颜色
* */
private var mTxColor = 0
/**
* 控件中心点
* */
private var cx = 0f
private var cy = 0f
/**
* 圆环半径
* */
private var radius = 0f
/**
* 下载动画因子,也就是进度值
* */
private var progress = 0f
/**
* 下载动画
* */
private var mAnimator: ValueAnimator? = null
/**
* 矩阵
* */
private val mRectF by lazy {
RectF(cx - radius,cy - radius,cx + radius,cy + radius)
}
/**
* 进度值
* */
private var mText = "0%"
/**
* 文字矩阵
* */
private val mFontMetricsInt by lazy {
mTxPaint.fontMetricsInt
}
constructor(context: Context) : super(context) {}
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
init(context, attrs)
}
/**
* 提取自定义属性
* */
private fun init(context: Context, attrs: AttributeSet?) {
val array = context.obtainStyledAttributes(attrs, R.styleable.DownloadView)
mBgColor = array.getColor(R.styleable.DownloadView_bgColor, Color.GREEN)
mPgColor = array.getColor(R.styleable.DownloadView_pgColor, Color.BLUE)
mTxColor = array.getColor(R.styleable.DownloadView_txColor, Color.BLACK)
mLineWidth = array.getDimension(R.styleable.DownloadView_lineWidth, dp2px(20))
array.recycle()
}
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
cx = measuredWidth / 2f
cy = measuredHeight / 2f
//半径取宽高的最小值的一半,再减去线的宽度
radius = min(measuredWidth, measuredHeight) / 2f - mLineWidth
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
//绘制背景圆环
canvas?.drawCircle(cx,cy,radius,mBgPaint)
//绘制进度圆环
canvas?.drawArc(mRectF,0f,progress * 360,false,mPgPaint)
//文字宽度的一半
val mHalfWidth = mTxPaint.measureText(mText) / 2
Log.v("pxd","mHalfWidth:$mHalfWidth")
//绘制显示的进度值
canvas?.drawText(mText,cx - mHalfWidth,cy - mFontMetricsInt.ascent / 2,mTxPaint)
}
/**
* 下载,实现下载动画
* */
private fun initAnimator() {
mAnimator = ValueAnimator.ofFloat(0f, 1f).apply {
duration = 2000
addUpdateListener {
progress = it.animatedValue as Float
mText = "${(progress * 100).toInt()}%"
//重绘
invalidate()
}
start()
}
}
/**
* 开始动画或者暂停动画
* */
fun start() {
if (mAnimator != null) {
if (mAnimator!!.isPaused) {
mAnimator!!.resume()
} else {
mAnimator!!.start()
}
} else {
initAnimator()
}
}
override fun onTouchEvent(event: MotionEvent?): Boolean {
if (event?.action == MotionEvent.ACTION_DOWN){
start()
}
return true
}
/**
* dp 转 px
* */
private fun dp2px(dpValue: Int): Float {
val scale = context.resources.displayMetrics.density
return (dpValue * scale + 0.5f)
}
}
这里有两个需要提到的点
- 1.如何提取自定义属性
- 2.如何绘制文本,属性动画这里就不再提了
提取自定义属性
第一步在
values
所对应的包名下新建attrs
的xml
文件
第二步声明自己想要的属性
第三步在构造方法中提取属性,也可以单独写一个方法来提取属性,我这里就是
最后在xml
文件里引用自定义的属性
atrrs
xml文件
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ProgressView">
<attr name="bg_color" format="color|integer"/>
<attr name="pg_color" format="color|integer"/>
<attr name="tv_color" format="color|integer"/>
<attr name="lineWidth" format="float|dimension"/>
<attr name="textSize" format="float|dimension"/>
</declare-styleable>
</resources>
init
方法,用来提取属性
/**
* 提取自定义属性
* */
private fun init(context: Context, attrs: AttributeSet?) {
val array = context.obtainStyledAttributes(attrs, R.styleable.DownloadView)
mBgColor = array.getColor(R.styleable.DownloadView_bgColor, Color.GREEN)
mPgColor = array.getColor(R.styleable.DownloadView_pgColor, Color.BLUE)
mTxColor = array.getColor(R.styleable.DownloadView_txColor, Color.BLACK)
mLineWidth = array.getDimension(R.styleable.DownloadView_lineWidth, dp2px(20))
array.recycle()
}
这里需要注意的是
/**
* 1.使用obtainStyledAttributes
* resId: R.styleable.ProgressView 指定从哪个样式中解析
* attrs: 从哪里解析 解析的数据在哪里
* 返回值 TypedArray
* 必须使用 recycle() 回收
* */
最后在xml文件里使用属性,自定义属性一般以app:
开头
app:bgColor="@color/colorAccent"
app:pgColor="@color/colorPrimary"
app:txColor="@android:color/black"
app:lineWidth="20dp"
那么我们如何绘制文本呢,具体来说就是调用canvas?.drawText
方法
里面有4个参数,第一个参数是绘制的内容,中间两个参数表示绘制的起始坐标,第4个参数画笔,这里我们的x坐标取绘制文字的起始点的横坐标,也就是圆中心坐标cx
减去一半文字宽度的距离mHalfWidth
,y坐标取值文字高度的一半,这里求文字高度的方法不是唯一的,可以通过文字矩阵的高度的一半 - bottom的距离,这里通过将y坐标向下平移一半的ascent的距离得到,ascent的值为负,所有减去一半就是向下平移一半的距离cy - mFontMetricsInt.ascent / 2
//绘制显示的进度值
canvas?.drawText(mText,cx - mHalfWidth,cy - mFontMetricsInt.ascent / 2,mTxPaint)
网友评论