在Xamarin forms中添加长按手势识别器

7

请问如何在Xamarin Forms应用程序中识别长按手势?

这是我创建的XAML页面,参考了此主题:Xamarin.forms.DataGrid

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataGridSample_01"
xmlns:dg="clr-namespace:Xamarin.Forms.DataGrid;assembly=Xamarin.Forms.DataGrid"
x:Class="DataGridSample_01.MainPage">

 <ContentView BackgroundColor="White" Padding="20" >
  <dg:DataGrid ItemsSource="{Binding Data}" SelectionEnabled="True" RowHeight="70" HeaderHeight="50" BorderColor="#CCCCCC" HeaderBackground="#E0E6F8" ActiveRowColor="#8899AA">
     <dg:DataGrid.Columns>
     <dg:DataGridColumn Title="Logo" PropertyName="Logo" Width="50" SortingEnabled="False">
        <dg:DataGridColumn.CellTemplate>
           <DataTemplate>
              <Image Source="{Binding}" HorizontalOptions="Center" VerticalOptions="Center" Aspect="AspectFit" HeightRequest="60" />
           </DataTemplate>
        </dg:DataGridColumn.CellTemplate>
     </dg:DataGridColumn>
     <dg:DataGridColumn Title="Team" PropertyName="Name" Width="2*" >
     </dg:DataGridColumn>
     <dg:DataGridColumn Title="Win" PropertyName="Win" Width="2*">
        <dg:DataGridColumn.CellTemplate>
           <DataTemplate>
              <Picker x:Name="Fruits" Title="Fruits" HorizontalOptions="FillAndExpand">
                 <Picker.Items>
                    <x:String>Apple</x:String>
                    <x:String>Mango</x:String>
                    <x:String>PineApple</x:String>
                    <x:String>Orange</x:String>
                 </Picker.Items>
              </Picker>
           </DataTemplate>
        </dg:DataGridColumn.CellTemplate>
     </dg:DataGridColumn>
     <dg:DataGridColumn Title="Loose" PropertyName="Loose"  Width="1*">                    
     </dg:DataGridColumn>
     <dg:DataGridColumn PropertyName="Home">
        <dg:DataGridColumn.FormattedTitle>
           <FormattedString>
              <Span Text="Home" ForegroundColor="Black" FontSize="13" FontAttributes="Bold"/>
              <Span Text=" (win-loose)" ForegroundColor="#333333" FontSize="11" />
           </FormattedString>
        </dg:DataGridColumn.FormattedTitle>
     </dg:DataGridColumn>
     <dg:DataGrid.RowsBackgroundColorPalette>
        <dg:PaletteCollection>
           <Color>#FFFFFF</Color>
        </dg:PaletteCollection>
     </dg:DataGrid.RowsBackgroundColorPalette>
  </dg:DataGrid>
 </ContentView>
</ContentPage>

我想在图像控件上添加长按手势识别器。我试着参考这个StackOverflow Thread来实现它,但好像不起作用。
我很新手,请帮忙。非常感谢。

如果您失败了,请考虑使用Mr.Gestures NuGet。 - Nick Kovalsky
2个回答

14

现在不需要自己定义效果,因为Xamarin Community Toolkit包中已经存在TouchEffect(这是一个收集了许多常用的可重用控件、效果、行为和转换器等内容的包)。

xaml命名空间:

 xmlns:xct="http://xamarin.com/schemas/2020/toolkit"

使用示例

您可以设置长按触发命令所需的持续时间,或者将其默认为500毫秒。在此示例中,LongPressCommand 将在2秒后被触发。

<Image Source="{Binding}" HorizontalOptions="Center" VerticalOptions="Center"
       Aspect="AspectFit" HeightRequest="60"
       xct:TouchEffect.LongPressCommand="{Binding LongPressCommand}"
       xct:TouchEffect.LongPressDuration="2000"/>
ICommand LongPressCommand = new Command(() =>
            {
                LongPressCount++;
                OnPropertyChanged(nameof(LongPressCount));
            });

此外,您还可以使用可选的LongPressCommandParameterCommandParameter相同,在其中绑定自定义参数到您的命令。

资源

文档(正在编写中)https://learn.microsoft.com/zh-cn/xamarin/community-toolkit/

代码库 https://github.com/xamarin/XamarinCommunityToolkit/

https://www.youtube.com/watch?v=BcFlZMhPmVk


如果您将其应用于Picker控件,则会失去选择项目的能力,有什么线索吗? - Caverna
1
出于好奇,为什么要将长按手势应用于选择器?如果您认为这是一个错误,您可以随时在官方存储库中报告或开启讨论。 - Cfun

3
您可以使用EffectLongPressGestureRecognizer添加到任何控件中。
在Forms中,创建一个新的共享效果。
using System;
using System.Windows.Input;
using Xamarin.Forms;

namespace App15
{
  public class LongPressedEffect : RoutingEffect
  {
    public LongPressedEffect() : base("MyApp.LongPressedEffect")
    {

    }

    public static readonly BindableProperty CommandProperty = BindableProperty.CreateAttached("Command", typeof(ICommand), typeof(LongPressedEffect), (object)null);
    public static ICommand GetCommand(BindableObject view)
    {

        //do something you want 
        Console.WriteLine("long press Gesture recognizer has been striked");


        return (ICommand)view.GetValue(CommandProperty);
    }

    public static void SetCommand(BindableObject view, ICommand value)
    {
        view.SetValue(CommandProperty, value);

    }


    public static readonly BindableProperty CommandParameterProperty = BindableProperty.CreateAttached("CommandParameter", typeof(object), typeof(LongPressedEffect), (object)null);
    public static object GetCommandParameter(BindableObject view)
    {

        return view.GetValue(CommandParameterProperty);
    }

    public static void SetCommandParameter(BindableObject view, object value)
    {
        view.SetValue(CommandParameterProperty, value);
    }
  }
}

在Android项目中:
using System;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

using App15;
using App15.Droid;    

[assembly: ResolutionGroupName("MyApp")]
[assembly: ExportEffect(typeof(AndroidLongPressedEffect), "LongPressedEffect")]
namespace AndroidAppNamespace.Effects
{

  public class AndroidLongPressedEffect : PlatformEffect
  {
    private bool _attached;

    public static void Initialize() { }

    public AndroidLongPressedEffect()
    {
    }

    protected override void OnAttached()
    {
        //because an effect can be detached immediately after attached (happens in listview), only attach the handler one time.
        if (!_attached)
        {
            if (Control != null)
            {
                Control.LongClickable = true;
                Control.LongClick += Control_LongClick;
            }
            else
            {
                Container.LongClickable = true;
                Container.LongClick += Control_LongClick;
            }
            _attached = true;
        }
    }


    // Invoke the command if there is one
    private void Control_LongClick(object sender, Android.Views.View.LongClickEventArgs e)
    {
        Console.WriteLine("Invoking long click command");
        var command = LongPressedEffect.GetCommand(Element);
        command?.Execute(LongPressedEffect.GetCommandParameter(Element));
    }


    protected override void OnDetached()
    {
        if (_attached)
        {
            if (Control != null)
            {
                Control.LongClickable = true;
                Control.LongClick -= Control_LongClick;
            }
            else
            {
                Container.LongClickable = true;
                Container.LongClick -= Control_LongClick;
            }
            _attached = false;
        }
    }
}

在iOS项目中。
using Foundation;
using UIKit;
using App15;
using App15.iOS;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

[assembly: ResolutionGroupName("MyApp")]
[assembly: ExportEffect(typeof(iOSLongPressedEffect), "LongPressedEffect")]
namespace App15.iOS
{
  public class iOSLongPressedEffect : PlatformEffect
  {
    private bool _attached;
    private readonly UILongPressGestureRecognizer _longPressRecognizer;

    public iOSLongPressedEffect()
    {
        _longPressRecognizer = new UILongPressGestureRecognizer(HandleLongClick);
    }


    protected override void OnAttached()
    {
        //because an effect can be detached immediately after attached (happens in listview), only attach the handler one time
        if (!_attached)
        {
            Container.AddGestureRecognizer(_longPressRecognizer);
            _attached = true;
        }
    }


    // Invoke the command if there is one       
    private void HandleLongClick(UILongPressGestureRecognizer sender)
    {
        if(sender.State==UIGestureRecognizerState.Began)
        {
            var command = LongPressedEffect.GetCommand(Element);
            command?.Execute(LongPressedEffect.GetCommandParameter(Element));
        }


    }

    protected override void OnDetached()
    {
        if (_attached)
        {
            Container.RemoveGestureRecognizer(_longPressRecognizer);
            _attached = false;
        }
    }

  }
}

现在,您可以将LongPressGestureRecognizer添加到控件中,例如标签或图像。

<Label Text="Long Press Me!" local:LongPressedEffect.Command="{Binding ShowAlertCommand}" local:LongPressedEffect.CommandParameter="{Binding .}">
  <Label.Effects>
      <local:LongPressedEffect />
  </Label.Effects>
</Label>

<Image Source="{Binding}" local:LongPressedEffect.Command="{Binding ShowAlertCommand}" local:LongPressedEffect.CommandParameter="{Binding .}">
   <Image.Effects>
        <local:LongPressedEffect />
   </Image.Effects>
</Image>

若想了解更多有关Effect的细节,请参考此处


11
虽然在StackOverflow上有这段代码很好,但请确保给原始来源以信用-这是正确的做法,也是SO和版权法的法律要求。这似乎是Alex Dunn在2017年发表的Xamarin Tip:Xamarin.Forms长按效果的副本。 - ToolmakerSteve
5
技术细节说明:当然,最终结果不是“GestureRecognizer”,而是“Effect”。因此,不要说“现在你可以将LongPressGestureRecognizer添加到控件中”,更准确的说法是“现在我们可以通过将LongPressedEffect添加到任何控件中来处理长按操作。” - ToolmakerSteve
2
使用此方法会导致在 Android 中添加的 Tap 手势无法被检测到,有什么想法可以修复这个问题吗? - Kikanye

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接