Grid Menu with Flow List View

I’m currently working in a project that require me to create a grid menu. In my previous project, I manually created it using grid, but later I found out a more effective way to create grid menu. I’m using third party library, created by the infamous Daniel Luberda, called Flow List View. Unlike the default list view which only has one column, flow list view allow you to set how many columns you want for your list view. In this post I want to discuss about how basically we can utilize this flow list view with MVVM pattern.

Selected Item Handling

When you create a menu for your app, there are, at least, two things you have to handle. First, how it handles user input and second how to navigate to other pages. To handle user input, you can see the following xaml code to get glimpse how it’ll be done.

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:flv="clr-namespace:DLToolkit.Forms.Controls;assembly=DLToolkit.Forms.Controls.FlowListView"              x:Class="App1.Pages.Breakfast.BreakfastPage">
 <ContentPage.Content>
  <Grid VerticalOptions="Fill" HorizontalOptions="Fill">
   <Grid.RowDefinitions>
    <RowDefinition Height="Auto"/>
    <RowDefinition Height="*"/>
   </Grid.RowDefinitions>

  <ContentView Grid.Row="0" HeightRequest="100" Padding="20">
   <Label Text="What do you want for breakfast?" FontAttributes="Bold" HorizontalOptions="Center" VerticalOptions="Center" TextColor="DarkBlue" FontSize="Large"/>
  </ContentView>

 <ScrollView Grid.Row="1">
  <flv:FlowListView FlowItemsSource="{Binding BreakfastMenuList}" FlowLastTappedItem = "{Binding SelectedBreakfastMenu}" FlowItemTappedCommand ="{Binding MenuTappedCommand}" FlowColumnCount="2" SeparatorVisibility="None" Margin="30,0,30,0" HasUnevenRows="True">
   <flv:FlowListView.FlowColumnTemplate>
    <DataTemplate>
     <Frame Margin="15,10,15,10" CornerRadius="5" HeightRequest="120" >
      <Grid HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" Margin="-20">
       <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="Auto"/>
       </Grid.RowDefinitions>

      <Image Grid.Row="1" Source="{Binding ImageSource}" HorizontalOptions="Center" VerticalOptions="Center"/>
      <ContentView Grid.Row="2" BackgroundColor="DarkBlue" HeightRequest="40">
      <Label Text="{Binding MenuTitle}" TextColor="White" FontSize="Medium" FontAttributes="Bold" HorizontalOptions="Center" VerticalOptions="Center"/>
      </ContentView>
      </Grid>
     </Frame>
    </DataTemplate>
   </flv:FlowListView.FlowColumnTemplate>
  </flv:FlowListView>
 </ScrollView>

  </Grid>
 </ContentPage.Content>
</ContentPage>

Take a look once again at Flow List View. As you can see it has several properties, two of them are Flow Last Tapped Item and Flow Item Tapped Command. Base on it’s name, you can guess the function of those properties. You can bind the menu item that user just tapped to Flow Last Tapped Item, and then Flow Item Tapped Command will execute the command to handle the tapped event. So, when user tap one of the menus, we can record what menu he just tapped and do action accordingly. Another important property is Flow Column Count, where you set how many column your menu will be.

Navigation Handling

After we’ve done doing binding in xaml file, we move on to the view model. In view model, to navigate to another page, we’ll need INavigation from the class binder. We’ll pass it from constructor and use it to navigate to other page depend on the tapped menu. The following codes are the example how I did it.

 

public class BreakfastViewModel : INotifyPropertyChanged
{
  public event PropertyChangedEventHandler PropertyChanged;
  private INavigation navigation;
  private ObservableCollection<BreakfastMenu> breakfastMenuList;
  private BreakfastMenu selectedBreakfastMenu;
  public ObservableCollection<BreakfastMenu> BreakfastMenuList
  {
   get => breakfastMenuList;
   set => SetObservableProperty(ref breakfastMenuList, value);
  }
  public BreakfastMenu SelectedBreakfastMenu
  {
   get => selectedBreakfastMenu;
   set => SetObservableProperty(ref selectedBreakfastMenu, value);
  }

  public ICommand MenuTappedCommand { get; set; }

  public BreakfastViewModel(INavigation navigation)
  {
   this.navigation = navigation;
   BreakfastMenuList = new ObservableCollection<BreakfastMenu>()
   {
     new BreakfastMenu() { ImageSource = "Burger.png", MenuTitle = "BURGER" },
     new BreakfastMenu() { ImageSource = "Pizza.png", MenuTitle = "PIZZA" },
     new BreakfastMenu() { ImageSource = "EggBacon.png", MenuTitle = "BACON" },
     new BreakfastMenu() { ImageSource = "Sandwich.png", MenuTitle = "SANDWICH" },
   };
   MenuTappedCommand = new Command(async () => await MenuSelectedAsync());
 }

private async Task MenuSelectedAsync()
{
 switch (SelectedBreakfastMenu.MenuTitle)
 {
  case "BURGER":
   await navigation.PushModalAsync(new BreakfastBurger());
   break;
  case "PIZZA":
   await navigation.PushModalAsync(new BreakfastPizza());
   break;
  case "BACON":
   await navigation.PushModalAsync(new BreakfastBacon());
   break;
  case "SANDWICH":
   await navigation.PushModalAsync(new BreakfastSandwich());
   break;
  }

}

protected void SetObservableProperty<T>(ref T field, T value,
[CallerMemberName] string propertyName = "")
{
  if (EqualityComparer<T>.Default.Equals(field, value)) return;
  field = value;
  OnPropertyChanged(propertyName);
}

protected virtual void OnPropertyChanged(string propertyName)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

 

[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class BreakfastPage : ContentPage
{
 public BreakfastPage()
 {
   InitializeComponent();
   BindingContext = new BreakfastViewModel(Navigation);
 }
}

If there’s anything you need to pay more attention is, how I navigate. I used PushModalAsync instead of, the more commonly used, PushAsync, because PushAsync is not supported globally to be used in view model.

Credit:

  • Icon from FlatIcon, Burger icon by Freepik, Pizza icon by Smashicons, EggBacon and Sandwich Icon by Twitter
  • Flow List View by Daniel Luberda (github)
Advertisements

4 thoughts on “Grid Menu with Flow List View

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s