c# - Xamarin.Android 点击手势和长按手势不能一起工作

标签 c# android xamarin xamarin.forms xamarin.android

我通过子类化 RoutingEffect 创建了自定义效果,以便为 iOSAndroid 允许 LongPressGesture在我的 Xamarin 项目中。

我在我共享项目的 XAML 中的 Image 上使用了这个效果,而这个 Image 也使用了 TapGesture,见下面代码:

                <Image x:Name="TapRight" Grid.Row="4" Grid.Column="2"  Source="right64" 
                   VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand"
                   IsEnabled="{Binding RightEnabled}"
                   Opacity="{Binding RightEnabled, Converter={StaticResource OpacityConverter}}"
                   effects:LongPressEffect.Command="{Binding LongPressGestureCommand}"
                   effects:LongPressEffect.CommandParameter="{x:Static common:NavType.Right}">
                <Image.GestureRecognizers>
                    <TapGestureRecognizer 
                        Command="{Binding TapGestureNavCommand}" 
                        NumberOfTapsRequired="1"
                        CommandParameter="{x:Static common:NavType.Right}"/>
                </Image.GestureRecognizers>
                <Image.Effects>
                        <effects:LongPressEffect></effects:LongPressEffect>
                </Image.Effects>
            </Image>

这适用于 iOS(当我点击和长按图像时我获得了不同的功能),但是对于 Android,它只允许我做 Long按下,但不执行 TapGesture 的命令,关于如何解决此问题的任何想法?

注意:如果我使用 Button 而不是 Image 它工作正常。但是,我真的很想使用 Image

我在下面添加了更多代码以供引用:

共享项目中的效果代码:

using System.Windows.Input;
using Xamarin.Forms;


namespace MyApp.Effects
{

    public class LongPressEffect : RoutingEffect
    {
        public LongPressEffect() : base("Xamarin.LongPressEffect")
        {

        }

        public static readonly BindableProperty CommandProperty =
         BindableProperty.CreateAttached("Command",
             typeof(ICommand),
             typeof(LongPressEffect),
             (object)null,
             propertyChanged: OnCommandChanged);

        public static ICommand GetCommand(BindableObject view)
        {
            return (ICommand)view.GetValue(CommandProperty);
        }

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

        static void OnCommandChanged(BindableObject bindable, object oldValue, object newValue)
        {
            var view = bindable as View;
            if (view == null)
            {
                return;
            }
            ICommand command = (ICommand)newValue;
            if (command != null)
            {
                view.SetValue(CommandProperty, command);
            }

        }

        public static readonly BindableProperty CommandParameterProperty =
            BindableProperty.CreateAttached("CommandParameter",
                typeof(object),
                typeof(LongPressEffect),
                (object)null,
                propertyChanged: OnCommandParameterChanged);

        public static object GetCommandParameter(BindableObject view)
        {
            return (object)view.GetValue(CommandParameterProperty);
        }

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

        static void OnCommandParameterChanged(BindableObject bindable, object oldValue, object newValue)
        {
            var view = bindable as View;
            if (view == null)
            {
                return;
            }
            object commandParameter = (object)newValue;
            if (commandParameter != null)
            {
                view.SetValue(CommandParameterProperty, commandParameter);
            }
        }
    }
}

iOS 效果代码:

using System;
using System.ComponentModel;
using MyApp.Effects;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

[assembly: ResolutionGroupName("Xamarin")]
[assembly:ExportEffect (typeof(MyApp.iOS.Effects.LongPressEffect), "LongPressEffect")]
namespace MyApp.iOS.Effects
{
    public class LongPressEffect : PlatformEffect
    {
        private readonly UILongPressGestureRecognizer _longPressGestureRecognizer;
        private bool _attached;
        public LongPressEffect()
        {
            _longPressGestureRecognizer = new UILongPressGestureRecognizer(HandleLongClick);
            _attached = false;

        }

        protected override void OnAttached()
        {
            if (!_attached)
            {
                Container.AddGestureRecognizer(_longPressGestureRecognizer);
                _attached = true;
            }
        }

        private void HandleLongClick()
        {
            if (_longPressGestureRecognizer.State == UIGestureRecognizerState.Ended)
                // Only execute when the press is ended.
            {
                var command = MyApp.Effects.LongPressEffect.GetCommand(Element);
                command?.Execute(MyApp.Effects.LongPressEffect.GetCommandParameter(Element));
            }
        }

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

        protected override void OnElementPropertyChanged(PropertyChangedEventArgs args)
        {
            base.OnElementPropertyChanged(args);
        }
    }
}

Android 中的效果代码:

using System;
using System.ComponentModel;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

[assembly: ResolutionGroupName("Xamarin")]
[assembly: ExportEffect(typeof(MyApp.Droid.Effects.LongPressEffect), "LongPressEffect")]
namespace MyApp.Droid.Effects
{
    public class LongPressEffect: PlatformEffect
    {
        private bool _attached;
        public static void Initialize() { }
        public LongPressEffect()
        {
            _attached = false;

        }

        protected override void OnAttached()
        {
            Console.WriteLine("Invoking long click command...");
            //throw new NotImplementedException();
            if (!_attached) {
                if (Control != null)
                {
                    Control.LongClickable = true;
                    Control.LongClick += HandleLongClick;
                }
                _attached = true;
            }
        }

        private void HandleLongClick(object sender, Android.Views.View.LongClickEventArgs e) {
            Console.WriteLine("Invoking long click command...");
            var command = MyApp.Effects.LongPressEffect.GetCommand(Element);
            command?.Execute(MyApp.Effects.LongPressEffect.GetCommandParameter(Element));

        }

        protected override void OnDetached()
        {
            //throw new NotImplementedException();
            if (_attached) {
                if (Control != null) {
                    Control.LongClickable = true;
                    Control.LongClick -= HandleLongClick;
                }
                _attached = false;
            }
        }

        protected override void OnElementPropertyChanged(PropertyChangedEventArgs args)
        {
            base.OnElementPropertyChanged(args);
        }
    }
}

最佳答案

这是 Xamarin 中的一个错误,可以找到更多详细信息 here

作为解决方法,我使用了 ImageButton 或 Android 和 Image for IOS,并使可见性平台依赖。我的 XAML 现在看起来像这样:

<ImageButton x:Name="Tap" Grid.Row="4" Grid.Column="2" Source="right64" 
       IsEnabled="{Binding RightEnabled}"
       Opacity="{Binding RightEnabled, Converter={StaticResource OpacityConverter}}"     
       effects:LongPressEffect.Command="{Binding LongPressGestureCommand}"
       effects:LongPressEffect.CommandParameter="{x:Static common:NavType.Right}"
       Command="{Binding TapGestureNavCommand}"
       CommandParameter="{x:Static common:NavType.Right}">
       <ImageButton.IsVisible>
            <OnPlatform x:TypeArguments="x:Boolean"
                        iOS="False"
                        Android="True"/>
       </ImageButton.IsVisible>
       <ImageButton.Effects>
           <effects:LongPressEffect></effects:LongPressEffect>
       </ImageButton.Effects>
</ImageButton>

<!--Due to different behaviour on platform(s) different views were needed for different platforms.-->

<Image x:Name="TapIOS" Grid.Row="4" Grid.Column="2"  Source="right64" 
        IsEnabled="{Binding RightEnabled}"
        Opacity="{Binding RightEnabled, Converter={StaticResource OpacityConverter}}"    
        effects:LongPressEffect.Command="{Binding LongPressGestureCommand}"
        effects:LongPressEffect.CommandParameter="{x:Static common:NavType.Right}">
    <Image.IsVisible>
        <OnPlatform x:TypeArguments="x:Boolean"
                    iOS="True"
                    Android="False"/>
    </Image.IsVisible>
    <Image.GestureRecognizers>
         <TapGestureRecognizer
             NumberOfTapsRequired="1"
             Command="{Binding TapGestureNavCommand}"
             CommandParameter="{x:Static common:NavType.Right}"/>
    </Image.GestureRecognizers>
    <Image.Effects>
          <effects:LongPressEffect></effects:LongPressEffect>
    </Image.Effects>
</Image>

关于c# - Xamarin.Android 点击手势和长按手势不能一起工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58698063/

相关文章:

c# - Migradoc 封面图片

c# - 必须初始化隐式类型的局部变量

c# - 如何在 Xamarin Forms 中部分切割 ViewCell 分隔线?

android - com.android.support :appcompat-v7 and design version 23. 2.0 崩溃包裹错误

android - 底部工具栏菜单项提示出现在顶部

android - Xamarin Forms BarBackground 在 Android 上丢失

c# - 如何在 MVVM 模式 wpf 中绑定(bind) StrokeDashArray 属性

Android Async Task 一个接一个

android - 从 android Webview 中托管的网站获取用户登录详细信息

c# - 与 android xamarin 中的命名空间混淆