Xamarin.Forms – 按下按钮并释放事件

我希望我的事件在按下和释放按钮时触发,但我只能在Xamarin.Forms中找到Click事件。

我相信必须有一些工作来获得这个function。 我的基本需求是在按下按钮时启动一个过程,在释放按钮时停止 。 它似乎是一个非常基本的function,但Xamarin.Forms现在没有它。

我在按钮上尝试了TapGestureRecognizer,但按钮只触发了点击事件。

MyButton.Clicked += (sender, args) => { Log.V(TAG, "CLICKED"); }; var tapGestureRecognizer = new TapGestureRecognizer(); tapGestureRecognizer.Tapped += (s, e) => { Log.V(TAG, "TAPPED"); }; MyButton.GestureRecognizers.Add(tapGestureRecognizer); 

请记住,我需要这些事件在Android和iOS中正常工作。

最后我得到了@Jason建议的解决方案。 开始了…

  1. 在PCL项目中创建Xamarin.Forms.Button的子类,具有事件处理function

     public class CustomButton : Button { public event EventHandler Pressed; public event EventHandler Released; public virtual void OnPressed() { Pressed?.Invoke(this, EventArgs.Empty); } public virtual void OnReleased() { Released?.Invoke(this, EventArgs.Empty); } } 
  2. 在各个项目中创建特定于平台的按钮渲染器

    对于安道尔

     [assembly: ExportRenderer(typeof(Button), typeof(CustomButtonRenderer))] namespace WalkieTalkie.Droid.Renderer { public class CustomButtonRenderer : ButtonRenderer { protected override void OnElementChanged(ElementChangedEventArgs e) { base.OnElementChanged(e); var customButton = e.NewElement as CustomButton; var thisButton = Control as Android.Widget.Button; thisButton.Touch += (object sender, TouchEventArgs args) => { if (args.Event.Action == MotionEventActions.Down) { customButton.OnPressed(); } else if (args.Event.Action == MotionEventActions.Up) { customButton.OnReleased(); } }; } } } 

    对于IOS

     [assembly: ExportRenderer(typeof(CustomButton), typeof(CustomButtonRenderer))] namespace WalkieTalkie.iOS.Renderer { public class CustomButtonRenderer : ButtonRenderer { protected override void OnElementChanged(ElementChangedEventArgs e) { base.OnElementChanged(e); var customButton = e.NewElement as CustomButton; var thisButton = Control as UIButton; thisButton.TouchDown += delegate { customButton.OnPressed(); }; thisButton.TouchUpInside += delegate { customButton.OnReleased(); }; } } } 
  3. 在页面中实例化自定义按钮

     var myButton = new CustomButton { Text = "CustomButton", HorizontalOptions = LayoutOptions.FillAndExpand }; myButton.Pressed += (sender, args) => { System.Diagnostics.Debug.WriteLine("Pressed"); }; myButton.Released += (sender, args) => { System.Diagnostics.Debug.WriteLine("Pressed"); }; 

希望这能帮助别人:)

这也可以使用效果而不是完整的自定义渲染器来完成。 有关如何操作的说明,请参阅此文章:

https://alexdunn.org/2017/12/27/xamarin-tip-xamarin-forms-long-press-effect/

如果该post消失,这里是您可以实现的代码:

在共享项目中:

 ///  /// Long pressed effect. Used for invoking commands on long press detection cross platform ///  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) { 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中:

 [assembly: ResolutionGroupName("MyApp")] [assembly: ExportEffect(typeof(AndroidLongPressedEffect), "LongPressedEffect")] namespace AndroidAppNamespace.Effects { ///  /// Android long pressed effect. ///  public class AndroidLongPressedEffect : PlatformEffect { private bool _attached; ///  /// Initializer to avoid linking out ///  public static void Initialize() { } ///  /// Initializes a new instance of the ///  class. /// Empty constructor required for the odd Xamarin.Forms reflection constructor search ///  public AndroidLongPressedEffect() { } ///  /// Apply the handler ///  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 ///  /// Sender. /// E. 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)); } ///  /// Clean the event handler on detach ///  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中:

 [assembly: ResolutionGroupName("MyApp")] [assembly: ExportEffect(typeof(iOSLongPressedEffect), "LongPressedEffect")] namespace iOSNamespace.Effects { ///  /// iOS long pressed effect ///  public class iOSLongPressedEffect : PlatformEffect { private bool _attached; private readonly UILongPressGestureRecognizer _longPressRecognizer; ///  /// Initializes a new instance of the ///  class. ///  public iOSLongPressedEffect() { _longPressRecognizer = new UILongPressGestureRecognizer(HandleLongClick); } ///  /// Apply the handler ///  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() { var command = LongPressedEffect.GetCommand(Element); command?.Execute(LongPressedEffect.GetCommandParameter(Element)); } ///  /// Clean the event handler on detach ///  protected override void OnDetached() { if (_attached) { Container.RemoveGestureRecognizer(_longPressRecognizer); _attached = false; } } } } 

在XAML中

  
 Button button = FindViewById (Resource.Id.myButton); button.Touch += (object sender, View.TouchEventArgs e) => { if (e.Event.Action == MotionEventActions.Up) { Toast.MakeText(this, "Key Up", ToastLength.Short).Show(); } if(e.Event.Action == MotionEventActions.Down) { Toast.MakeText(this, "Key Down", ToastLength.Short).Show(); } }; 

从Xamarin.Forms 2.4.0开始, PressedReleased事件开箱即用(参见PR )。

注意:为了实现Walkie Talkie效果,您可能希望使用Device.BeginInvokeOnMainThread (或通过Prism的IDeviceService )来调用后续操作,以便调用Released事件,否则可能会阻止UI线程。
或者,您可以将事件处理程序声明为asyncawait您的调用,以保持UI线程不被占用。