Xamarin Forms Pull To Refresh With ListView

The Xamarin Forms ListView control has the ability to allow the user to pull down from the top of the ListView to trigger a refresh command. I say a refresh command, because the pull to refresh, just triggers a command and you can do whatever you want in that command, including not updating the ListView.

Properties

There are 3 properties you need to be aware of to implement the pull to refresh functionality.

 <ListView ItemsSource="{Binding MyList}"
           IsPullToRefreshEnabled="True"
           RefreshCommand="{Binding RefreshCommand}"
           IsRefreshing="{Binding IsRefreshing}" />

Set IsPullToRefreshEnabled=”True” to enable the functionality, then create these 2 properties in your ViewModel.

private bool _isRefreshing = false;
public bool IsRefreshing { 
get { return _isRefreshing; }
set {
    _isRefreshing = value;
    OnPropertyChanged(nameof(IsRefreshing));
    }
}
public ICommand RefreshCommand
{
    get {
        return new Command(async () =>
        {
            IsRefreshing = true;
            
            await RefreshData();

            IsRefreshing = false;
        });
    }
}

Now when you pull down from the top of the listview, it will show a refresh animation, while IsRefreshing=”true”.

Pull To Refresh Android  Pull To Refresh iOS

Pull To Refresh Customization

On each platform we can customize a small part of the refresh animation.

Android

Android uses the SwipeRefreshLayout control to display an animation while the ListView is being updated. The SwipeRefreshLayout is internal in the ListViewRenderer, hence you are not able to call any properties on it directly, unless you want to write a whole new ListViewRenderer. Hence, until this has some access given, it’s currently impossible to do, without writing your own ListViewRenderer.

However, there is a way, using reflection and a custom renderer, that this can be done. It’s not the best solution, but it works.

First create a new file in Resources > values in your Android project, called array.xml

<?xml version="1.0" encoding="utf-8"?>
<resources> 
    <color name="red">#FF0000</color> 
    <array name="SwipeRefreshColors"> 
        <item>@color/red</item> 
    </array>
</resources>

Now create a custom renderer, to get this private field, and set the color.

[assembly: ExportRenderer(typeof(Xamarin.Forms.ListView), typeof(CustomListViewRenderer))]
namespace Mobile.Droid
{ 
    public class CustomListViewRenderer : ListViewRenderer 
    { 
        protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.ListView> e) 
        { 
            base.OnElementChanged(e);
            if (e.NewElement != null) 
            { 
                FieldInfo[] fields = typeof(ListViewRenderer).GetFields( BindingFlags.NonPublic | BindingFlags.Instance);
                var refresh = (SwipeRefreshLayout)fields.First(x => x.Name == "_refresh").GetValue(this); 
                refresh.SetColorSchemeColors(this.Context.Resources.GetIntArray(Resource.Array.SwipeRefreshColors)); 
            }
        }
    }
}

iOS

In iOS the UIRefreshControl to display the animation while refreshing data. The UIRefreshControl has a TintColor and AttributedTitle, however unlike Android, we have a way to interact with this control. The ListViewRenderer has a ViewController, which is actually a UITableViewController. From here we can reach the RefreshControl.

[assembly: ExportRenderer(typeof(ListView), typeof(ListViewRender))]
namespace Mobile.iOS
{
    public class ListViewRender: ListViewRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<ListView> e)
        {
            base.OnElementChanged(e);

            ((UITableViewController)ViewController).RefreshControl.TintColor = UIColor.Red;
        }
    }
}

Limitations

  • Not available on UWP, Android or Windows Phone 8.1
  • Not able to easily customize the refresh animation.
  • Only limited styling options available.


XAMARIN WEEKLY NEWSLETTER

Subscribe to a hand-picked round up of the best Xamarin development links every week. Published every Friday. Free.

Signup to Weekly Xamarin

* I do not maintain or run this newsletter, but I do recommend it.

Microsoft MVP | Xamarin MVP | Xamarin Forms Developer | Build Flutter

Related Posts

6 Comments

    1. Adam Pedley

      RefreshData is just a placeholder that I used in my example. You will need to create it yourself to get a new version of the data and bind it to the list.

    1. Adam Pedley

      OnPropertyChanged can be written yourself or may be part of your MVVM framework. To ensure that updates from your ViewModel to your View are recognized, your ViewModel should inherit INotifyPropertyChanged.

      This will then create an event called PropertyChanged.

      Then you create a function, to call this event. e.g.

      public class BaseViewModel : INotifyPropertyChanged
      {
      public event PropertyChangedEventHandler PropertyChanged;

      public void OnPropertyChanged([CallerMemberName] string propertyName = “”)
      {
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
      }
      }