The Xamarin ListView on Steroids

It's 2017. We have been using smartphones for over 10 years now. And with time, our expectations of sophistication from mobile apps has grown exponentially. As users, we want immediate feedback, support for all gestures and impeccable performance from apps. Keep all this in mind as you build your next cross-platform mobile app with Xamarin.

As is the case, most apps need to display a list of things. And most often, the developer's choice of user interface control is the ubiquitous ListView. Sure you can start with the vanilla ones and build features of your own – but wouldn't you rather focus on your app's functionality, than sweating over perfecting the ListView's interactivity?

Call me biased, but I prefer well-engineered polished and performant UI controls out of the box – like the cross-platform Xamarin.Forms ListView that comes with Telerik UI for Xamarin. This article dives into some advanced features of the Telerik ListView and how you could implement them easily in your apps. Your users will invariably expect all this from a modern app – will you deliver?

Pull to Refresh

Your first ask with a ListView is to bind it to some data and display a nicely formatted list of items. But what if your items collection changes on the fly after initial load? Your users will want to see the data refreshed and will expect pull-to-refresh gesture to be supported.

With the content scrolled to the top, swipe a finger down – and voila, the Telerik ListView supports pull-to-refresh out of the box, including a custom animated refresh indicator on each mobile platform.

Let us pick up from where we left off with our aviation app – after all, it doesn't get much fancier than luxury private jets. Having already bound the ListView to a RESTful endpoint bringing down cloud data, here's to add pull-to-refresh functionality.

First, enable the feature in the Xamarin.Forms XAML markup declaration:

<TelerikDataControls:RadListView x:Name="BizJetsList" SelectionMode="Single" ItemTapped="BizJet_Selected"
                                 IsPullToRefreshEnabled="true" RefreshRequested="BizJetsList_RefreshRequested">
        <TelerikDataControls:RadListView.ItemTemplate>
            ...
            ...
        </TelerikDataControls:RadListView.ItemTemplate>
</TelerikDataControls:RadListView>

Next, implement the RefreshRequested() public event in the code-behind – this is triggered by the pull-to-refresh gesture. Your custom data refresh logic goes here; I simply call upon my ViewModel to refresh the data, in case there are new items:

BizJetsViewModel BZVM;

public BizJetsView()
{
    InitializeComponent();
    BZVM = new BizJetsViewModel();
    this.FetchViewData();
}
    
private void BizJetsList_RefreshRequested(object sender, PullToRefreshRequestedEventArgs e)
{
    this.FetchViewData();
    this.BizJetsList.EndRefresh();
}
    
private async void FetchViewData()
{
    await BZVM.GetAllBizJets();
    this.BizJetsList.ItemsSource = BZVM.BizJetsCollection;
}

Finally, invoke the EndRefresh() method in the RefreshRequested() handler to indicate that the data refresh has been completed. Now when the user is near the the top of the ListView, a quick pull/swipe down from the top refreshes the bound data collection, complete with an animated activity indicator that is customized for iOS/Android/Windows.

Load on Demand

We all know shipping a huge amount of data to the client side on a mobile app isn't recommended, yet there aren't any warnings before you shoot yourself in the foot. What if you bind your ListView to 100K of data items, each with a fancy item template for display?

While not recommended, if you do end up with massive data binding/rendering payload, your UI should be smart enough to handle it, instead of bringing the app down to its knees. The Telerik ListView can handle this graciously with built-in load on demand – it supports intelligent, incremental data loads before item visualization, when bound to a large data set.

There are two modes in which load on demand works:

  1. Automatic – Data is requested automatically when user scrolls near end of visualized items.
  2. Manual – Data is requested explicitly by clicking on a button rendered near the end of visualized items.

Back in our aviation app where we list business jets, here's the simplest way to enable automatic load on demand for our Listview. Simply turn it on in markup, respond to an event and add fresh data to the collection.

<TelerikDataControls:RadListView x:Name="BizJetsList" SelectionMode="Single" ItemTapped="BizJet_Selected"
                                 IsLoadOnDemandEnabled="true" LoadOnDemandMode="Automatic" LoadOnDemand="BizJetsList_LoadOnDemand">
        <TelerikDataControls:RadListView.ItemTemplate>
            ...
            ...
        </TelerikDataControls:RadListView.ItemTemplate>
</TelerikDataControls:RadListView>
private void BizJetsList_LoadOnDemand(object sender, EventArgs e)
{
    BizJets lodBizJet = new BizJets();
    lodBizJet.AircraftName = "Load on Demand Aircraft";
    lodBizJet.AircraftCapacity = "N/A";
    (this.BizJetsList.ItemsSource as ObservableCollection<BizJets>).Add(lodBizJet);
}

You could alternatively manage the data loading from your ViewModel itself through a custom ListViewLoadOnDemandCollection collection object, as well as manage the number of preloaded items and change the appearance of the manual load button – the ListView performs with the same aplomb.

Cell Swipe

Your app users will invariably want to interact with the rows in your ListView. What happens if I swipe right or left? With the Telerik ListView, you have built-in support for swipe gestures – the content view simply moves over for actions or interactive buttons, with completely customizable experiences.

Once enabled, you get to control the swipe threshold and offset – to customize exactly how the user interactivity should behave. You also get to respond to several events as they relate to the swipe – when it starts, when it is happening and when it ends, all with corresponding event arguments. These events can be used in conjunction with the swipe direction or swiped distance to either take decisive action on the data item or reveal interactive content.

In the case of our aviation app, potential customers may like a specific business jet and swipe it to make reservations. This can be set up as in the code below – note that the content you reveal is completely up to you and controlled by a simple template.

<TelerikDataControls:RadListView x:Name="BizJetsList" 
                                   IsItemSwipeEnabled="True" SwipeThreshold="10" SwipeOffset="70, 0, 0, 0">
        <TelerikDataControls:RadListView.ItemTemplate>
            <DataTemplate>
            ...
            ...
            </DataTemplate>
        </TelerikDataControls:RadListView.ItemTemplate>
        <TelerikDataControls:RadListView.ItemSwipeContentTemplate>
            <DataTemplate>
                <Grid Padding="0" Margin="0" RowSpacing="0" ColumnSpacing="0">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="70" />
                        <ColumnDefinition Width="*" />
                    </Grid.ColumnDefinitions>
                    <Button Text="Book" Clicked="Book_BizJet" WidthRequest="70" BorderRadius="0" Margin="0" />
                </Grid>
            </DataTemplate>
        </TelerikDataControls:RadListView.ItemSwipeContentTemplate>
</TelerikDataControls:RadListView>
private void Book_BizJet(object sender, EventArgs e)
{
    // Do stuff here.
}

Responding to interactive buttons revealed on swiped content is simple – just respond to a regular event handler. The cell swipe interactions are commonly used to flag/delete items in the ListView – you get event notifications to adjust the underlying data collection accordingly.

Cell Style

It shouldn't be a surprise that a modern ListView would allow developers complete flexibility into how each of the row cells are styled, and the Telerik ListView does not disappoint on this either. It offers styling customization for regular, selected and pressed modes.

Here's how I could style the list of business jets – take out the cell borders if I preferred:

<TelerikDataControls:RadListView x:Name="BizJetsList">
        <TelerikDataControls:RadListView.ItemStyle>
            <TelerikListView:ListViewItemStyle BackgroundColor="Transparent" BorderLocation="None"/>
        </TelerikDataControls:RadListView.ItemStyle>
        <TelerikDataControls:RadListView.ItemTemplate>
            <DataTemplate>
            ...
            ...
            </DataTemplate>
        </TelerikDataControls:RadListView.ItemTemplate>
</TelerikDataControls:RadListView>

Or, if we're allowing selections, we could have a style for the selected data item to highlight it, like so:

<TelerikDataControls:RadListView.SelectedItemStyle>
            <TelerikListView:ListViewItemStyle BackgroundColor="#E5EDF3" BorderWidth="3" BorderLocation="Bottom"/>
</TelerikDataControls:RadListView.SelectedItemStyle>

Cell Reorder

Sure, your users can sort and filter their ListView records, but sometimes having some personal control matters – like being able to just grab and reorder items. Thankfully, the Telerik ListView obliges with a built-in reorder feature. All you need to do is simply enable it to allow to user to tap, hold and move items within your ListView. The changes trickle back to the data items collection that the UI is bound to as well.

Here's how to add this to our ListView of business jets – the user gets to hold, move and release item at desired location in the list:

<TelerikDataControls:RadListView x:Name="BizJetsList" SelectionMode="None" IsItemsReorderEnabled="true">
        <TelerikDataControls:RadListView.ItemTemplate>
            <DataTemplate>
            ...
            ...
            </DataTemplate>
        </TelerikDataControls:RadListView.ItemTemplate>
</TelerikDataControls:RadListView>

Conclusion

With mobile apps, it is often a race to the market with a great app idea. Don't get left behind re-inventing the wheel. Professionally engineered UI components like Telerik UI for Xamarin will drastically cut your development time and allow you to grab your audience quicker.

Even if you have the luxury of an established user base, your users will naturally expect common gestures from your app UI, like the often-used ubiquitous ListView. If you're using the Telerik ListView, you'll get most modern features and gesture support built-in – simply enable them in your app, respond to events and manage your data collection. That's called efficiency when it comes to making native cross-platform mobile apps with Xamarin. Let no app be left behind!

Header image courtesy of midiman

Related resources:

Comments