Приостановить выполнение ObjectAnimator - PullRequest
0 голосов
/ 12 октября 2018

Я реализую пользовательский вид, который рисует какой-то вид 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 голосов
/ 12 октября 2018

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), которую должна занимать полоса

Надеюсь, это поможет

...