Customize Xamarin.Forms ListView with ViewCell

Xamarin.Forms has several cell types for the ubiquitous ListView control that require the developer to bind some properties and presto; a fully functioning listview with items is built.

I used the TextCell on the NewsView of my sample Xamarin.Forms app. It was as simple as setting the ItemsSource and binding properties.

listView.ItemsSource = ViewModel.NewsItems;
var cell = new DataTemplate(typeof(ListTextCell));
cell.SetBinding (TextCell.TextProperty, "headline");
cell.SetBinding (TextCell.DetailProperty, "Title");
listView.ItemTemplate = cell;

And that was it, I now had a fully featured list view on three platforms, that just worked.

image of news view

The built in cell types are great and probably cover a majority of cases, however if there isn't a cell for you there is still hope.

The ViewCell

Xamarin built in a view cell that allows for a developer to define their own Xamarin.Forms view to define as the ItemTemplate for the list view.

I spent a little bit of time messing with text formatting on the text/image cells for the GroupMatchView, but couldn't get the matches to look just right.

I decided to implement a ViewCell to handle the custom formatting that I needed. From what I can tell, I could definitely be mistaken, developers are allowed to use any of the layouts that inherit from View to make their cell. For my purposes I chose to play with something all developers love, the Grid.

  • First we create the class and inherit from ViewCell

    public class ScoreCell : ViewCell
    
  • Next, setup the grid. For the purposes of time, I did this in the constructor, there are numerous better ways to do this, but it served it's purpose.

    Grid grid = new Grid
        {
            Padding = new Thickness(5, 10, 0, 0),
            ColumnDefinitions =
            {
                new ColumnDefinition { Width = new GridLength(10, GridUnitType.Star) },
                new ColumnDefinition { Width = new GridLength(2, GridUnitType.Star) },
                new ColumnDefinition
                { Width = new GridLength(25, 
                        GridUnitType.Absolute)
                }, 
                new ColumnDefinition { Width = new GridLength(2, GridUnitType.Star) },
                new ColumnDefinition { Width = new GridLength(10, GridUnitType.Star)  },
            },
        };
    

    Those of you familiar with WPF will notice the GridUnitType.Star on the majority of the columns. That is the same as the WPF star for sizing, which indicates proportional sizing. There are a few other types you can use for sizing.

    • Auto the Grid column will only take up as much space as needed for the content.

    • Absolute sets the size absolutely. See column 2 above.

  • From there we create labels and set the binding properties.

    var homeLabel = new Label()
        {
            YAlign = TextAlignment.Center,
            XAlign = TextAlignment.End,
        };
        var awayLabel = new Label()
        {
            YAlign = TextAlignment.Center
        };
        var homeScore = new Label()
        {
            YAlign = TextAlignment.Center,
            XAlign = TextAlignment.End
        };
        var awayScore = new Label()
        {
            YAlign = TextAlignment.Center
        };
        homeLabel.SetBinding(Label.TextProperty, "HomeTeam");
        awayLabel.SetBinding(Label.TextProperty, "AwayTeam");
        homeScore.SetBinding(Label.TextProperty, "HomeScore");
        awayScore.SetBinding(Label.TextProperty, "AwayScore");
    
  • Then add each label to the appropriate column and set the view to our grid.

        grid.Children.Add(homeLabel);   
        grid.Children.Add(homeScore, 1, 0);
        grid.Children.Add(new Label
        {
            Text = "vs.",
            YAlign = TextAlignment.Center,
        }, 2, 0);
        grid.Children.Add(awayScore, 3, 0);
        grid.Children.Add(awayLabel, 4, 0);
        this.View = grid;
    

That's it.

We now have a fully functioning ViewCell to set the template to.

 var viewTemplate = new DataTemplate(typeof(ScoreCell));
listView.ItemTemplate = viewTemplate;
listView.ItemsSource = Groups;

Which looks like this on three devices.

image of three devices

In conclusion

This post demonstrated how a developer has many options when building a custom and unique listview. Xamarin makes it quite simple to build something to fit your needs if the* out-of-the-box *templates don't meet your needs. And most importantly/awesomely it is 100% same code, no device specific rendering.

comments powered by Disqus