暂停ObjectAnimator的进度

时间:2018-10-12 02:55:09

标签: android kotlin android-animation objectanimator

我正在实现一个自定义视图,该视图绘制某种ProgressBar视图,并以两个视图作为参数(起点和终点)。像这样:

enter image description here

这是完整的课程:

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毫秒内完成。它们不会在距原点相同的距离处暂停:

enter image description here

我尝试从LinearInterpolator切换到AccelerateInterpolator,以使动画的开始速度变慢,但是我仍然对结果不满意。

enter image description here

对我来说,下一步是尝试实现自定义TimeInterpolator,以使动画的开始速度相同,而不管每个视图上的路径有多长,但是我无法用数学方法将箭头指向创建所需的公式。

valueAnimator = ObjectAnimator.ofFloat(this, PROGRESS, 0f, pathMeasure.length).apply {
        duration = 500L
        interpolator = TimeInterpolator { input ->
            // formula here
        }
    }

对此的任何帮助都会得到好评。关于不同方法的任何建议。你觉得呢?

1 个答案:

答案 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)

希望有帮助