Skip to content

How to interpret and translate a Lottie animation from Kotlin to Java?

I have been trying to translate this Kotlin code to Java since the project is in Java. I am translating by looking into Kotlin syntax. However, there are still others that I am having a hard time understanding.

https://github.com/airbnb/lottie-android/blob/master/LottieSample/src/main/kotlin/com/airbnb/lottie/samples/AppIntroActivity.kt

Specifically:

private val animationView: LottieAnimationView by lazy {
    rootView.inflate(R.layout.app_intro_animation_view, false) as LottieAnimationView
}

private val viewPager: LockableViewPager by lazy {
    findViewById<LockableViewPager>(R.id.intro_activity_viewPager)
}

override fun generateFinalButtonBehaviour(): IntroButton.Behaviour {
    return object : IntroButton.Behaviour {
        override fun setActivity(activity: IntroActivity) { finish() }
        override fun getActivity(): IntroActivity? = null
        override fun run() {}
    }
}

private fun setViewPagerScroller() {
    try {
        val scrollerField = ViewPager::class.java.getDeclaredField("mScroller")
        scrollerField.isAccessible = true
        val interpolator = ViewPager::class.java.getDeclaredField("sInterpolator")
        interpolator.isAccessible = true

        val scroller = object : Scroller(this, interpolator.get(null) as Interpolator) {
            override fun startScroll(startX: Int, startY: Int, dx: Int, dy: Int, duration: Int) {
                super.startScroll(startX, startY, dx, dy, duration * 7)
            }
        }
        scrollerField.set(viewPager, scroller)
    } catch (e: NoSuchFieldException) {
        // Do nothing.
    } catch (e: IllegalAccessException) {
        // Do nothing.
    }
}

For the setViewPagerScroller, I was able to translate the first part.

Field scrollerField = ViewPager.class.getDeclaredField("mScroller");
scrollerField.setAccessible(true);

Field interpolator = ViewPager.class.getDeclaredField("sInterpolator");
interpolator.setAccessible(true);

Answer

The method setViewPagerScroller uses kotlin anonymous inner class syntax. That is the ‘object’ part which has no real counterpart in java syntax.

private void setViewPagerScroller() {
    try {
        Field scrollerField = ViewPager.class.getDeclaredField("mScroller");
        scrollerField.setAccessible(true);

        Field interpolator = ViewPager.class.getDeclaredField("sInterpolator");
        interpolator.setAccessible(true);

        Scroller scroller = new Scroller(this, (android.view.animation.Interpolator) interpolator.get(null)){

            @Override
            public void startScroll(int startX, int startY, int dx, int dy, int duration) {
                super.startScroll(startX, startY, dx, dy, duration * 7);
            }
        }

        scrollerField.set(viewPager, scroller);
    } catch (NoSuchFieldException error) {
        // Do nothing.
    } catch (IllegalAccessException error) {
        // Do nothing.
    }
}

And the as keyword is like a casting in java. Hopefully you can use this to translate fun generateFinalButtonBehaviour(), it contains more of the same.

The Lazy construct unsurprisingly gets more verbose in java. You have to employ discipline to not access the viewpager wrongly if you choose to follow the structure below.

private LockableViewPager viewPager;

private LockableViewPager getViewPager(){
    if(viewPager == null){
        // produce viewpager and store in field
    }
    return viewPager;
}  

You can also use a class to more accurately represent a lazy initialization of your fields. (So that you cannot by mistake access a field which you meant to be lazily initialized) This gets even more verbose but could be worth it.