airbnb / lottie-android

Render After Effects animations natively on Android and iOS, Web, and React Native

Home Page:http://airbnb.io/lottie/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Cannot render when using LottieDrawable without setting bounds with SOFTWARE rendering

CodeReadOnlyUser opened this issue · comments

Lottie is supported and developed on nights and weekends. Issues from Lottie sponsors will be prioritized.

Describe the bug

When using RenderMode.SOFTWARE or renderMode not specified. LottieDrawable without setting bounds before resumeAnimation() cannot be rendered using lottieDrawable.draw(canvas) on devices with Android version < Oreo (API 26)

When using RenderMode.HARDWARE or devices with Android version >= Oreo (API 26). LottieDrawable without setting bounds before resumeAnimation() will be rendered. The bounds will be lottieDrawable.composition.bounds

What version of Lottie did you test this on?
implementation("com.airbnb.android:lottie:6.4.0") and some older versions.

What version of Android did you test this on?
Android API 23, API 25, API 26, API 32, API 34

Steps To Reproduce
Steps to reproduce the behavior:

Custom drawable with lottie example:

class CustomLottieDrawable(val view: View) : Drawable() {

    //constants
    private val size = 600
    private val lottieAssetName = "Lottie Logo 1.json"

    private val lottieDrawable: LottieDrawable = initLottieDrawable()

    //keep reference here, or callback will be recycled
    private var refreshCallback: Callback? = null


    init {
        this.bounds = Rect(0, 0, size, size)
        //⚠️
        //lottieDrawable.bounds = Rect(0, 0, size, size)
        lottieDrawable.resumeAnimation()
    }

    override fun draw(canvas: Canvas) {
        lottieDrawable.draw(canvas)
    }

    override fun setAlpha(alpha: Int) {}

    override fun setColorFilter(colorFilter: ColorFilter?) {}

    override fun getOpacity(): Int = PixelFormat.TRANSLUCENT

    private fun initLottieDrawable(): LottieDrawable {
        val lottieDrawable = LottieDrawable()
        this.refreshCallback = object : Callback {
            override fun invalidateDrawable(who: Drawable) {
                view.invalidate()
            }

            override fun scheduleDrawable(who: Drawable, what: Runnable, `when`: Long) {}
            override fun unscheduleDrawable(who: Drawable, what: Runnable) {}
        }
        lottieDrawable.callback = this.refreshCallback
        val result = LottieCompositionFactory.fromAssetSync(view.context, lottieAssetName).value
        lottieDrawable.composition = result
        lottieDrawable.repeatCount = LottieDrawable.INFINITE
        //⚠️
        //lottieDrawable.renderMode = RenderMode.HARDWARE
        return lottieDrawable
    }


}

Then, setting this CustomLottieDrawable as some view's background.

Uncomment any lines with ⚠️ comment to render properly on pre Android Oreo devices.

Additional information:

When debugging using lottieDrawable.toBitmap(,,), the bitmap is the correct rendered image. So I am wondering why renderMode and Android version can cause different render result.

Solution
Set lottieDrawable.bounds before calling lottieDrawable.resumeAnimation()

Screenshots
Nothing visible

This is not surprising because with render mode software, the canvas is backed by a bitmap which inherently has bounds due to the bitmap and there is nothing Lottie can do to render beyond that.

with render mode software

I tested again on devices with Android >= 8.0. If SOFTWARE rendering is manually enabled, nothing is rendered. So the real behavior is LottieDrawable without setting bounds will not be visible in SOFTWARE rendering mode.

And the reason why HARDWARE rendering is used starting from Android Oreo can be found here.

return sdkInt <= Build.VERSION_CODES.N_MR1;

Thanks for your answer🙏

@CodeReadOnlyUser It not being visible doesn't sound right. Can you create a project that repros this?