Using UIGestureRecognizer in MonoTouch

Gesture Recognisers are a great feature added in iOS 3.2 (ages ago!), and using them in MonoTouch couldn’t be simpler. I’ll skip over a discussion on how they work, if you want more info on the recognisers themselves, be sure to check out the Apple documentation.

Selectors

UIGestureRecognizer instances use selectors to call back methods in your class. Selectors are supported in MonoTouch, you just need to do a little more work:

[Export("ViewTapSelector")]
protected void OnViewTapped(UIGestureRecognizer sender)
{
    MessageLabel.Text = "View Tapped";
}

Essentially you need to create a method, then mark it for export. This tells the MonoTouch compiler to make the method callable by ObjC code. Make sure the containing class is decorated with the Register attribute (ViewControllers are automatically registered).

First Recogniser

Setting up a UIGestureRecognizer is very easy:

var tapRecogniser = new UITapGestureRecognizer(this, new MonoTouch.ObjCRuntime.Selector("ViewTapSelector"));
View.AddGestureRecognizer(tapRecogniser);

This creates a new recogniser, with a callback and assigns it to the root view for the controller. You don’t need to worry about garbage collection since the view will retain the recogniser. You can access all of the recognisers for a view by using the GestureRecognizers property.

That’s it!

Surprisingly that’s all there is to it! You can download an example project here, or just view the code snippet below to flesh out the principles:

Sample Code

private void SetupGestureRecognisers()
{
    var tapRecogniser = new UITapGestureRecognizer(this, new MonoTouch.ObjCRuntime.Selector("ViewTapSelector"));
    View.AddGestureRecognizer(tapRecogniser);

    var doubleTapRecogniser = new UITapGestureRecognizer(this, new MonoTouch.ObjCRuntime.Selector("ViewDoubleTapSelector"));
    doubleTapRecogniser.NumberOfTapsRequired = 3;
    View.AddGestureRecognizer(doubleTapRecogniser);

    var longPressRecogniser = new UILongPressGestureRecognizer(this, new MonoTouch.ObjCRuntime.Selector("LongPressSelector"));
    View.AddGestureRecognizer(longPressRecogniser);

    var panRecogniser = new UIPanGestureRecognizer(this, new MonoTouch.ObjCRuntime.Selector("LabelPanSelector"));
    DragLabel.AddGestureRecognizer(panRecogniser);
}

[Export("ViewTapSelector")]
protected void OnViewTapped(UIGestureRecognizer sender)
{
    MessageLabel.Text = "View Tapped";
}

[Export("ViewDoubleTapSelector")]
protected void OnViewDoubleTapped(UIGestureRecognizer sender)
{
    MessageLabel.Text = "View Triple Tapped";
}

[Export("LongPressSelector")]
protected void OnLongPress(UIGestureRecognizer sender)
{
    MessageLabel.Text = "View Long Pressed";
}

[Export("LabelPanSelector")]
protected void OnLabelPan(UIGestureRecognizer sender)
{
    var panRecogniser = sender as UIPanGestureRecognizer;

    if (panRecogniser == null)
        return;

    switch (panRecogniser.State)
    {
        case UIGestureRecognizerState.Began:
            _originalPosition = DragLabel.Frame.Location;
            break;

        case UIGestureRecognizerState.Cancelled:
        case UIGestureRecognizerState.Failed:
            DragLabel.Frame = new RectangleF(_originalPosition, DragLabel.Frame.Size);
            break;

        case UIGestureRecognizerState.Changed:
            var movement = panRecogniser.TranslationInView(View);
            var newPosition = new PointF(movement.X + _originalPosition.X, movement.Y + _originalPosition.Y);
            DragLabel.Frame = new RectangleF(newPosition, DragLabel.Frame.Size);
            break;
    }
}

4 comments

Mike Bluestein

Nice post Dan!

In addition to using a selector, you can also use the overload that takes an action and provide a lambda expression that is passed the gesture, like this:

var longPress = new UILongPressGestureRecognizer ((g) => {
Console.WriteLine (g.LocationInView (View));
});
View.AddGestureRecognizer (longPress);

Cheers,
Mike

Thanks Mike! I’m not seeing that overload in my version of MonoTouch.UIKit?

Thanks Mike, I had problem with selector on nested class, this works for me.. Cheers

thanks a lot. it helped me a lot

Leave a Reply