Longpress Event For Image In Xamarin.Forms

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
  1. public class CustomImage : Image  
  2.    {  
  3.   
  4.        public static readonly BindableProperty LongpressCommandProperty =  
  5.       BindableProperty.Create(nameof(LongpressCommand), typeof(ICommand), typeof(CustomImage), null);  
  6.   
  7.        public ICommand LongpressCommand  
  8.        {  
  9.            get { return (ICommand)GetValue(LongpressCommandProperty); }  
  10.            set { SetValue(LongpressCommandProperty, value); }  
  11.        }  
  12.   
  13.        public static readonly BindableProperty CommandProperty =  
  14.      BindableProperty.Create(nameof(Command), typeof(ICommand), typeof(CustomImage), null);  
  15.   
  16.        public ICommand Command  
  17.        {  
  18.            get { return (ICommand)GetValue(CommandProperty); }  
  19.            set { SetValue(CommandProperty, value); }  
  20.        }  
  21.   
  22.        public static readonly BindableProperty CommandParameterProperty = BindableProperty.Create("CommandParameter"typeof(object), typeof(CustomImage), (object)null);  
  23.         
  24.        public object CommandParameter  
  25.        {  
  26.            get { return GetValue(CommandParameterProperty); }  
  27.            set { SetValue(CommandParameterProperty, value); }  
  28.        }  
  29.   
  30.         
  31.   
  32.        /// <summary>  
  33.        /// Long press event.  
  34.        /// 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.  
  35.        /// </summary>  
  36.        public event EventHandler LongPressed  
  37.        {  
  38.            add { LongPressedHandler += value; }  
  39.            remove { LongPressedHandler -= value; }  
  40.        }  
  41.        public EventHandler LongPressedHandler;  
  42.   
  43.        /// <summary>  
  44.        /// Tap event.  
  45.        /// 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.  
  46.        /// </summary>  
  47.        public event EventHandler Tapped  
  48.        {  
  49.            add { TappedHandler += value; }  
  50.            remove { TappedHandler -= value; }  
  51.        }  
  52.        public EventHandler TappedHandler;  
  53.   
  54.         
  55.   
  56.   
  57.    }  
Now we have 3 bindable properties – the LongpressCommand that we want to bind when the longpress detects the command when Tap is detected and
the 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 
  1. [assembly: ExportRenderer(typeof(CustomImage), typeof(CustomImageRenderer))]  
  2. namespace LongpressSample.Droid.CustomRenderer  
  3. {  
  4.       
  5.     public class CustomImageRenderer : ImageRenderer  
  6.     {  
  7.         private CustomImage _view;  
  8.   
  9.         public CustomImageRenderer(Context context) : base(context) { }  
  10.   
  11.         protected override void OnElementChanged(ElementChangedEventArgs<Image> e)  
  12.         {  
  13.             base.OnElementChanged(e);  
  14.   
  15.   
  16.             if (e.NewElement != null)  
  17.             {  
  18.                 _view = e.NewElement as CustomImage;  
  19.             }  
  20.   
  21.             Control.SoundEffectsEnabled = true;  
  22.   
  23.             Control.LongClickable = true;  
  24.             Control.LongClick += (s, ea) =>  
  25.             {  
  26.                 if (_view != null)  
  27.                 {  
  28.                     _view.LongPressedHandler?.Invoke(_view, ea);  
  29.                     var command = _view.LongpressCommand;// CustomImage.GetCommand(_view);  
  30.                      command?.Execute(_view);  
  31.   
  32.                 }  
  33.             };  
  34.   
  35.             Control.Clickable = true;  
  36.             Control.Click += (s, ea) =>  
  37.             {  
  38.                 if (_view != null)  
  39.                 {  
  40.                     _view.TappedHandler?.Invoke(_view, ea);  
  41.                     var command = _view.Command;// CustomImage.GetCommand(_view);  
  42.                     command?.Execute(_view);  
  43.                 }  
  44.             };  
  45.         }  
  46.     }  
Now in IOS,
 
CustomImageRenderer.cs
  1. [assembly: ExportRenderer(typeof(CustomImage), typeof(CutomImageRenderer))]  
  2. namespace LongpressSample.iOS.CustomRenderer  
  3. {  
  4.     public class CutomImageRenderer : ImageRenderer  
  5.     {  
  6.         private CustomImage _view;  
  7.         private readonly UILongPressGestureRecognizer _longPressRecognizer;  
  8.         private readonly UITapGestureRecognizer _tapGestureRecognizer;  
  9.   
  10.         public CutomImageRenderer()  
  11.         {  
  12.             _longPressRecognizer = new UILongPressGestureRecognizer((s) =>  
  13.             {  
  14.                 if (s.State == UIGestureRecognizerState.Began && _view != null)  
  15.                 {  
  16.                    _view.LongPressedHandler?.Invoke(_view, null);  
  17.                     var command = _view.LongpressCommand;// CustomImage.GetCommand(_view);  
  18.                     command?.Execute(_view);  
  19.                 }  
  20.             });  
  21.   
  22.             _tapGestureRecognizer = new UITapGestureRecognizer(() =>  
  23.             {  
  24.                   
  25.                 _view.TappedHandler?.Invoke(_view, null);  
  26.                 var command = _view.Command;// CustomImage.GetCommand(_view);  
  27.                 command?.Execute(_view);  
  28.             });  
  29.         }  
  30.   
  31.         protected override void OnElementChanged(ElementChangedEventArgs<Image> e)  
  32.         {  
  33.             base.OnElementChanged(e);  
  34.   
  35.             if (e.NewElement != null)  
  36.             {  
  37.                 _view = e.NewElement as CustomImage;  
  38.             }  
  39.   
  40.               
  41.   
  42.             if (Control != null)  
  43.             {  
  44.                 Control.UserInteractionEnabled = true;  
  45.                 Control.AddGestureRecognizer(_longPressRecognizer);  
  46.                 Control.AddGestureRecognizer(_tapGestureRecognizer);  
  47.             }  
  48.         }  
  49.     }  
  50. }   
Now create a Model for images so that we can use it for our list of images:
  1. public  class ImageModel  
  2.     {  
  3.         public string Image { getset; }  
  4.         public int ImageId { getset; }  
  5.     }  
After that create a view model for main page,
  1. public class ImageVM  
  2.    {  
  3.        public ImageVM()  
  4.        {  
  5.            ImageModels = new List<ImageModel>  
  6.            {  
  7.                new ImageModel{ImageId=1,Image="download.jfif"},  
  8.                new ImageModel{ImageId=2,Image="download1.jfif"},  
  9.                new ImageModel{ImageId=3,Image="download2.jfif"},  
  10.                new ImageModel{ImageId=4,Image="download3.png"},  
  11.                new ImageModel{ImageId=5,Image="download4.jfif"},  
  12.                new ImageModel{ImageId=6,Image="download.jfif"},  
  13.                new ImageModel{ImageId=7,Image="download5.png"},  
  14.                new ImageModel{ImageId=8,Image="images6.jfif"},  
  15.                new ImageModel{ImageId=9,Image="images7.jfif"},  
  16.                new ImageModel{ImageId=10,Image="images8.jfif"},  
  17.            };  
  18.        }  
  19.        public ICommand LongPressCommand  
  20.        {  
  21.            get  
  22.            {  
  23.                return new Command(() =>  
  24.                {  
  25.                    App.Current.MainPage.DisplayAlert("LongPress Command""This is long press command""OK");  
  26.                });  
  27.            }  
  28.        }  
  29.        public ICommand TappCommand  
  30.        {  
  31.            get  
  32.            {  
  33.                return new Command(() =>  
  34.                {  
  35.                    App.Current.MainPage.DisplayAlert("Tapp Command""This is Tap command""OK");  
  36.                });  
  37.            }  
  38.        }  
  39.        public List<ImageModel> ImageModels { getset; }  
  40.    }  
Here we create a list of ImageModels that we will bind with listview in our main page, we also create two commands - one for longpress and the other one for single tap which we will bind with image.
 
Now that we have our 2 (Android and IOS) implementations, let’s use it in our XAML! 
  1. <?xml version="1.0" encoding="utf-8" ?>    
  2. <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"    
  3.              xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"    
  4.              xmlns:d="http://xamarin.com/schemas/2014/forms/design"    
  5.              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"    
  6.              xmlns:customimage="clr-namespace:LongpressSample.CustomControl"    
  7.              mc:Ignorable="d"    
  8. xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"  
  9. ios:Page.UseSafeArea="true"  
  10.              x:Class="LongpressSample.MainPage">    
  11.     
  12.     <StackLayout>    
  13.         <Label Text="Image with binable Command" HorizontalOptions="CenterAndExpand" FontSize="Medium"/>    
  14.         <customimage:CustomImage  Source="download.jfif"  Aspect="AspectFit" HeightRequest="100" WidthRequest="100"     
  15.                                   Command="{Binding TappCommand}"    
  16.                                   LongpressCommand="{Binding LongPressCommand}">    
  17.     
  18.         </customimage:CustomImage>    
  19.         <Label Text="List of Images with events" HorizontalOptions="CenterAndExpand" FontSize="Medium"/>    
  20.         <ListView ItemsSource="{Binding ImageModels}" HasUnevenRows="True" RowHeight="50">    
  21.             <ListView.ItemTemplate>    
  22.                 <DataTemplate>    
  23.                     <ViewCell>    
  24.                         <StackLayout>    
  25.                         <customimage:CustomImage  ClassId="{Binding ImageId}" Source="{Binding Image}" HorizontalOptions="Start"    
  26.                                                   Aspect="Fill" HeightRequest="150" WidthRequest="150"     
  27.                                                   LongPressed="CustomImage_LongPressed"    
  28.                                                   Tapped="CustomImage_Tapped">    
  29.                                
  30.                         </customimage:CustomImage>    
  31.                         </StackLayout>    
  32.                     </ViewCell>    
  33.                 </DataTemplate>    
  34.             </ListView.ItemTemplate>    
  35.         </ListView>    
  36.     </StackLayout>    
  37.     
  38. </ContentPage>    
Now .cs code of the main page where we set BindingContext for page and implement events for Image .
  1. public partial class MainPage : ContentPage  
  2.    {  
  3.        public MainPage()  
  4.        {  
  5.            InitializeComponent();  
  6.            BindingContext = new ImageVM();  
  7.        }  
  8.   
  9.        private void CustomImage_Tapped(object sender, EventArgs e)  
  10.        {  
  11.            var image = (sender) as Image;  
  12.            DisplayAlert("Tapped Event",$"You Tapped on image {image.ClassId}""OK");  
  13.        }  
  14.   
  15.        private void CustomImage_LongPressed(object sender, EventArgs e)  
  16.        {  
  17.            var image = (sender) as Image;  
  18.            DisplayAlert("Longpress Event", $"Longpress on image {image.ClassId}""OK");  
  19.        }  
  20.    }  
And that's itLongpress Event For Image In Xamarin.Forms
 
Note
Commands for Image will not work in Listview or Collectionview 
 
Please leave your comment if you have any query.
 
if you want to give any suggestions or if you think i have to change or improve the code, I would be happy to hear from you .
 
Thank you! 
 
Output 
 
Longpress Event For Image In Xamarin.FormsLongpress Event For Image In Xamarin.Forms
Longpress Event For Image In Xamarin.FormsLongpress Event For Image In Xamarin.Forms 
Longpress Event For Image In Xamarin.Forms