我正在实现一个自定义视图,该视图绘制某种ProgressBar视图,并以两个视图作为参数(起点和终点)。像这样:
这是完整的课程:
class BarView @JvmOverloads constructor(context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0) : View(context, attrs, defStyleAttr) {
private var valueAnimator: ObjectAnimator? = null
private lateinit var path: Path
private val pathMeasure = PathMeasure()
private var pauseProgress: Int = dip(40)
var progress = 0f
set(value) {
field = value.coerceIn(0f, pathMeasure.length)
invalidate()
}
private var originPoint: PointF? = null
private var destinationPoint: PointF? = null
private val cornerEffect = CornerPathEffect(dip(10).toFloat())
private val linePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
style = Paint.Style.STROKE
strokeWidth = dip(10f).toFloat()
color = ContextCompat.getColor(context, android.R.color.darker_gray)
pathEffect = cornerEffect
}
override fun draw(canvas: Canvas) {
super.draw(canvas)
if (progress < pathMeasure.length) {
val intervals = floatArrayOf(progress, pathMeasure.length - progress)
val progressEffect = DashPathEffect(intervals, 0f)
linePaint.pathEffect = ComposePathEffect(progressEffect, cornerEffect)
}
canvas.drawPath(path, linePaint)
}
object PROGRESS : Property<BarView, Float>(Float::class.java, "progress") {
override fun set(view: BarView, progress: Float) {
view.progress = progress
}
override fun get(view: BarView) = view.progress
}
private fun startAnimator() {
valueAnimator = ObjectAnimator.ofFloat(this, PROGRESS, 0f, pathMeasure.length).apply {
duration = 500L
interpolator = LinearInterpolator()
}
setPauseListener()
valueAnimator!!.start()
}
fun resume() {
valueAnimator!!.resume()
}
fun reset() {
startAnimator()
}
fun setPoints(originView: View, destinationView: View) {
originPoint = PointF(originView.x + originView.width / 2, 0f)
destinationPoint = PointF(destinationView.x + destinationView.width / 2, 0f)
setPath()
startAnimator()
}
private fun setPath() {
path = Path()
path.moveTo(originPoint!!.x, originPoint!!.y)
path.lineTo(destinationPoint!!.x, destinationPoint!!.y)
pathMeasure.setPath(path, false)
}
private fun setPauseListener() {
valueAnimator!!.addUpdateListener(object : ValueAnimator.AnimatorUpdateListener {
override fun onAnimationUpdate(valueAnimator: ValueAnimator?) {
val progress = valueAnimator!!.getAnimatedValue("progress") as Float
if (progress > pauseProgress) {
valueAnimator.pause()
this@BarView.valueAnimator!!.removeUpdateListener(this)
}
}
})
}
}
我想做的是在特定进度下暂停动画,在这种情况下为40dp:
private fun setPauseListener() {
valueAnimator!!.addUpdateListener(object : ValueAnimator.AnimatorUpdateListener {
override fun onAnimationUpdate(valueAnimator: ValueAnimator?) {
val progress = valueAnimator!!.getAnimatedValue("progress") as Float
if (progress > pauseProgress) {
valueAnimator.pause()
this@BarView.valueAnimator!!.removeUpdateListener(this)
}
}
})
}
但是,由于视图具有不同的路径长度,因此动画的速度有所不同,并且所有动画都必须在500毫秒内完成。它们不会在距原点相同的距离处暂停:
我尝试从LinearInterpolator
切换到AccelerateInterpolator
,以使动画的开始速度变慢,但是我仍然对结果不满意。
对我来说,下一步是尝试实现自定义TimeInterpolator
,以使动画的开始速度相同,而不管每个视图上的路径有多长,但是我无法用数学方法将箭头指向创建所需的公式。
valueAnimator = ObjectAnimator.ofFloat(this, PROGRESS, 0f, pathMeasure.length).apply {
duration = 500L
interpolator = TimeInterpolator { input ->
// formula here
}
}
对此的任何帮助都会得到好评。关于不同方法的任何建议。你觉得呢?
答案 0 :(得分:0)
1)正如我提到的,我将使用确定的ProgressBar并通过最大进度量(指定给特定视图的)来调节条宽度
2)我将使用ValueAnimator.ofFloat和自定义插值器并在其中设置进度
3)我将从AccelerateInterpolator扩展自定义插值器,使其看起来像这样:
class CustomInterpolator(val maxPercentage: Float) : AccelerateInterpolator(){
override fun getInterpolation(input: Float): Float {
val calculatedVal = super.getInterpolation(input)
return min(calculatedVal, maxPercentage)
}
}
其中maxPercentage是您应该占据的视图宽度的一部分(从0到1)
希望有帮助