Animation in Xamarin Forms with Airbnb Lottie

When it comes to animation, I think Lottie library from Airbnb is one of the most recommended free libraries available out there. It’s easy to use, light weight, and most importantly, can be used across platforms, including Xamarin Forms. So, in this post, I want to do a little introduction how to use this library, and I gonna using some animations that already available at LottieFiles.

Lottie Nuget Package

To start using this library, it’s actually pretty simple. Just go to NuGet Package Manager, look for NuGet called Com.Airbnb.Xamarin.Forms.Lottie and then install it. After you finish installing, you gonna see a readme text, looks like the picture below.

From that readme text, we already get example that cover some of most important events that can be handled by Lottie. It can handle a lot more, but for starter, I will discuss those three main events handler. I will walk you through it by giving simple example how to use it.

Animation Event Handlers

Base of its name, I think you’re already able to guess what function for each handler. PlaybackStartedCommand will be triggered when the animation start playing, in the other hand, PlaybackFinishedCommand triggered at animation finished. And if by any chance user click or tap on the AnimationView, ClickedCommand will handle it. 

I made a simple example to simulate that process. I created a program to show some animations. When the animation start animating, it gonna display the name of the animation file. When it finished, it gonna show how many times the animation already played. And then when user clicking, we gonna play another animation. You can see the sample code below.

public class LottieAnimationViewModel : BaseViewModel
{
    private string animationName;
    public string AnimationName
    {
        get => animationName;
        set => SetProperty(ref animationName, value);
    }

    private string animationPlayed;
    public string AnimationPlayed
    {
        get => animationPlayed;
        set => SetProperty(ref animationPlayed, value);
    }

    private int currentAnimation { get; set; }
    private int played { get; set; }
    private List<string> animationList { get; set; } 

    public ICommand PlayingCommand { get; set; }
    public ICommand FinishedCommand { get; set; }
    public ICommand ClickedCommand { get; set; }

    public LottieAnimationViewModel()
    {
        currentAnimation = 0;
        played = 0;
        animationList = new List<string>() 
        {
            "check_animation.json", "idea_bulb.json", "washing_machine.json"
        };
        AnimationName = animationList[currentAnimation];
        AnimationPlayed = SetAnimationPlayed(played);

        MessagingCenter.Send(this, "play");

        PlayingCommand = new Command(Playing);
        FinishedCommand = new Command(Finished);
        ClickedCommand = new Command(Clicked);
    }

    private void Playing()
    {
        AnimationName = animationList[currentAnimation];
    }

    private void Finished()
    {
        played++;
        AnimationPlayed = SetAnimationPlayed(played);
        MessagingCenter.Send(this, "play");
    }

    private void Clicked()
    {
        if (currentAnimation < 2)
            currentAnimation++;
        else
            currentAnimation = 0;

        played = 0;
        AnimationPlayed = SetAnimationPlayed(played);
        MessagingCenter.Send(this, "play");
    }

    private string SetAnimationPlayed(int number)
    {
        return $"Animation Played {number} times";
    }
}

You can see the complete source code of that example in my Github repo. If you run the code, it will look like the video below.

Handling Images

One little note before I end this post. When I tried this library in my project, one thing that little bit tricky is how to handle images. There’s a difference where to put it in Droid and iOS project. In Droid project, you put your JSON animation file in folder Asset. And if you have images, you have to create folder inside Asset to store the images. In Animation View you have to reference ImageAsset property to that folder. But in iOS project, unlike Android, you have to store both JSON file and images in Resources folder. It’s not gonna work if you create another folder inside resources to store your image . Your iPhone won’t show the images.

I think that’s all for this post. You can always refer to my Github for complete code and feel free to ask, Thank you.

Credit Animation

Sample Animations from LottieFiles

Washing Machine and idea bulb by Mohit Saini

Check animation by Joshua Oluwagbemiga 

Create your own Animated Bottom Picker

OK guys, I’m still playing around in animation in Xamarin, so in this post I want to try out two other animation functions, which are TranslateTo and FadeTo. In order to do that, I created my own picker that comes up from the screen’s bottom , just like picker you would get if you used Swift or React Native. The picker itself would not really looks similar like the picker in that platforms but it would kinda works like them. My goal in this post will be just exploring different kind of animation in Xamarin. In my last post, I already used RotateTo for accordion list view which was awesome and I’m exited to dig deeper about this stuff. So, let’s begin.

Absolute Layout

First thing first, we need to create a layout that enable us to put our “picker” outside the screen when the app started because the picker will be showing up from the bottom of the screen. So, I used Absolute Layout to put some elements off the screen. If you are not familiar with Absolute Layout, basically anything you put inside this layout can have 2 important properties. First, LayoutBonds which takes 4 parameters, X position, Y position, Width and Height. Second, LayoutFlags which is the setting of the LayoutBound, whether you want to use pixel or screen proportion for those 4 parameters. You can read the complete explanation in the documentation, in this post I will only discuss what I did with my absolute layout. So, let’s take a look at the code first.

BottomPickerCode

So, I put everything inside absolute layout, but I only used absolute layout’s properties in two elements. First, in a BoxView, which I used to the background of the picker. I set layout flag to All, means the layout bound will be the screen’s proportion. With the layout bound 0,0,1,1; I put the background in upper left corner (0,0) and I set it as big as the screen (1,1). I’ll do the same for the Frame, which will be the picker and contain a list view. I just set different proportion to make it bellow the screen and has half of the screen size. For user interaction, I only used familiar function like entry’s Focused, list view’s ItemSelected and also GestureRecognizer for the box view. Now, let’s move to code behind and add some animations into our screen.

The Animation

I created two methods, Show_Picker and Hide_Picker to execute the animation that will be accessed from our event handlers. Here’s the code.

public partial class PickerButtomPage : ContentPage
{
    public ObservableCollection CountryList;

    public PickerButtomPage()
    {
        InitializeComponent();
        CountryList = new ObservableCollection()
        {
            new Country("Indonesia"),
            new Country("India"),
            new Country("United States"),
            new Country("Brazil"),
            new Country("United Kingdom")
        };
        PickerContry.ItemsSource = CountryList;
    }

    void Handle_ItemTapped(object sender, ItemTappedEventArgs e)
    {
        ((ListView)sender).SelectedItem = null;
    }

    void Handle_ItemSelected(object sender, SelectedItemChangedEventArgs e)
    {
        if (e.SelectedItem == null)
            return;

        Country country = e.SelectedItem as Country;
        EntryCountry.Text = country.Name;

        Hide_Picker();
    }

    void Handle_Tapped(object sender, EventArgs e)
    {
        Hide_Picker();
    }

    void Handle_Focused(object sender, FocusEventArgs e)
    {
        Show_Picker();
    }

    void Show_Picker()
    {
        Background.FadeTo(0.4, 500, Easing.SinIn);
        PickerFrame.TranslateTo(0, -300, 500);
    }
void Hide_Picker()
    {
        Background.FadeTo(0, 500, Easing.SinOut);
        PickerFrame.TranslateTo(0, 300, 500);
        EntryHide.Focus();
    }
}

public class Country
{
    public Country(string name){ Name = name; }
    public string Name { get; set; }
}

So in Show_Picker, I faded in the background (box view) into opacity 0.4 in 0.5 second. Meanwhile I also moved the Frame Picker 300 pixels up, also in 0.5 second. I did the other way around for the Hide_Picker and then added one line to remove focus from the Entry.

Basically, this how my picker works. I trigger the picker to show up when the country entry is focused . Then when user choose one country or hide the picker by clicking the background, I set the focus to another entry I hide in the screen to prevent the user to type manually to the entry. And if it works as expected, it will look like this.

Adding Animation to Accordion ListView

So, I just started learning about animation in Xamarin. I read the documentation and want to try implementing it. Because I’m new at this stuff, I wanna start with something simple. I modified one of my old post about accordion list view by adding little animation to it. If you’ve read that post, you will know that when I expand the list view, I changed the down arrow icon to up arrow icon. And when I collapse the list view, I do the otherwise. The icon changing process just happen as it is, without any effect or animation on it. I want to change that. I want to add a rotate animation when the icon changing happen. So, let’s do that.

Image Gesture Recognizer

First thing we need to is switching the trigger of expanding list view event. Back then I used List View Item Tapped event, but now, because I want to rotate the arrow icon, I need to put the trigger in Image view where the arrow icon is. So, I add Image Gesture Recognizer to the Image view. It’s look like this.

animated accordion

With this gesture recognizer, I can get the current Image view being tapped by user so I can handle it properly in code behind. In code behind, all I need to is just rotate the image and call function in view model to expand or collapse the list view. I rotate the image 180 degree and for 0,5 second.

public partial class AccordionCountriesPage : ContentPage
{
    AccordionCountriesViewModel viewModel;
    public AccordionCountriesPage()
    {
        InitializeComponent();
        BindingContext = viewModel = new AccordionCountriesViewModel();
    }

    void Handle_ItemTapped(object sender, ItemTappedEventArgs e)
    {
        //Country mCountry = (Country)e.Item;
        //viewModel.ShowCities(mCountry);
        ListView listView = sender as ListView;
        listView.SelectedItem = null;
    }

    async void Handle_Tapped(object sender, EventArgs e)
    {
        Image image = sender as Image;
        await image.RotateTo(180, 500);
        Grid grid = image.Parent as Grid;
        Label label = grid.Children[0] as Label;
        viewModel.ShowCities(label.Text);
    }
}

A little bit downside from this method is I don’t get the whole Country class like I did when I was using List View Item Tapped. But I’m still able to know which country user tapped by accessing the label which contain the country’s name. By doing this, it means I also need little modification to the view model as well. This is how the view model look like now. I only updated the ShowCities method.

public class AccordionCountriesViewModel : BaseViewModel
{
    private CustomObservableCollection countries;
    public CustomObservableCollection Countries
    {
        get => countries;
        set => SetProperty(ref countries, value);
    }

    public AccordionCountriesViewModel()
    {
        ObservableCollection USACities = new ObservableCollection()
        {
            new City(){ CityName = "Washington DC" },
            new City(){ CityName = "New York" },
            new City(){ CityName = "Los Angeles" }
        };

        ObservableCollection ChinaCities = new ObservableCollection()
        {
            new City(){ CityName = "Beijing" },
            new City(){ CityName = "Shanghai" },
            new City(){ CityName = "Shenzhen" }
        };

        ObservableCollection RussiaCities = new ObservableCollection()
        {
            new City(){ CityName = "Moscow" },
            new City(){ CityName = "St. Peterburg" },
            new City(){ CityName = "Kazan" }
        };

        countries = new CustomObservableCollection()
        {
            new Country(){ CountryName = "USA", IsChildrenVisible = false, Cities = USACities },
            new Country(){ CountryName = "China", IsChildrenVisible = false, Cities = ChinaCities },
            new Country(){ CountryName = "Russia", IsChildrenVisible = false, Cities = RussiaCities },
        };
    }

    public void ShowCities(string countryName)
    {
        Country country = Countries.SingleOrDefault(c => c.CountryName == countryName);
        country.IsChildrenVisible = !country.IsChildrenVisible;
        Countries.ReportItemChange(country);
    }
}

Let’s rotate it!

Nah, now we can run the project again and see how our arrow rotating.

 

Credit :

  • Arrow Icons from FlatIcon, Down Arrow icon by Freepik, Right Arrow icon by GraphicsBay, Up Arrow icon by Hadrien