{"id":38508,"date":"2019-01-30T12:56:02","date_gmt":"2019-01-30T17:56:02","guid":{"rendered":"https:\/\/blog.xamarin.com\/?p=38508"},"modified":"2019-03-25T13:12:08","modified_gmt":"2019-03-25T21:12:08","slug":"complex-ui-with-fastgrid-for-xamarin-forms","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/xamarin\/complex-ui-with-fastgrid-for-xamarin-forms\/","title":{"rendered":"Complex UI with FastGrid for Xamarin.Forms"},"content":{"rendered":"<p>\t\t\t\t<em>This guest post was contributed by Slava Chernikoff (Principal Engineer at\u00a0<a href=\"https:\/\/binwell.com\/\">Binwell<\/a>,\u00a0 Microsoft MVP, Xamarin Certified Mobile Developer), Artem Tischenko (Xamarin developer at <a href=\"https:\/\/binwell.com\/\">Binwell<\/a>) and Kirill Ashikhmin (Xamarin and Android developer at <a href=\"https:\/\/binwell.com\/\">Binwell<\/a>).<\/em><\/p>\n<h2><span style=\"font-weight: 400\">Introduction\u00a0<\/span><\/h2>\n<p><span style=\"font-weight: 400\">Binwell\u2019s 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. <\/span><\/p>\n<p><span style=\"font-weight: 400\">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.<\/span><\/p>\n<h2>A Complex UI with FastGrid<\/h2>\n<p><span style=\"font-weight: 400\">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. <\/span><\/p>\n<p><img decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/binwelldata.blob.core.windows.net\/data\/instamart_1.png\" alt=\"Instamart application based on Xamarin.Forms\" \/><\/p>\n<p><i><span style=\"font-weight: 400\">Notes: We are very excited with Xamarin.Forms evolution and the\u00a0<a href=\"https:\/\/blog.xamarin.com\/xamarin-forms-4-0-feature-preview-an-entirely-new-point-of-collectionview\/\">upcoming Xamarin.Forms 4.0. New CollectionView<\/a>. FastGrid was created for another set of tasks and distributed &#8216;as is&#8217;.<\/span><\/i><\/p>\n<p><span style=\"font-weight: 400\">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. <\/span><\/p>\n<h3><span style=\"font-weight: 400\">1. Searching for the solution<\/span><\/h3>\n<p><span style=\"font-weight: 400\">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\u2019t 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.<\/span><\/p>\n<p><span style=\"font-weight: 400\">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.<\/span><\/p>\n<p><span style=\"font-weight: 400\">We tried a number of commercial Xamarin.Forms components based on RecyclerView\/UICollectionView, though most of them were limited and didn\u2019t provide the necessary functionality.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Then we found a great sample by Twin Technologies (TwinTechs): <\/span><a href=\"http:\/\/twintechs.com\/debunking-the-great-xamarin-xaml-myth-how-to-achieve-native-performance-with-xamarin-forms-listview-and-xaml-cells\/\"><span style=\"font-weight: 400\">Debunking the great Xamarin XAML myth: how to achieve native performance with Xamarin Forms ListView and Xaml cells<\/span><\/a><\/p>\n<p><span style=\"font-weight: 400\">TwinTechs FastGrid implementation was very promising. Although it didn\u2019t 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!<\/span><\/p>\n<h3><span style=\"font-weight: 400\">2. Meet the FastGrid<\/span><\/h3>\n<p><span style=\"font-weight: 400\">First, our goal was an implementation of a complex user interface for our client\u2019s application. We didn&#8217;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! <a href=\"https:\/\/medium.com\/@slava.chernikoff\">Slava Chernikoff<\/a><\/span><span style=\"font-weight: 400\">\u00a0was focused on iOS implementation, and later <a href=\"https:\/\/github.com\/KirillAshikhmin\">Kirill Ashikhmin<\/a><\/span><span style=\"font-weight: 400\">\u00a0adopted it for Android. <\/span><\/p>\n<h3><span style=\"font-weight: 400\">2.1 How it Works?<\/span><\/h3>\n<p><span style=\"font-weight: 400\">Let us remind you of the task at hand &#8211; 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).<\/span><\/p>\n<p><span style=\"font-weight: 400\">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.<\/span><\/p>\n<p><img decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/binwelldata.blob.core.windows.net\/data\/fastgrid_1.png\" alt=\"FastGridTemplateSelector\" \/><\/p>\n<p><span style=\"font-weight: 400\">The diagram above demonstrates using of DataTemplateSelector for making a complex UI based on data from backend API. <\/span><\/p>\n<h3><span style=\"font-weight: 400\">2.2 Current Binwell FastGrid Features<\/span><\/h3>\n<p><span style=\"font-weight: 400\">Below is a brief feature list of the Binwell FastGrid:<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Use a large number of cell types<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Every cell type is related to the data model (including sections)<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Using of Flow Layouts to deal with layout inside RecyclerView and UICollectionView<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Support for dynamic data adding\/updating\/removing, including LoadMore feature<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Pull-to-refresh features<\/span><\/li>\n<\/ul>\n<p><span style=\"font-weight: 400\">Complete source code and sample are available through <\/span><a href=\"https:\/\/github.com\/Binwell\/FastGrid\"><span style=\"font-weight: 400\">this Binwell FastGrid GitHub<\/span><\/a><\/p>\n<h3><span style=\"font-weight: 400\">3. How to use FastGrid<\/span><\/h3>\n<p><span style=\"font-weight: 400\">To demonstrate the usage of Binwell FastGrid, let\u2019s start with a common mobile marketplace case: displaying a grouped products list in 2 columns. <\/span><\/p>\n<p><img decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/binwelldata.blob.core.windows.net\/data\/fastgrid_2.png\" alt=\"FastGrid Sample\" \/><\/p>\n<p><span style=\"font-weight: 400\">In general, use of FastGridView is similar to ListView &#8211; you will need to create a custom ViewCell:<\/span><\/p>\n<pre class=\"lang:c# decode:true \" title=\"FastGridCell sample\">    public class ProductCell : FastGridCell\r\n    {\r\n        CachedImage _image;\r\n        Label _name;\r\n        Label _price;\r\n\r\n        protected override void InitializeCell()\r\n        {\r\n            var screenWidth = Device.Info.ScaledScreenSize.Width;\r\n\r\n            _image = new CachedImage\r\n            {\r\n                HorizontalOptions = LayoutOptions.Center,\r\n                Aspect = Aspect.AspectFill,\r\n                WidthRequest = screenWidth \/ 2 - 40,\r\n                HeightRequest = screenWidth \/ 2 - 40\r\n            };\r\n\r\n            _name = new Label\r\n            {\r\n                HorizontalOptions = LayoutOptions.Center,\r\n                FontSize = 20,\r\n                TextColor = Color.Black\r\n            };\r\n\r\n            _price = new Label { HorizontalOptions = LayoutOptions.Center,\r\n                FontSize = 14,\r\n                TextColor = Color.Black\r\n            };\r\n\r\n            View = new StackLayout\r\n            {\r\n                BackgroundColor = Color.White,\r\n                Padding = 20,\r\n                VerticalOptions = LayoutOptions.FillAndExpand,\r\n                HorizontalOptions = LayoutOptions.FillAndExpand,\r\n                Children =\r\n                {\r\n                    _image,\r\n                    _name,\r\n                    _price\r\n                }\r\n            };\r\n        }\r\n\r\n        protected override void SetupCell(bool isRecycled)\r\n        {\r\n            if (!(BindingContext is ProductObject bindingContext)) return;\r\n\r\n            _image.Source = null;\r\n            _image.Source = bindingContext.ImageUrl;\r\n            _name.Text = bindingContext.Name;\r\n            _price.Text = bindingContext.Price;\r\n        }\r\n    }<\/pre>\n<p><span style=\"font-weight: 400\">As you can see, you should implement custom <span class=\"lang:c# decode:true crayon-inline \">InitializeCell()<\/span>\u00a0and <span class=\"lang:c# decode:true crayon-inline\">SetupCell()<\/span>\u00a0methods. The example above demonstrates code-behind UI creation, but you can also use XAML and Bindings by placing <span class=\"lang:c# decode:true crayon-inline \">InitializeComponent()<\/span>\u00a0<\/span><span style=\"font-weight: 400\">inside <span class=\"lang:c# decode:true crayon-inline\">InitializeCell()<\/span>. Additionally, you can use the\u00a0<span class=\"lang:c# decode:true crayon-inline \">SetupCell()<\/span>\u00a0method for manually setting of new values. In some cases it lets you fine-tune your data or UI.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Then create a FastGridTemplateSelector:<\/span><\/p>\n<pre class=\"lang:c# decode:true \" title=\"FastGridTemplateSelector Sample in MainPage.xaml.cs\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0var size = Device.Info.ScaledScreenSize;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0fastGridView.ItemTemplateSelector = new FastGridTemplateSelector(\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0new FastGridDataTemplate(typeof(CategoryObject).Name, \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0typeof(CategoryCell),new Size(size.Width, 70)),\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0new FastGridDataTemplate(typeof(ProductObject).Name, \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0typeof(ProductCell),new Size(size.Width \/ 2, 260))\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0);<\/pre>\n<p><span style=\"font-weight: 400\">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\u2019s not very flexible, but also does not require heavy cell size calculations.<\/span><\/p>\n<p><span style=\"font-weight: 400\">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.<\/span><\/p>\n<p><span style=\"font-weight: 400\">If you are familiar Russian and want to see FastGrid in action, check out the Instamart applications in:<\/span><\/p>\n<ul>\n<li><a href=\"https:\/\/itunes.apple.com\/ru\/app\/id1166642457?mt=8\"><span style=\"font-weight: 400\">AppStore<\/span><\/a><\/li>\n<li><a href=\"https:\/\/play.google.com\/store\/apps\/details?id=ru.instamart\"><span style=\"font-weight: 400\">Google Play<\/span><\/a><\/li>\n<\/ul>\n<h2><span style=\"font-weight: 400\">Future works<\/span><\/h2>\n<p><span style=\"font-weight: 400\">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:<\/span><\/p>\n<ol>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Don\u2019t use ViewRenderer<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Don\u2019t use Xamarin.Forms.Internals<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Implement ColumnSpacing and RowSpacing for iOS<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Dynamic cell sizing<\/span><\/li>\n<\/ol>\n<p><span style=\"font-weight: 400\">Many thanks for TwinTechs for initial project and ideas! \u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400\">You can find Binwell FastGrid and sample here: <\/span><a href=\"https:\/\/github.com\/Binwell\/FastGrid\"><span style=\"font-weight: 400\">https:\/\/github.com\/Binwell\/FastGrid<\/span><\/a><\/p>\n<p><span style=\"font-weight: 400\">Stay tuned!<\/span>\t\t<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this guest blog Slava and team show you how to use FastGrid for complex Xamrin.Forms user interfaces to create a great native experience and how they use it as a customizable white box component.<\/p>\n","protected":false},"author":803,"featured_media":40893,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[2],"tags":[589,16],"class_list":["post-38508","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-developers","tag-community","tag-xamarin-forms"],"acf":[],"blog_post_summary":"<p>In this guest blog Slava and team show you how to use FastGrid for complex Xamrin.Forms user interfaces to create a great native experience and how they use it as a customizable white box component.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/posts\/38508","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/users\/803"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/comments?post=38508"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/posts\/38508\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/media\/40893"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/media?parent=38508"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/categories?post=38508"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/tags?post=38508"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}