skip to Main Content

I have been trying to find a solution for swipe gestures not working on devices but working fine in emulator. In visual studio running android 33.x on x64 platform emulator swipe gestures work. But on hardware device it does not at all.

Tap gestures are working on device and emulator.

Here is xaml code

<?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:model="clr-namespace:NerdNewsNavigator2.Model"
             xmlns:viewmodel="clr-namespace:NerdNewsNavigator2.ViewModel"
             x:Class="NerdNewsNavigator2.View.ShowPage"
             x:DataType="viewmodel:ShowViewModel"
             Title="">
    <Shell.BackButtonBehavior>
        <BackButtonBehavior IsEnabled="True" IsVisible="{OnPlatform Android=False,iOS=False, WinUI=True}">
        </BackButtonBehavior>
    </Shell.BackButtonBehavior>
    <CollectionView  ItemsSource="{Binding Shows}">
        <CollectionView.ItemTemplate>
            <DataTemplate x:DataType="model:Show">
                <Frame WidthRequest="{OnPlatform Android=375, iOS=375, WinUI=800}" 
                       BackgroundColor="White" 
                       Padding="10">
                    <Frame.GestureRecognizers>
                        <SwipeGestureRecognizer Direction="Left" 
                            Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodel:ShowViewModel}}, Path=SwipedGestureCommand}" 
                            CommandParameter="{Binding Url}"/>
                        <TapGestureRecognizer 
                            Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodel:ShowViewModel}}, Path=TapCommand}" 
                            CommandParameter="{Binding Url}"/>
                    </Frame.GestureRecognizers>
                    <StackLayout VerticalOptions="Start" Spacing="10" Padding="10">
                        <Label Text="{Binding Title}" 
                               HorizontalTextAlignment="Center" 
                               TextColor="Black"  
                               FontSize="12"  
                               FontAttributes="Bold"
                               LineBreakMode="WordWrap"/>
                        <Image Aspect="AspectFill" Source="{Binding Image}" HeightRequest="{OnPlatform WinUI=400}">
                        </Image>
                        <Label Text="{Binding Description}" 
                               MaximumHeightRequest="{OnPlatform WinUI=1200}" 
                               FontSize="10" 
                               LineBreakMode="WordWrap" 
                               TextColor="Black" 
                               TextType="Html">
                        </Label>
                    </StackLayout>
                </Frame>
            </DataTemplate>
        </CollectionView.ItemTemplate>
    </CollectionView>
</ContentPage>


Here is c# code for page:

// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Collections.ObjectModel;
using CodeHollow.FeedReader;
using CodeHollow.FeedReader.Feeds.Itunes;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using NerdNewsNavigator2.Model;
using NerdNewsNavigator2.View;

namespace NerdNewsNavigator2.ViewModel;

[QueryProperty("Url", "Url")]
public partial class ShowViewModel : ObservableObject
{
    #region Properties
    public ObservableCollection<Show> Shows { get; set; } = new();
    #endregion

    public string Url
    {
        set
        {
            this.Shows = ShowViewModel.GetShow(value);
            OnPropertyChanged(nameof(Shows));
        }
    }
    #region GetShow
    private static ObservableCollection<Show> GetShow(string url)
    {
        ObservableCollection<Show> result = new();
        try
        {
            var feed = FeedReader.ReadAsync(url);
            foreach (var item in feed.Result.Items)
            {
                Show show = new()
                {
                    Title = item.Title,
                    Description = item.Description,
                    Image = item.GetItunesItem().Image.Href,
                    Url = item.Id
                };
                result.Add(show);
            }
            return result;
        }
        catch
        {
            Show show = new()
            {
                Title = string.Empty,
            };
            result.Add(show);
            return result;
        }
    }
    #endregion
    [RelayCommand]
    async Task SwipedGesture(string Url) => await Shell.Current.GoToAsync($"{nameof(PodcastPage)}?Url={Url}");

    [RelayCommand]
    async Task Tap(string Url) => await Shell.Current.GoToAsync($"{nameof(PlayPodcastPage)}?Url={Url}");
}

Any suggestions on how to fix this? Or is it a problem with maui? I am going to try default config for swipe gestures and modify post after I test. I wanted to use url variable to go back using viewmodel. But all I need is a swipe left to go back. This may be I just can’t code this way but I don’t understand why it works in emulator and not on device.

2

Answers


  1. Chosen as BEST ANSWER

    This is a working example. It works on Windows, Android emulator, and Android devices. I don't know about iOS or Mac. I do not have a developer account. My sample solution to swipe gestures with Maui

    SwipeGestures.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:viewmodel="clr-namespace:SwipeGesturesSample.ViewModel"
                 xmlns:model="clr-namespace:SwipeGesturesSample.Model"
                 x:DataType="viewmodel:SwipeGesturesViewModel"
                 x:Class="SwipeGesturesSample.View.SwipeGesturesPage"
                 Title="SwipeGesturesPage">
        <StackLayout BackgroundColor="White" Padding="20" WidthRequest="375">
            <StackLayout.GestureRecognizers>
                <SwipeGestureRecognizer
                      Direction="Right" 
                    Swiped="SwipedGesture" />
                <SwipeGestureRecognizer
                      Direction="Left" 
                    Swiped="SwipedGesture" />
                <SwipeGestureRecognizer
                      Direction="Down" 
                    Swiped="SwipedGesture" />
                <SwipeGestureRecognizer
                      Direction="Up" 
                    Swiped="SwipedGesture" />
            </StackLayout.GestureRecognizers>
            <Label
                TextColor="Black"
                FontSize="20"
                x:Name="Right"
                HorizontalOptions="Center"
                Text="StackLayout Example: Swipe Right"
                SemanticProperties.Hint=""/>
            <Label
                TextColor="Black"
                FontSize="20"
                x:Name="Left"
                HorizontalOptions="Center"
                Text="StackLayout Example: Swipe Left"
                SemanticProperties.Hint=""/>
            <Label
                TextColor="Black"
                FontSize="20"
                x:Name="Up"
                HorizontalOptions="Center"
                Text="StackLayout Example: Swipe Up"
                SemanticProperties.Hint=""/>
            <Label
                TextColor="Black"
                FontSize="20"
                x:Name="Down"
                HorizontalOptions="Center"
                Text="StackLayout Example: Swipe Down"
                SemanticProperties.Hint=""/>
        </StackLayout>
    </ContentPage>
    

    code behind: SwipeGesturesPage.xaml.cs

    using SwipeGesturesSample.Model;
    using SwipeGesturesSample.ViewModel;
    
    namespace SwipeGesturesSample.View;
    
    public partial class SwipeGesturesPage : ContentPage
    {
        Data data = new();
        public SwipeGesturesPage(SwipeGesturesViewModel viewmodel)
        {
            InitializeComponent();
            data.swipeTop = 0;
            data.swipeLeft = 0;
            data.swipeRight = 0;
            data.swipeBottom= 0;
           
            BindingContext= viewmodel;
        }
        private void SwipedGesture(object sender, SwipedEventArgs e)
        {
            switch (e.Direction)
            {
                case SwipeDirection.Up:
                    data.swipeTop += 1;
                    Up.Text = $"Gestured up {data.swipeTop}";
                    SemanticScreenReader.Announce(Up.Text);
                    break;
                case SwipeDirection.Down:
                    data.swipeBottom += 1;
                    Down.Text = $"Gestured down {data.swipeBottom}";
                    SemanticScreenReader.Announce(Down.Text);
                    break;
                case SwipeDirection.Left:
                    data.swipeLeft += 1;
                    Left.Text = $"Gestured left {data.swipeLeft}";
                    SemanticScreenReader.Announce(Left.Text);
                    break;
                case SwipeDirection.Right:
                    data.swipeRight += 1;
                    Right.Text = $"Gestured right {data.swipeRight}";
                    SemanticScreenReader.Announce(Right.Text);
                    break;
            }
        }
    }
    

    Data file: Data.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace SwipeGesturesSample.Model;
    
    public class Data
    {
        public int number { get; set; } 
        public int swipeLeft { get; set; }
        public int swipeRight { get; set;}
        public int swipeTop { get; set;}
        public int swipeBottom { get; set;}
    }
    
    using SwipeGesturesSample.Model;
    using SwipeGesturesSample.ViewModel;
    
    namespace SwipeGesturesSample.View;
    
    public partial class SwipeGesturesPage : ContentPage
    {
        Data data = new();
        public SwipeGesturesPage(SwipeGesturesViewModel viewmodel)
        {
            InitializeComponent();
            data.swipeTop = 0;
            data.swipeLeft = 0;
            data.swipeRight = 0;
            data.swipeBottom= 0;
           
            BindingContext= viewmodel;
        }
        private void SwipedGesture(object sender, SwipedEventArgs e)
        {
            switch (e.Direction)
            {
                case SwipeDirection.Up:
                    data.swipeTop += 1;
                    Up.Text = $"Gestured up {data.swipeTop}";
                    SemanticScreenReader.Announce(Up.Text);
                    break;
                case SwipeDirection.Down:
                    data.swipeBottom += 1;
                    Down.Text = $"Gestured down {data.swipeBottom}";
                    SemanticScreenReader.Announce(Down.Text);
                    break;
                case SwipeDirection.Left:
                    data.swipeLeft += 1;
                    Left.Text = $"Gestured left {data.swipeLeft}";
                    SemanticScreenReader.Announce(Left.Text);
                    break;
                case SwipeDirection.Right:
                    data.swipeRight += 1;
                    Right.Text = $"Gestured right {data.swipeRight}";
                    SemanticScreenReader.Announce(Right.Text);
                    break;
            }
        }
    }
    

  2. There is something seriously wrong with it, that failed me on several occasions in the last months.

    Here for example: https://github.com/dotnet/maui/issues/7403

    It is working in some cases, you cant write normally custom controls however.

    Try adding it, as the very first example, here:
    https://learn.microsoft.com/en-us/dotnet/maui/fundamentals/gestures/swipe?view=net-maui-7.0

    Also, Tap gesture will fire anyway. (This is why you will see many swipe controls, to have double tap effect, not tap).

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search