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建议的解决方案。 开始了…
-
在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); } }
-
在各个项目中创建特定于平台的按钮渲染器
对于安道尔
[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(); }; } } } -
在页面中实例化自定义按钮
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开始, Pressed
和Released
事件开箱即用(参见PR )。
注意:为了实现Walkie Talkie效果,您可能希望使用Device.BeginInvokeOnMainThread
(或通过Prism的IDeviceService
)来调用后续操作,以便调用Released
事件,否则可能会阻止UI线程。
或者,您可以将事件处理程序声明为async
并await
您的调用,以保持UI线程不被占用。