0

I'm developing an application for the Ipad using Monotouch (5.0.4). I have a problem with swipe gestures which I hope someone can help me with, where the swipe gestures calls my target delegate twice.

The specific case is this: In my UINavigationController, I push the first UIViewController (which is then the root) in the overridden method ViewDidLoad. In this view controller, I register a swipe gesture (left), which in its target delegate pushes a new view controller in the navigation controller. This works, also with multiple pushes of different view controllers. However, after the first view controller has been pushed, right swipe gestures (which pops a view controller) calls their delegate twice, and two view controllers are popped. This does not happen in the root view controller.

I've made an isolated test of the problem in this simple class. What it does is to register two swipe recognizers for left and right swipes. Left swipes pushes a new instance of the same view controller, and right swipes pops it. I have tried using selectors instead of NSAction delegates as well, with the same result.

    public class SwipeTest : UIViewController
{
    public override void LoadView ()
    {
        base.LoadView ();

        // Create left swipe recognizer
        UISwipeGestureRecognizer leftRecognizer = new UISwipeGestureRecognizer ();
        leftRecognizer.Direction = UISwipeGestureRecognizerDirection.Left;
        leftRecognizer.Delegate = new UIGestureRecognizerDelegate ();
        leftRecognizer.AddTarget (new NSAction (OnSwipeLeft));
        View.AddGestureRecognizer (leftRecognizer);

        // Create right swipe recognizer
        UISwipeGestureRecognizer rightRecognizer = new UISwipeGestureRecognizer ();
        rightRecognizer.Direction = UISwipeGestureRecognizerDirection.Right;
        rightRecognizer.Delegate = new UIGestureRecognizerDelegate ();
        rightRecognizer.AddTarget (new NSAction (OnSwipeRight));
        View.AddGestureRecognizer (rightRecognizer);
    }

    public override void ViewWillDisappear (bool animated)
    {
        base.ViewWillDisappear (animated);
    }

    private void OnSwipeLeft ()
    {
        Console.WriteLine ("swipe left");

        NavigationManager.Instance.PushViewController (new SwipeTest (), true);
    }

    private void OnSwipeRight ()
    {
        Console.WriteLine ("swipe right");

        NavigationManager.Instance.PopViewControllerAnimated (true);
    }
}

NavigationManager is my UINavigationController, it is a singleton, but doesn't do much else.

    public class NavigationManager : UINavigationController
{
    #region Singleton

    class Nested
    {
        static Nested () {}

        internal static readonly NavigationManager instance = new NavigationManager();
    }

    public static NavigationManager Instance
    {
        get { return Nested.instance; }
    }

    #endregion

    #region Private fields

    private UIViewController firstController;

    private UIViewController root;

    #endregion

    #region Constructor

    private NavigationManager ()
    {
        // Set first view
        //firstController = new InitializationView ();
        firstController = new SwipeTest ();
    }

    #endregion

    #region Methods

    public override void ViewDidLoad ()
    {
        PushViewController (firstController, false);

        base.ViewDidLoad ();
    }

    #endregion

    #region Properties

    public UIViewController RootController
    {
        get {
            return root;
        }
        set {
            root = value;

            ViewControllers = new UIViewController[1] {value};
        }
    }

    #endregion
}

So, to recap: Left swipes (pushing a view controller) works, right swipes (popping a view controller) works the first time while at the root controller (so it doesn't actually do anything), but after a view controller has been pushed (after the root controller), right swipes calls the delegate twice.

I hope someone has an idea as to why this happens, I have run out of things with my knowledge of Monotouch to try.

jub
  • 43
  • 1
  • 7
  • Maybe LoadView is called several times, creating more than one gesture recognizers? – Rolf Bjarne Kvinge Jan 03 '12 at 14:30
  • I had actually not tested that (or I forgot), but sadly that wasn't the problem. Thanks for the suggestion though :) – jub Jan 03 '12 at 15:29
  • I think you can remove where you are setting the `Delegate` on each recognizer, although I don't think this is going to cause your issue. Can you post a quick project on GitHub, etc. that reproduces this? – jonathanpeppers Jan 04 '12 at 13:12
  • On left swipes, you create another `SwipeTest`, assigning it delegates and new targets, without removing targets for the current one. That may be the cause of the double triggering. Try printing object's handle in `OnSwipeRight` method, I wouldn't be surprised if it's fired twice, but from two different instances of your `SwipeTest` class. – psycho Jan 04 '12 at 15:14
  • psycho: I have tried that actually, assigned them names, but both calls was the same instance. – jub Jan 04 '12 at 15:25
  • Jonathan.Peppers: I've never used github before, but the code I posted is everything I use in the test case. – jub Jan 04 '12 at 15:26

1 Answers1

2

You've probably long since figured this out, but here is a handy Swipe extension method that I came up with.

In LoadView call:

View.Swipe(UISwipeGestureRecognizerDirection.Right).Event += (s, r) =>
    new UIAlertView("Swipe Test", "Swipe " + r.Direction.ToString(), null, "Ok")
        .Show();
Chuck Savage
  • 11,775
  • 6
  • 49
  • 69