Hot questions for Using Lottie in animation

Question:

I have install pod files for Lottie and downloaded the hello.json file from lottiefiles.com

 LOTAnimationView *Hello_loader;
 Hello_loader = [LOTAnimationView animationNamed:@"hello"];
 [self.view addSubview:Hello_loader];

I had tried it in both viewDidLoad() and viewDidAppear() but still, it does not appear

I am new to this ios programming can anyone please help me to resolve this?. Thanks in advance...


Answer:

Swift 5 (with latest version of lottie)

    let animationView = AnimationView(name: "Bubbles") //Replace "Bubbles" with your animation file name.
    animationView.frame = CGRect(x: 0, y: 0, width: 150, height: 150)
    animationView.center = self.view.center
    animationView.loopMode = .loop
    animationView.backgroundBehavior = .pauseAndRestore //to pause in background and restart when it reach foreground
    self.view.addSubview(animationView)
    animationView.play()

Check output on this link

Question:

I added demo animation to the web using lottie, but the playback speed is too fast. How do I get to normal speed? The link below is a problem animation.

problem animation link : https://saybgm.github.io/Lottie_example/

My animation : https://youtu.be/CcHT7VgUF38

After Effect aep file : https://drive.google.com/file/d/1YGqgiuU-hU5Raq2WXu3r1ZrCANXB_Gw9/view?usp=sharing

my code

var animate = lottie.loadAnimation({
container: document.getElementById("hello"),
renderer: 'svg',
autoplay: true,
loop:true,
path: 'animation2.json'})

Answer:

I think the problem is inside the animation file, tried with the Lottiefiles preview, it looks the same as your code runs: https://www.lottiefiles.com/share/TNdLkQ

If you want to make it slower, call setSpeed (1 is the current speed, < 1 will make it slower):

var animate = lottie.loadAnimation({
  container: document.getElementById("hello"),
  renderer: 'svg',
  autoplay: true,
  loop:true,
  path: 'animation2.json'
});
animate.setSpeed(0.1);

From the document: http://airbnb.io/lottie/web/getting-started.html

Question:

I want this Lottie animation to exit after it finishes animating, then it should send me to the mainactivity

It's a splash screen, and I want it to load animation, finish animation, then send me to mainactivity.

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <com.airbnb.lottie.LottieAnimationView
        android:id="@+id/dd"
        android:layout_width="250dp"
        android:layout_height="150dp"
        android:layout_marginBottom="204dp"
        android:translationX="80dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="1.0"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:lottie_autoPlay="true"
        app:lottie_loop="true"
        app:lottie_rawRes="@raw/gold">

    </com.airbnb.lottie.LottieAnimationView>

    <com.airbnb.lottie.LottieAnimationView
        android:id="@+id/dd2"
        android:layout_width="440dp"
        android:layout_height="256dp"
        android:layout_marginBottom="124dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.965"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:lottie_autoPlay="true"
        app:lottie_loop="true"
        app:lottie_rawRes="@raw/luffy">

    </com.airbnb.lottie.LottieAnimationView>


</android.support.constraint.ConstraintLayout>

and here is my mainactivity

package com.example.myapplication;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.ProgressDialog;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.StrictMode;
import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.studioidan.httpagent.HttpAgent;
import com.studioidan.httpagent.StringCallback;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    private TextView textViewl;
    private RecyclerView recy;
    private TextView textView;
    private RecyclerView.Adapter mAdapter;
    private RecyclerView.LayoutManager layoutManager;
    private List<PersonUtils> personUtilsList;
    private int ints = 1;
    private DrawerLayout Mdrawer;
    private DatabaseTool databaseTool;

    private ArrayList<HashMap<String,Object>> listmap = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textViewl = (TextView) findViewById(R.id.textview1);
        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
        StrictMode.setThreadPolicy(policy);
        setTitle("Latest Chapters");
        databaseTool = new DatabaseTool();
        init();
    }
    public void init() {
        databaseTool.makeData(getFilesDir().getAbsolutePath(),"fav");
        recy = (RecyclerView) findViewById(R.id.recy);
        Mdrawer = (DrawerLayout) findViewById(R.id.drawer_layout) ;
        recy.setHasFixedSize(true);
        textView = (TextView) findViewById(R.id.titlead);
        layoutManager = new LinearLayoutManager(getApplicationContext());

        recy.setLayoutManager(layoutManager);

        personUtilsList = new ArrayList<>();
        final Document[] document = new Document[1];
        JSONArray array = new JSONArray();
        //Get Document object after parsing the html from given url.
        final ProgressDialog dialog = new ProgressDialog(this);
        dialog.setMessage("Please Wait...");
        dialog.setCancelable(false);
        dialog.show();
            JSONObject obj = new JSONObject();
            String url = "..." + ints;
            HttpAgent.get(url).
                    goString(new StringCallback() {
                        @Override
                        protected void onDone(boolean success, String results) {
                            dialog.cancel();
                            if (success) {
                                document[0] = Jsoup.parse(results);
                                //Get images from document object.
                                Elements images =
                                        document[0].select(".story-list").get(0).children();
                                //Iterate images and print image attributes.
                                int iss = images.size();
                                iss = --iss;
                                for (int i = 0; i <= iss; i++) {
                                    personUtilsList.add(new PersonUtils(images.get(i).getElementsByTag("img").attr("alt"),
                                            images.get(i).child(2).text(), images.get(i).getElementsByTag("img").attr("src"),images.get(i).child(0).attr("href")));
                                };
                                mAdapter = new CustomRecyclerAdapter(getApplicationContext(), personUtilsList);
                                recy.setAdapter(mAdapter);
                            } else {
                                showMessage(getErrorMessage());
                            }
                        }
                    });
        recy.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                if (!recyclerView.canScrollVertically(1)) {
                    ints = ints+1;
                    final ProgressDialog dialog = new ProgressDialog(MainActivity.this);
                    dialog.setMessage("Please Wait...");
                    dialog.setCancelable(false);
                    dialog.show();
                    JSONObject obj = new JSONObject();
                    String url = "..." + ints;
                    HttpAgent.get(url).
                            goString(new StringCallback() {
                                @Override
                                protected void onDone(boolean success, String results) {
                                    dialog.cancel();
                                    if (success) {
                                        List<PersonUtils> personUtils = new ArrayList<>();
                                        document[0] = Jsoup.parse(results);
                                        //Get images from document object.
                                        Elements images =
                                                document[0].select("").get(0).children();
                                        //Iterate images and print image attributes.
                                        int iss = images.size();
                                        iss = --iss;
                                        for (int i = 0; i <= iss; i++) {
                                            personUtils.add(new PersonUtils(images.get(i).getElementsByTag("img").attr("alt"),
                                                    images.get(i).child(2).text(), images.get(i).getElementsByTag("img").attr("src"),images.get(i).child(0).attr("href")));
                                        };
                                        int insertIndex = mAdapter.getItemCount();
                                        personUtilsList.addAll(insertIndex,personUtils);
                                        mAdapter.notifyItemRangeInserted(insertIndex, personUtils.size());
                                        showMessage(""+ints);
                                    } else {
                                        showMessage(getErrorMessage());
                                    }
                                }
                            });
                }
            }
        });
    }
    @SuppressLint("NewApi")
    public void showMessage(String s) {
        TextView te = new TextView(getApplicationContext());
        te.setText("<        "+s+"        >");
        LinearLayout layout2 = new LinearLayout(getApplicationContext());
        layout2.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
        layout2.setOrientation(LinearLayout.HORIZONTAL);
        layout2.setBackgroundResource(R.drawable.runded);
        layout2.setElevation(8);
        layout2.addView(te);
        Toast to = new Toast(getApplicationContext());
        to.setView(layout2);
        to.setDuration(Toast.LENGTH_SHORT);
        to.show();
    }
    @Override
    protected void onDestroy() {
       super.onDestroy();
       clearApplicationData();
            // Cancel running task(s) to avoid memory leaks
    }

    public void opendrwer(View view) {
        try {
            Mdrawer.openDrawer(Gravity.LEFT);
        } catch (Exception e) {
            Mdrawer.openDrawer(Gravity.RIGHT);
        }
    }


    public void opengenre(View view) {
        Intent intent = new Intent();
        intent.setClass(getApplicationContext(),GenreActivity.class);
        startActivity(intent);
    }
    public void clearApplicationData()
    {
        File cache = getCacheDir();
        File appDir = new File(cache.getParent());
        if (appDir.exists()) {
            String[] children = appDir.list();
            for (String s : children) {
                if (!s.equals("lib")) {
                    deleteDir(new File(appDir, s));
                    Log.i("TAG", "**************** File /data/data/APP_PACKAGE/" + s + " DELETED *******************");
                }
            }
        }
    }
    public static boolean deleteDir(File dir)
    {
        if (dir.isDirectory()) {
        String[] children = dir.list();
        for (int i = 0; i < children.length; i++) {
            boolean success = deleteDir(new File(dir, children[i]));
            if (!success) {
                return false;
            }
        }
    }
        return dir.delete();
    }

    public void clearcac(View view) {

    }

    public void openSpoilers(View view) {
        Intent ddd = new Intent();
        ddd.setClass(getApplicationContext(),Spoilers.class);
        startActivity(ddd);
    }
}

(did not include scraped urls)


Answer:

you can add listener to played animation

xml

<com.airbnb.lottie.LottieAnimationView
    android:id="@+id/lottieView"
    android:layout_width="440dp"
    android:layout_height="256dp"
    android:layout_marginBottom="124dp"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintHorizontal_bias="0.965"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:lottie_autoPlay="true"
    app:lottie_loop="false" // this is required to listen to end of animation
    app:lottie_rawRes="@raw/luffy">

code

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    LottieAnimationView lottieView=findViewById(R.id.lottieView);
    lottieView.addAnimatorListener(new Animator.AnimatorListener() {
        @Override
        public void onAnimationStart(Animator animator) {
        }

        @Override
        public void onAnimationEnd(Animator animator) {
            // do here the action you want 
        }
        @Override
        public void onAnimationCancel(Animator animator) {

        }
        @Override
        public void onAnimationRepeat(Animator animator) {

        }
    });


}

Question:

I have two separate questions in order to achieve the goal stated in the title.

The first question is: what's the visibility state of a com.airbnb.lottie.LottieAnimationView by default in the XML? I have used two different LottieAnimationView's in my XML with the same characteristics:

    <com.airbnb.lottie.LottieAnimationView
        android:id="@+id/lottie_animation_ribbon_and_confetti"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:lottie_autoPlay="false"
        app:lottie_fileName="exploding-ribbon-and-confetti.json"
        app:lottie_loop="true"
        app:lottie_repeatCount="1"/>

    <com.airbnb.lottie.LottieAnimationView
        android:id="@+id/lottie_cat_throws_cup"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintTop_toBottomOf="@id/puntuacionTotal"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toStartOf="@id/puntosAtrevimiento"
        app:layout_constraintBottom_toTopOf="@id/textoAtrevimiento"
        app:lottie_autoPlay="false"
        app:lottie_fileName="cat_throws_cup.json"
        app:lottie_loop="true"
        app:lottie_repeatCount="1"
        />

And while the first is only visible when I use lottieanimationview.playAnimation() from code, the second is immediately visible by default when the Activity starts.

My second question is due to the problem described in the first question. To solve this problem I first added android:visibility="gone" to those LottieAnimationViewthat were immediately visible when the activity started, and then I tried several pieces of code to make the animations visible when they were played and back to invisible after finished (all without success):

One attempt:

lottieCatThrowsCup.setVisibility(View.VISIBLE);
lottieCatThrowsCup.playAnimation();
if(!(lottieCatThrowsCup.isAnimating())) lottieCatThrowsCup.setVisibility(View.GONE);

Another attempt:

lottieCatThrowsCup.setVisibility(View.VISIBLE);
lottieCatThrowsCup.playAnimation();
if(!lottieCatThrowsCup.isAnimating())lottieCatThrowsCup.cancelAnimation();

Third attempt:

lottieCatThrowsCup.setVisibility(View.VISIBLE);
lottieCatThrowsCup.playAnimation();
lottieCatThrowsCup.cancelAnimation();

Fourth attempt:

lottieCatThrowsCup.setVisibility(View.VISIBLE);
lottieCatThrowsCup.playAnimation();
lottieCatThrowsCup.addAnimatorListener(this);
@Override
    public void onAnimationEnd(Animator animation) {

        animation.setVisibility(View.GONE);


    }

To my mind, the easiest solution would be to use an xml attribute on com.airbnb.lottie.LottieAnimationViewto indicate that it doesn't have to be visible by default unless it's played, but it doesn't seem to exist one... How would you guys solve this? Thanks in advance.


Answer:

There are other listeners as well that you can use to hide/show Lottie view.

mAddedToCartAnimation.addAnimatorListener(new Animator.AnimatorListener() {
        @Override
        public void onAnimationStart(Animator animation) {
            Log.e("Animation:","start");
            lottieCatThrowsCup.setVisibility(View.VISIBLE);
        }

        @Override
        public void onAnimationEnd(Animator animation) {
            Log.e("Animation:","end");
            lottieCatThrowsCup.setVisibility(View.GONE);
        }

        @Override
        public void onAnimationCancel(Animator animation) {
            Log.e("Animation:","cancel");
        }

        @Override
        public void onAnimationRepeat(Animator animation) {
            Log.e("Animation:","repeat");
        }
    });

Question:

I keep getting this error: Initializer for conditional binding must have Optional type, not 'LOTAnimationView' on the if let animationView = LOTAnimationView(name: "pop_heart") { line of code. I think the format of the code may be wrong. Can anyone guide me in the right direction? Thanks :)

override func viewDidLoad() {
    super.viewDidLoad()
    print("view loaded")

    if let animationView = LOTAnimationView(name: "pop_heart") {
        animationView.frame = CGRect(x: 0, y: 0, width: 400, height: 400)
        animationView.center = self.view.center
        animationView.contentMode = .scaleAspectFill
        animationView.loopAnimation = true
        animationView.animationSpeed = 0.5
        view.addSubview(animationView)

        animationView.play()
    }}

Answer:

Simply remove if let from your code. To use if let you must have an Optional variable.

override func viewDidLoad() {
    super.viewDidLoad()
    print("view loaded")

     animationView = LOTAnimationView(name: "pop_heart") 
     animationView.frame = CGRect(x: 0, y: 0, width: 400, height: 400)
     animationView.center = self.view.center
     animationView.contentMode = .scaleAspectFill
     animationView.loopAnimation = true
     animationView.animationSpeed = 0.5
     view.addSubview(animationView)
     animationView.play()
}

or if you want to use if let you can use if like this.

if let value = someMethodWhichReturnsAny as? String {
    //In above like there is a method which returns a string but in the form of type `Any` so I downcast it to String with optional and remove the nil case with if let
}