MAUI Gesture Detection Part-1


Gesture detection in .NET MAUI helps you build dynamic, interactive user interfaces which respond to the user’s gestures like swipes, taps, and pinches.

Topics Covered

  • Refreshing View – Pull to refresh gesture using RefreshView.
  • Working with SwipeView – Add swipe gestures to list items to perform actions like deleting or editing in the list item.
  • Working with GestureRecognizers – Add tap and double-tap gesture recognizers to elements.

I will create a page where:

  • There are pull to refresh gestures that users can implement on a list.
  • For example we have each list item that can be swiped to show additional actions (delete).
  • Tap gestures can also be opened on the label element to provide additional interactivity.

Setting Up the ViewModel

I will have a ViewModel that will hold a list Items that the users can interact with.

GestureViewModel.cs

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;

namespace MauiAppExample
{
    public class GestureViewModel : INotifyPropertyChanged
    {
        private bool _isRefreshing;

        public ObservableCollection<string> Items { get; set; }
        public ICommand RefreshCommand { get; }
        public ICommand TapCommand { get; }

        public bool IsRefreshing
        {
            get => _isRefreshing;
            set
            {
                _isRefreshing = value;
                OnPropertyChanged();
            }
        }

        public GestureViewModel()
        {
            Items = new ObservableCollection<string>
            {
                "Item 1",
                "Item 2",
                "Item 3",
                "Item 4",
                "Item 5"
            };

            RefreshCommand = new Command(OnRefresh);
            TapCommand = new Command(OnTapped);
        }

        private void OnRefresh()
        {
            // Simulate refreshing the data
            Items.Add($"New Item {Items.Count + 1}");
            IsRefreshing = false;
        }

        private void OnTapped()
        {
            // Handle tap gesture
            App.Current.MainPage.DisplayAlert("Tapped", "You tapped the label!", "OK");
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
  • Items: Items displayed in the list.
  • RefreshCommand: When the user pulls to refresh the list, what command must be performed.
  • TapCommand: A command for handling tap gestures on area of UI elements.
  • IsRefreshing: Indicates the refreshing state for the RefreshView.

Creating the User Interface in XAML

MainPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:MauiAppExample"
             x:Class="MauiAppExample.MainPage">

    <ContentPage.BindingContext>
        <local:GestureViewModel />
    </ContentPage.BindingContext>

    <StackLayout Padding="20">

        <!-- RefreshView for pull-to-refresh functionality -->
        <RefreshView IsRefreshing="{Binding IsRefreshing}"
                     Command="{Binding RefreshCommand}">
            <ListView ItemsSource="{Binding Items}">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <!-- Using SwipeView to add swipe actions to each item -->
                        <SwipeView>
                            <SwipeView.LeftItems>
                                <SwipeItems>
                                    <SwipeItem Text="Delete"
                                               BackgroundColor="Red"
                                               Command="{Binding Path=BindingContext.RemoveCommand, Source={x:Reference Name=MainPage}}"
                                               CommandParameter="{Binding .}" />
                                </SwipeItems>
                            </SwipeView.LeftItems>
                            <Grid Padding="10">
                                <Label Text="{Binding .}"
                                       FontSize="Medium" />
                            </Grid>
                        </SwipeView>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </RefreshView>

        <!-- Label to demonstrate tap gesture recognizer -->
        <Label Text="Tap Me"
               FontSize="Large"
               HorizontalOptions="Center"
               Margin="0,20,0,0">
            <Label.GestureRecognizers>
                <TapGestureRecognizer Command="{Binding TapCommand}" NumberOfTapsRequired="1" />
            </Label.GestureRecognizers>
        </Label>

    </StackLayout>
</ContentPage>

Explanation of Key Gesture Features

  • Refreshing View (RefreshView):
    • The ListView was wrapped around by RefreshView which adds pull to refresh functionality.
    • With IsRefreshing property that helps us set up refreshing state, and command (RefreshCommand) does the job of actually refreshing the items.
    • OnRefresh method of the RefreshCommand simulates adding new items and stops refreshing.
  • Working with SwipeView:
    • Each item in the ListView is wrapped around by SwipeView.
    • Swipe actions (i.e. such as “Delete”) are defined via SwipeItems.
    • SwipeItem defines the text, background color, and a command to invoke when item is swiped.
  • Working with Gesture Recognizers (TapGestureRecognizer):
    • TapGestureRecognizer helps you with capturing taps (like taps on a Label, Button, or basically any other VisualElement).
    • Where the NumberOfTapsRequired property is a property that lets you set it to single or double taps.
    • In this example when we tap on the label it invokes the TapCommand as part of the ViewModel which is then created to display an alert.

Adding Delete Functionality

The SwipeView interaction will require some adding of functionality to remove items from the list when the “Delete” button is tapped.

Add a RemoveCommand to your ViewModel:

Update ViewModel (GestureViewModel.cs):

public ICommand RemoveCommand { get; }

public GestureViewModel()
{
    Items = new ObservableCollection<string>
    {
        "Item 1",
        "Item 2",
        "Item 3",
        "Item 4",
        "Item 5"
    };

    RefreshCommand = new Command(OnRefresh);
    TapCommand = new Command(OnTapped);
    RemoveCommand = new Command<string>(OnRemove);
}

private void OnRemove(string item)
{
    if (Items.Contains(item))
    {
        Items.Remove(item);
    }
}

RemoveCommand:

  • Command Parameter: Remove method removes an item from the Items collection when OnRemove method is called with item as a parameter.

Summary of MAUI Gesture Detection

FeatureDescription
RefreshViewProvides pull-to-refresh functionality, typically wrapping a list or scrollable element.
SwipeViewAdds swipe actions to items in a collection, like “Delete” or “Edit”.
GestureRecognizersAllow elements to respond to gestures, such as tapping, double-tapping, pinching, or swiping.