The practice of using the lottie library in the bank’s mobile application

    Hello, Habr!

    At one time, Product Owner asked us to think about creating an effective process for introducing animation into our android / ios application. At that time, we did the task of pre-filling the application with personal data for a loan product, and it took some time for the server to respond, during which we wanted to show a beautiful loading animation.


    The task was clear: the designer wanted to draw beautifully, to give the source code directly to both
    platforms without any dodging on his part, and so that this would not lag on old devices (yes, we still support android 4.1).

    What were my options for introducing animation:

    1. Pens using animated vector drawable. The advantages are that rendering works
      in a separate stream (starting with api 25), the minuses are the complexity of creating such animations and the small number of manipulations with objects. For simple animations, this all works well, but a little more complicated, and hell begins. Yes, and on different platforms you will not start.
    2. Gif - they weigh a lot, have a fixed size, which means they do not scale normally. And you won’t do any special manipulations with them.
    3. The png sequence (no comment).

    Having dug for a while towards the native vector animation of the android and gif (oh my god, we still considered this option), I remembered the wonderful Lottie library, and showed it to my colleagues.

    After some tests with various devices, we decided that the library should be implemented, especially since its capabilities were impressive. The designer was especially delighted, now he could do almost any animation in Adobe After Effects, and export to a json file with a few clicks. We were delighted too, but first things first.

    Lottie was invented and implemented by Airbnb in response to a growing demand for cross-platform animation, so it works equally (well, almost) on all platforms. The developers themselves claim that their goal is to realize the maximum number of After Effects features, and they succeeded in this. Now embedding Lottie animation is as easy as inserting a picture into ImageView.

    Key 3 classes:

    1. LottieAnimationView is the successor to ImageView, and the easiest way to use animation. You can describe the animation in xml, or you can in the code, most methods are supported.
    2. LottieDrawable - Drawable descendant, with the same functionality as the previous class, allows you to apply animation to any view.
    3. LottieComposition и его спутник LottieCompositionFactory позволяют предварительно загружать анимацию из различных источников и применять к LottieDrawable и LottieAnimationView.

    Загрузка ресурсов


    Поддерживается загрузка ресурсов из:

    1. res/raw
    2. src/assets
    3. Json строки
    4. Любого url из сети, ведущего на json или zip файл (реализуется через HttpURLConnection, чтобы не добавлять внешних зависимостей. Если у вас анимация с изображениями, то нужно использовать zip)
    5. InputStream json или zip файла

    Кэширование анимации


    The cool thing is that all animations downloaded via res / raw or assets are saved by the LRU cache, which allows us not to waste user time reloading and parsing the animation, since in the case of complex animations it may take some time. What's even cooler, if you need to pre-load the animation, and then in the next fragment display the animation instantly, you can use the code

    LottieCompositionFactory.fromRawRes(context, rawFile)

    The animation is cached using the rawFile key, and where you really need to use it, it starts almost instantly.

    Progress management


    Lottie allows you to set the current animation state through setProgress (...). This can come in handy if you want to animate the file upload status, scroll position, various gestures, etc. I saw various implementations on BottomSheets, PullToRefresh, CollapsingToolbarLayout.

    Here's how to use progress with AppBarLayout:

    
    appBarLayout.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener
    { appBarLayout, verticalOffset ->
      val percent = Math.abs(verticalOffset).toFloat()/appBarLayout.totalScrollRange
      animationView.progress = percent
    })
    

    Looping


    Lottie supports looping setRepeatMode () or setRepeatCount () not only the whole animation, but also any fragment within (0.0 ... 1.0). This is implemented by the properties setMinFrame, setMaxFrame, setMinAndMaxFrame. We used this so as not to implement 3 animations for different file upload states: idle, progress, complete. Here is a small piece of code that solves this:

    
    when (loadingStatus) {
      LoadingStatus.IDLE -> {
        animationView.setMaxProgress(0.1f)
      }
      LoadingStatus.PROGRESS -> {
        animationView.setMinAndMaxProgress(0.2f, 0.9f)
        animationView.repeatCount = LottieDrawable.INFINITE
        animationView.playAnimation()
      }
      LoadingStatus.COMPLETE -> {
        animationView.setMinAndMaxProgress(0.9f, 1f)
        animationView.repeatCount = 1
        animationView.playAnimation()
    }}


    Images


    One of the main advantages of Lottie for us was that the library supports the insertion of pictures directly into the animation. Moreover, you can insert both a static image and a dynamic one downloaded from the Internet. Now I will explain how it works.

    In the case of a static picture, everything is simple: the designer unloads the archive containing json plus the picture itself.

    {
    "v": "5.1.13",
    "fr": 29.9700012207031,
    "ip": 0,
    "op": 47.0000019143492,
    "w": 1034,
    "h": 1334,
    "nm": "Композиция 1",
    "ddd": 0,
    "assets": [
        {
         "id": "image_0",
         "w": 130,
         "h": 436,
         "u": "images/",
         "p": "img_0.png"
         },
         {
         "id": "comp_0",
         "layers": [
              ...
         ]}]
    }

    This img_0.png, this is the picture that you should put in src / assets, and which will be inside the animation.

    For dynamic loading, the setImageAssetDelegate method is used, to which you must pass the bitmap. We preload the image with Glide, so at the stage of opening a fragment with animation and a picture, everything gets out of the cache, so everything is pretty fast. Here is the code:

    
    glideLoader.loadAsBitmap(imageUrl).into(object: CustomTarget() {
      override fun onResourceReady(resource: Bitmap, transition: Transition?) {
         viewAnimation.setImageAssetDelegate(object: ImageAssetDelegate {
           override fun fetchBitmap(asset: LottieImageAsset?): Bitmap {
             asset?.let {
               val resizeBitmap =Bitmap.createScaledBitmap(resource, it.width, it.height, true);
                 return resizeBitmap
               } ?: run {
                 return resource
               }
             }
           })
        setAnimation(viewAnimation, animationImage)
      }
      override fun onLoadCleared(placeholder: Drawable?) {}
    })
    


    Performance


    Of course, it is better not to use a lot of animation on screens where the user spends a lot of time, since it is demanding on the processor. According to our tests, the processor load on some animations reaches 20%. Therefore, the ideal case of such an animation is interactive elements that fire once.

    If animation on some devices slows down, sometimes it helps

    viewAnimation.useHardwareAcceleration(true)

    However, developers recommend using this method with caution, since different phones use hardware acceleration in different ways, so instead of acceleration, you can get the opposite effect.

    Conclusion


    In general, the use of the Lottie library greatly simplifies the implementation of animation in the application.

    The main advantages of lottie that we highlighted:

    1. Small library size (300 kb)
    2. Cross-platform solution ios / android / web
    3. Download animations from the web
    4. Progress management and looping anywhere
    5. A large number of features from after effects allows the designer to realize the intended effect.

    Minuses:

    1. Rendering is done in the main thread, and fps can drop significantly in the application.
    2. Parsing lottie animations can take considerable time with complex animations.


    By the way, to check how resource-intensive animation is, you can use the official Lottie app from Google Play . There is a Render Graph where you can see the time for rendering a frame, and also see how the animation will look if you cut it into frames, or how hardwareAcceleration and much more will affect.

    Also popular now: