Recently I came up with a great solution. As you know, Xamarin forms have no event or gesture recognizer for longpress. So today I came up with a simple solution using Rendering.
Let's create a shared custom control in our shared code (form project), name the class CustomImage, and Inherit it with Xamarin.Forms.Image
CustomImage.cs
- public class CustomImage : Image
- {
- public static readonly BindableProperty LongpressCommandProperty =
- BindableProperty.Create(nameof(LongpressCommand), typeof(ICommand), typeof(CustomImage), null);
- public ICommand LongpressCommand
- {
- get { return (ICommand)GetValue(LongpressCommandProperty); }
- set { SetValue(LongpressCommandProperty, value); }
- }
- public static readonly BindableProperty CommandProperty =
- BindableProperty.Create(nameof(Command), typeof(ICommand), typeof(CustomImage), null);
- public ICommand Command
- {
- get { return (ICommand)GetValue(CommandProperty); }
- set { SetValue(CommandProperty, value); }
- }
- public static readonly BindableProperty CommandParameterProperty = BindableProperty.Create("CommandParameter", typeof(object), typeof(CustomImage), (object)null);
- public object CommandParameter
- {
- get { return GetValue(CommandParameterProperty); }
- set { SetValue(CommandParameterProperty, value); }
- }
- /// <summary>
- /// Long press event.
- /// If the Content or its children have gesture recognizers set, in order to prevent gesture conflicts, it is recommended to set their InputTransparent property to True.
- /// </summary>
- public event EventHandler LongPressed
- {
- add { LongPressedHandler += value; }
- remove { LongPressedHandler -= value; }
- }
- public EventHandler LongPressedHandler;
- /// <summary>
- /// Tap event.
- /// If the Content or its children have gesture recognizers set, in order to prevent gesture conflicts, it is recommended to set their InputTransparent property to True.
- /// </summary>
- public event EventHandler Tapped
- {
- add { TappedHandler += value; }
- remove { TappedHandler -= value; }
- }
- public EventHandler TappedHandler;
- }
Now we have 3 bindable properties – the Longpress
the
Command that we want to bind when the longpress detects the command when Tap is detected andthe
CommandParameter passes into the Command. We can use these in our native Renderer implementations to invoke when the press is detected. Let’s create our Android implementation.
In Android project,
CustomImageRenderer.cs
- [assembly: ExportRenderer(typeof(CustomImage), typeof(CustomImageRenderer))]
- namespace LongpressSample.Droid.CustomRenderer
- {
- public class CustomImageRenderer : ImageRenderer
- {
- private CustomImage _view;
- public CustomImageRenderer(Context context) : base(context) { }
- protected override void OnElementChanged(ElementChangedEventArgs<Image> e)
- {
- base.OnElementChanged(e);
- if (e.NewElement != null)
- {
- _view = e.NewElement as CustomImage;
- }
- Control.SoundEffectsEnabled = true;
- Control.LongClickable = true;
- Control.LongClick += (s, ea) =>
- {
- if (_view != null)
- {
- _view.LongPressedHandler?.Invoke(_view, ea);
- var command = _view.LongpressCommand;// CustomImage.GetCommand(_view);
- command?.Execute(_view);
- }
- };
- Control.Clickable = true;
- Control.Click += (s, ea) =>
- {
- if (_view != null)
- {
- _view.TappedHandler?.Invoke(_view, ea);
- var command = _view.Command;// CustomImage.GetCommand(_view);
- command?.Execute(_view);
- }
- };
- }
- }
Now in IOS,
CustomImageRenderer.cs
- [assembly: ExportRenderer(typeof(CustomImage), typeof(CutomImageRenderer))]
- namespace LongpressSample.iOS.CustomRenderer
- {
- public class CutomImageRenderer : ImageRenderer
- {
- private CustomImage _view;
- private readonly UILongPressGestureRecognizer _longPressRecognizer;
- private readonly UITapGestureRecognizer _tapGestureRecognizer;
- public CutomImageRenderer()
- {
- _longPressRecognizer = new UILongPressGestureRecognizer((s) =>
- {
- if (s.State == UIGestureRecognizerState.Began && _view != null)
- {
- _view.LongPressedHandler?.Invoke(_view, null);
- var command = _view.LongpressCommand;// CustomImage.GetCommand(_view);
- command?.Execute(_view);
- }
- });
- _tapGestureRecognizer = new UITapGestureRecognizer(() =>
- {
- _view.TappedHandler?.Invoke(_view, null);
- var command = _view.Command;// CustomImage.GetCommand(_view);
- command?.Execute(_view);
- });
- }
- protected override void OnElementChanged(ElementChangedEventArgs<Image> e)
- {
- base.OnElementChanged(e);
- if (e.NewElement != null)
- {
- _view = e.NewElement as CustomImage;
- }
- if (Control != null)
- {
- Control.UserInteractionEnabled = true;
- Control.AddGestureRecognizer(_longPressRecognizer);
- Control.AddGestureRecognizer(_tapGestureRecognizer);
- }
- }
- }
- }






gadda rajuPosted Jun 15, 2021, 2:44 PM
Excellent article thank you bro.
Colin SpearPosted Feb 16, 2021, 3:03 PM
Excellent article thank you. Especially helpful to a newbie to Xamarin such as myself. I have one query. I used this custom renderer to replace a current image that also used a PanGestureRecognizer. After implementation the Tap and LongPress events work perfectly but the PanGestureRecognizer is not. I cannot see any reason why this event is not triggered unless it is being consumed by the LongPress event handler? Is there perhaps something obvious I am missing?
Sean FranklinPosted Jun 10, 2020, 12:09 AM
Nice article