Complex UI with FastGrid for Xamarin.Forms

Slava Chernikoff

This guest post was contributed by Slava Chernikoff (Principal Engineer at Binwell,  Microsoft MVP, Xamarin Certified Mobile Developer), Artem Tischenko (Xamarin developer at Binwell) and Kirill Ashikhmin (Xamarin and Android developer at Binwell).

Introduction 

Binwell’s team members have a long history of using Xamarin and were very excited to adopt Xamarin.Forms 1.0 for real projects. One day in 2015, we got a task to make a mobile marketplace application. An application that should have a complex user interface with many different components and a large product data set.

This application should be able to display hundreds of products, banners and other controls on one page. There should be an almost infinite scrolling with many products, banners, special sections (favorite, discounted items, etc). That was the beginning of our story to adopting Android RecyclerView and iOS UICollectionView for Xamarin.Forms.

A Complex UI with FastGrid

In this article, we will focus on one of our favorite projects: Instamart grocery delivery service for Russian customers. Here are screenshots of the current Instamart application based on Xamarin.Forms and Binwell FastGrid.

Instamart application based on Xamarin.Forms

Notes: We are very excited with Xamarin.Forms evolution and the upcoming Xamarin.Forms 4.0. New CollectionView. FastGrid was created for another set of tasks and distributed ‘as is’.

This article will show how to use FastGrid for complex user interfaces with many cell view types. Binwell FastGrid can be adopted by teams with native experience and used as a customizable white box component.

1. Searching for the solution

When we started our research on Xamarin.Forms controls for complex UI, our first thought was using Grid and Stack Layouts. Obviously, performance was very poor because these layouts were created for another task. The main drawback of layout components is that they don’t reuse child views while creating all of the views when the layout is displayed. That is why it can be near impossible to deal with a large number of child views with Grid, StackLayout, etc.

As a second step, we tried to use the default ListView component to display a number of cells in one row. It was much better than using Layouts (including a 3rd party RepeaterView), however, it still had performance drawbacks and issues with scrolling. Horizontal scroll implementation inside a row was a bit tricky, while vertical scrolling lagged on low-end Android devices. So we continued our research.

We tried a number of commercial Xamarin.Forms components based on RecyclerView/UICollectionView, though most of them were limited and didn’t provide the necessary functionality.

Then we found a great sample by Twin Technologies (TwinTechs): Debunking the great Xamarin XAML myth: how to achieve native performance with Xamarin Forms ListView and Xaml cells

TwinTechs FastGrid implementation was very promising. Although it didn’t work on Android and had a lot of limitations out-of-box, it was a great starting point. We used this FastGrid control as a white box (just add files directly to project) and improved significantly over the last 3 years. Many thanks to TwinTechs for such a great idea and implementation!

2. Meet the FastGrid

First, our goal was an implementation of a complex user interface for our client’s application. We didn’t try to implement a universal CollectionView component for all possible cases and scenarios. Instead, we just tried to get a single result and it worked! Slava Chernikoff was focused on iOS implementation, and later Kirill Ashikhmin adopted it for Android.

2.1 How it Works?

Let us remind you of the task at hand – getting a complex UI with many different view types, horizontal scrolling, and the fastest possible vertical scrolling. It also had to be data driven from a backend API (show and hide views depending on data models received from the backend).

The first point was to achieve maximum scrolling performance. Leading us to skip dynamic cell sizing and use hard-coded width/height for every ViewCell type. The second point was handling many cell types. Which is why we used DataTemplateSelector for all of these tasks.

FastGridTemplateSelector

The diagram above demonstrates using of DataTemplateSelector for making a complex UI based on data from backend API.

2.2 Current Binwell FastGrid Features

Below is a brief feature list of the Binwell FastGrid:

  • Use a large number of cell types
  • Every cell type is related to the data model (including sections)
  • Using of Flow Layouts to deal with layout inside RecyclerView and UICollectionView
  • Support for dynamic data adding/updating/removing, including LoadMore feature
  • Pull-to-refresh features

Complete source code and sample are available through this Binwell FastGrid GitHub

3. How to use FastGrid

To demonstrate the usage of Binwell FastGrid, let’s start with a common mobile marketplace case: displaying a grouped products list in 2 columns.

FastGrid Sample

In general, use of FastGridView is similar to ListView – you will need to create a custom ViewCell:

    public class ProductCell : FastGridCell
    {
        CachedImage _image;
        Label _name;
        Label _price;

        protected override void InitializeCell()
        {
            var screenWidth = Device.Info.ScaledScreenSize.Width;

            _image = new CachedImage
            {
                HorizontalOptions = LayoutOptions.Center,
                Aspect = Aspect.AspectFill,
                WidthRequest = screenWidth / 2 - 40,
                HeightRequest = screenWidth / 2 - 40
            };

            _name = new Label
            {
                HorizontalOptions = LayoutOptions.Center,
                FontSize = 20,
                TextColor = Color.Black
            };

            _price = new Label { HorizontalOptions = LayoutOptions.Center,
                FontSize = 14,
                TextColor = Color.Black
            };

            View = new StackLayout
            {
                BackgroundColor = Color.White,
                Padding = 20,
                VerticalOptions = LayoutOptions.FillAndExpand,
                HorizontalOptions = LayoutOptions.FillAndExpand,
                Children =
                {
                    _image,
                    _name,
                    _price
                }
            };
        }

        protected override void SetupCell(bool isRecycled)
        {
            if (!(BindingContext is ProductObject bindingContext)) return;

            _image.Source = null;
            _image.Source = bindingContext.ImageUrl;
            _name.Text = bindingContext.Name;
            _price.Text = bindingContext.Price;
        }
    }

As you can see, you should implement custom InitializeCell() and SetupCell() methods. The example above demonstrates code-behind UI creation, but you can also use XAML and Bindings by placing InitializeComponent() inside InitializeCell(). Additionally, you can use the SetupCell() method for manually setting of new values. In some cases it lets you fine-tune your data or UI.

Then create a FastGridTemplateSelector:

           var size = Device.Info.ScaledScreenSize;
           fastGridView.ItemTemplateSelector = new FastGridTemplateSelector(
               new FastGridDataTemplate(typeof(CategoryObject).Name, 
                              typeof(CategoryCell),new Size(size.Width, 70)),
               new FastGridDataTemplate(typeof(ProductObject).Name, 
                              typeof(ProductCell),new Size(size.Width / 2, 260))
           );

Create a new FastGridDataTemplate to configure a relationship between the model (data object) and view types. As mentioned earlier, to speed up the scrolling performance we set exact view sizes depending on model type. It’s not very flexible, but also does not require heavy cell size calculations.

Android RecyclerView requires integer numbers to identify different view types. That is why FastGridTemplateSelector use Prepare() method to populate a DataTemplateViewTypes dictionary. Below you can see more samples of using FastGrid.

If you are familiar Russian and want to see FastGrid in action, check out the Instamart applications in:

Future works

We are constantly improving FastGrid with every project by adding app-specific features. Additionally, there are a number of things to do in future updates:

  1. Don’t use ViewRenderer
  2. Don’t use Xamarin.Forms.Internals
  3. Implement ColumnSpacing and RowSpacing for iOS
  4. Dynamic cell sizing

Many thanks for TwinTechs for initial project and ideas!  

You can find Binwell FastGrid and sample here: https://github.com/Binwell/FastGrid

Stay tuned!

1 comment

Discussion is closed. Login to edit/delete existing comments.

  • Nicke Manarin 0

    Is the app (Instamart) open source in anyway (at least the UI)?
    The interface is beatiful and I wish to learn how to do the same.

Feedback usabilla icon