3

I am trying to get long touch gestures into my xamarin app. I have a view where a tap brings you to an edit screen & a long touch reveals an options menu. I followed this guide on SO about implementing such a thing. The item I want to be long touchable is a Frame, so I wrote an extension for Frame. Here is this class:

public class FrameWithLongTouchGesture : Frame
{
    public FrameWithLongTouchGesture()
    {
    }

    public EventHandler LongPressActivated;

    public void HandleLongPress(object sender, EventArgs e)
    {
        //Handle LongPressActivated Event
        EventHandler eventHandler = this.LongPressActivated;
        eventHandler?.Invoke((object)this, EventArgs.Empty);
    }
}

As you can see I have added an event handler to this object. Now I then went about implementing a custom renderer for each platform, I started with iOS (since I am an iOS dev). Worked absolutely no problem, took 5 minutes to get working. So now I've come round to android, this should be even easier since the post I linked earlier shows you how to implement the renderer in android... great!....

Not so great :( No long touch event is handled AT ALL with the exact code in the post. I have set breakpoints, tried to write to the console but the gesture event handler is never fired. I can even see that the phone receives a touch down event because it prints to the console when I run it on my test device. I have absolutely no idea why android isn't letting me recognise this gesture, I have also played around with androids GestureDetector but that never fired either. Here is my android renderer:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Diagnostics;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

using Android.Content;
using Android.Views;
using Android.Widget;

using LongTouchGestureDemo;
using LongTouchGestureDemo.Droid;

[assembly: ExportRenderer(typeof(FrameWithLongTouchGesture), typeof(FrameWithLongTouchGestureRenderer))]

namespace LongTouchGestureDemo.Droid
{
    public class FrameWithLongTouchGestureRenderer : FrameRenderer
    {
        FrameWithLongTouchGesture view;
        //GestureDetector gesture;

        public FrameWithLongTouchGestureRenderer(Context context) : base(context)
        {
            //gesture = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener());

            this.LongClick += (object sender, LongClickEventArgs e) => {
                view.HandleLongPress(sender, e);
            };
        }

        protected override void OnElementChanged(ElementChangedEventArgs<Frame> e)
        {
            base.OnElementChanged(e);

            if (e.NewElement != null)
            {
                view = e.NewElement as FrameWithLongTouchGesture;
            }
        }
    }
}

This is really frustrating because I cannot seem to implement core functionality into the android app. It doesn't help that I have no experience developing android, it doesnt seem as easy to implement gestures in droid as it does in iOS unfortunately :/

All help and suggestions are welcomed! Thanks

Bodungus
  • 175
  • 14
  • 2
    I think you can achieve the desired behavior with an effect! A colleague of mine did a great write-up on the subject: https://alexdunn.org/2017/12/27/xamarin-tip-xamarin-forms-long-press-effect/ – Joe Feb 22 '18 at 17:57
  • 1
    Yes check out Alex Dunn's article for sure. I followed that to implement some down click and up click functionality and it worked like a charm. – GBreen12 Feb 22 '18 at 20:59

1 Answers1

5

You need a custom Gesture Listener to manage the long press. Here is the basic structure:

public class FrameWithLongTouchGestureRenderer : FrameRenderer
{
    FrameWithLongTouchGesture view;
    readonly MyGestureListener _listener;
    readonly Android.Views.GestureDetector _detector;

    public FrameWithLongTouchGestureRenderer()
    {
        _listener = new MyGestureListener();
        _detector = new GestureDetector(_listener);
    }

    protected override void OnElementChanged(ElementChangedEventArgs<Frame> e)
    {
        base.OnElementChanged(e);

        if (e.NewElement != null)
        {
            view = e.NewElement as FrameWithLongTouchGesture;
            UpdateEventHandlers();
        }
    }

    private void UpdateEventHandlers()
    {
        _listener.MyFrame = view;

        GenericMotion += (s, a) => _detector.OnTouchEvent(a.Event);
        Touch += (s, a) => _detector.OnTouchEvent(a.Event);
    }
}

And then your Gesture Listener:

internal class MyGestureListener : GestureDetector.SimpleOnGestureListener
{
    public FrameWithLongTouchGesture MyFrame { private get; set; }

    public override void OnLongPress(MotionEvent e)
    {
        base.OnLongPress(e);

        if (MyFrame != null)
        {
            MyFrame.HandleLongPress(this, new System.EventArgs());
        }
    }
}
sme
  • 4,023
  • 3
  • 28
  • 42
  • I will have a look into this however I was more after an android implementation. My Frame extension class works with iOS, it was a 5 minutes job to get this working in iOS. I'm more looking for how to add a touch gesture listener to a frame in xamarin android, if that makes sense? – Bodungus Feb 25 '18 at 17:11
  • The code is for Android. Its working fine in my projects – sme Feb 25 '18 at 17:16
  • I've got round to looking at gestures and this worked, Your answer was a better version of this //http://arteksoftware.com/gesture-recognizers-with-xamarin-forms/. I struggled on that for a bit as I was unable to callback to my frame. Thanks alot this really helped! (although it annoyingly disables the xamarin forms gesture so I've had to conditionally add a single tapped event that i only raise on android) – Bodungus Mar 01 '18 at 17:00