Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom transitions #93

Open
GVFiQst opened this issue Mar 1, 2019 · 3 comments
Open

Custom transitions #93

GVFiQst opened this issue Mar 1, 2019 · 3 comments

Comments

@GVFiQst
Copy link

GVFiQst commented Mar 1, 2019

Привет! На одном из моих проектов мне надо было анимировать смену TextView::textSize и я написал вот такой Transition. Может еще кому-то понадобится и поэтому решил создать pull request с ним (Он был написан на котлине. Но для ПР я его переписал на java)

import android.animation.Animator
import android.animation.ValueAnimator
import android.content.Context
import android.util.AttributeSet
import android.util.TypedValue
import android.view.ViewGroup
import android.widget.TextView
import androidx.transition.Transition
import androidx.transition.TransitionValues

class ChangeTextSize : Transition {

    constructor() : super()
    constructor(context: Context, attrs: AttributeSet) : super(context, attrs)

    override fun captureStartValues(transitionValues: TransitionValues) {
        captureValues(transitionValues)
    }

    override fun captureEndValues(transitionValues: TransitionValues) {
        captureValues(transitionValues)
    }

    private fun captureValues(transitionValues: TransitionValues) {
        if (transitionValues.view is TextView) {
            transitionValues.values[PROP_NAME] = (transitionValues.view as TextView).textSize
        }
    }

    override fun createAnimator(sceneRoot: ViewGroup, startValues: TransitionValues?, endValues: TransitionValues?): Animator? {
        if (startValues == null || endValues == null || startValues.view !is TextView || endValues.view !is TextView)
            return null

        val start = startValues.values[PROP_NAME] as? Float ?: return null
        val end = endValues.values[PROP_NAME] as? Float ?: return null
        if (start == end) return null

        val view = endValues.view as TextView

        return ValueAnimator.ofFloat(start, end)
                .apply { addUpdateListener { view.setTextSize(TypedValue.COMPLEX_UNIT_PX, it.animatedValue as Float) } }
    }

    companion object {
        private const val PROP_NAME = "ChangeTextSize.textSize"
    }
}

Неплохая идея собрать библиотеку с разными кастомными Transition!
Жду Вашего фид-бэка!

@andkulikov
Copy link
Owner

Привет! Спасибо за желание поделиться своим кастомным транзишном!

К сожалению конкретно про этот у меня есть сомнения и я не хотел бы иметь его частью библиотеки. Причина простая: не стоит анимировать вызов setTextSize, потому что он в том числе изменяет размер вьюхи и влечет за собой вызов requestLayout и весь парент лейаут и все следующие зависящие от его размера лейауты будут обязаны пройти через measure/layout цикл на каждом фрейме анимации и это не может работать оптимально и давать плавную анимацию. На быстрых флагманах это может быть незаментно и если конкретно под требования вашего проекта такая реализация подходит то все равно не стоит её продвигать как рекомендованную. Как бы я заимплементил подобное: создал бы кастомную вьюху где рисовал нужный текст прям на канвасе и на каждый шаг анимации только вызывал invalidate, где в onDraw применял новый размер, но это не меняло бы размер View.

Еще раз спасибо!

@GVFiQst GVFiQst changed the title ChangeTextSize transition Custom transitions Apr 11, 2019
@GVFiQst
Copy link
Author

GVFiQst commented Apr 11, 2019

Привет еще раз! Не хотел создавать отдельный ишю ведь тема та же. Я написал еще один простенький транзишн.

Как я писал вверху идея собрать либку с кастомными транзишнами очень хороша. Таким образом, если каждый хто писал транзишины кинет свои кастомные версии, другие разработчики не будут тратить время, а будуть иметь большой выбор транзишнов под рукой.

Вот он:

import android.animation.Animator
import android.animation.ValueAnimator
import android.view.ViewGroup
import android.widget.ProgressBar
import androidx.transition.Transition
import androidx.transition.TransitionValues

class ChangeProgress : Transition() {

    override fun captureStartValues(transitionValues: TransitionValues) {
        captureValues(transitionValues)
    }

    override fun captureEndValues(transitionValues: TransitionValues) {
        captureValues(transitionValues)
    }

    fun captureValues(values: TransitionValues) {
        (values.view as? ProgressBar)?.apply {
            values.values[PROP_NAME] = progress
        }
    }

    override fun createAnimator(sceneRoot: ViewGroup, startValues: TransitionValues?, endValues: TransitionValues?): Animator? {
        if (startValues == null || endValues == null || startValues.view !is ProgressBar || endValues.view !is ProgressBar)
            return null

        val start = startValues.values[PROP_NAME] as? Int ?: return null
        val end = endValues.values[PROP_NAME] as? Int ?: return null
        if (start == end) return null

        val view = endValues.view as ProgressBar

        return ValueAnimator.ofInt(start, end)
                .apply { addUpdateListener { view.progress = it.animatedValue as Int } }
    }

    companion object {
        const val PROP_NAME = "android:progress:progress"
    }
}

Создавать пулл реквест не тороплюсь, а буду ждать от Вас фидбека!

P.S.
Я знаю о том что есть метод ProgressBar.setProgress(progress: Int, animated: Boolean). Но он доступен только с 24 API.

@andkulikov
Copy link
Owner

Привет!
Я думаю в этом случае правильнее было бы использовать этот транзишн для версий до 24 Api, а начиная с него официальную функциональность. Причина простая: setProgress(animated = true) будет работать гораздо плавнее, он внутри анимирует прогресс как float, то есть не просто скачет по целым числам и прогресс выглядит плавнее. особенно это будет заметно когда прогресс меняется не слишком сильно, например с 10 до 15, если duration 300, то анимация будет состоять из примерно 18 фреймов, а реальных значений только 5.
Поэтому может не стоит делать и этот транзишн частью библиотеки, потому что я хочу в ней иметь только подходы, которые могу назвать рекомендованными. Здесь я бы или использовал этот транзишн до 24 апи, или вообще не имел никакой анимации до 24 апи, возможно это не критично для бизнеса, в виду малого количества пользователей на этих версиях.
Спасибо!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants