---
title: "Customize user interactions in iOS PDF viewer | Nutrient SDK"
canonical_url: "https://www.nutrient.io/guides/ios/customizing-the-interface/handling-user-interactions/"
md_url: "https://www.nutrient.io/guides/ios/customizing-the-interface/handling-user-interactions.md"
last_updated: "2026-06-19T09:21:00.297Z"
description: "This guide discusses how Nutrient handles user interactions and presents some examples of how this mechanism can be customized to achieve the desired behavior."
---

# Customize user interactions on iOS

This guide discusses how Nutrient handles user interactions and presents some examples of how this mechanism can be customized to achieve the desired behavior.

## Overview of user interaction components

The starting point of working with user interactions is the [`interactions`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/pdfviewcontroller/interactions) property of [`PDFViewController`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/pdfviewcontroller), which contains a set of **user interaction components**. These are objects responsible for handling single or multiple user interactions. In addition, they can be customized and observed.

Below is a table showing each component and what it’s responsible for.

<!-- Text in the first column breaks because the second column contains
longer text. Unfortunately, Markdown doesn’t support setting widths of
table columns, and using plain HTML would require us to hardcode links in
<a> elements. Instead, we’ll wrap the Markdown table inside a container
and customize it using CSS. Best of both worlds! -->

| Component                                                                      | Responsible for...                                                                          |
| ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------- |
| [`selectAnnotation`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/documentviewinteractions/selectannotation)       | Selecting annotations on a page.                                                            |
| [`deselectAnnotation`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/documentviewinteractions/deselectannotation)   | Discarding the current annotation selection.                                                |
| [`transformAnnotation`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/documentviewinteractions/transformannotation) | Moving, resizing, and adjusting the currently selected annotations.                         |
| [`editAnnotation`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/documentviewinteractions/editannotation)           | Initiating the editing of form elements, free text annotations, and link annotations.       |
| [`openLinkAnnotation`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/documentviewinteractions/openlinkannotation)   | “Opening” link annotations, i.e. executing their actions.                                   |
| [`fastScroll`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/documentviewinteractions/fastscroll)                   | Changing pages by tapping near the edges of a document.                                     |
| [`smartZoom`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/documentviewinteractions/smartzoom)                     | Zooming in on and out of content on a page.                                                 |
| [`toggleUserInterface`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/documentviewinteractions/toggleuserinterface) | Toggling the user interface.                                                                |
| [`selectText`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/documentviewinteractions/selecttext)                   | Selecting images on a page. Before 14.2, this also handled text selection. Deprecated.      |
| [`deselectText`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/documentviewinteractions/deselecttext)               | Discarding an image selection. Before 14.2, this also handled text deselection. Deprecated. |

There are also three user interaction components that are composed of other user interaction components. You can use them to conveniently customize several user interaction components at once.

| Component                                                                                  | Composed of...                                      |
| ------------------------------------------------------------------------------------------ | --------------------------------------------------- |
| [`allAnnotationInteractions`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/documentviewinteractions/allannotationinteractions) | All components related to annotations.              |
| [`allTextInteractions`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/documentviewinteractions/alltextinteractions)             | All components related to text and image selection. |
| [`allInteractions`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/documentviewinteractions/allinteractions)                     | All components.                                     |

## Customizing the user interaction components

By default, all user interaction components are enabled. To disable one, you can use its [`isEnabled`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/interactioncomponent/isenabled) property. For example, the following line will disable all user interaction components related to annotations:

### SWIFT

```swift

interactions.allAnnotationInteractions.isEnabled = false

```

### OBJECTIVE-C

```objc

interactions.allAnnotationInteractions.enabled = NO;

```

For more advanced use cases, you can take advantage of **activation conditions** to allow or disallow certain user interaction components to proceed only if a particular requirement is met. Activation condition closures have three parameters: a `context` object that provides information about a user interaction; a `point` at which it is taking place; and a [`coordinateSpace`](https://developer.apple.com/documentation/uikit/uicoordinatespace) in which the aforementioned `point` is provided. For example, to disallow selecting annotations on a certain page, you can write the following:

### SWIFT

```swift

interactions.selectAnnotation.addActivationCondition { context, point, coordinateSpace in
    return context.pageView.pageIndex!= 0
}

```

### OBJECTIVE-C

```objc

[interactions.selectAnnotation addActivationCondition:^BOOL(PSPDFAnnotationSelectionContext *context, CGPoint point, id<UICoordinateSpace> coordinateSpace) {
    return context.pageView.pageIndex!= 0;
}];

```

Some user interaction components, like [`toggleUserInterface`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/documentviewinteractions/toggleuserinterface), have no additional information they can provide except a `point` and a [`coordinateSpace`](https://developer.apple.com/documentation/uikit/uicoordinatespace). Therefore, the type of their `context` will be `NSNull`.

You can add as many activation conditions to a user interaction component as you want. They will be evaluated in the order they were added until one of them returns `false`. This means they’re not suitable for performing side effects. To learn more about performing side effects when a user interaction occurs, check out the following section.

## Responding to user interaction components

If you want to respond to a certain user interaction without modifying its behavior, you can take advantage of **activation callbacks**. Activation callback closures have the exact same parameters as activation condition closures and are executed _just before_ a user interaction takes place. For example, to print a console message every time a smart zoom is performed, you can write the following:

### SWIFT

```swift

interactions.smartZoom.addActivationCallback { context, point, coordinateSpace in
    print("Will smart zoom to: \(context.targetRect) in: \(context.scrollView)")
}

```

### OBJECTIVE-C

```objc

[interactions.smartZoom addActivationCallback:^(PSPDFSmartZoomContext *context, CGPoint point, id<UICoordinateSpace> coordinateSpace) {
    NSLog(@"Will smart zoom to: %@ in: %@", NSStringFromCGRect(context.targetRect), context.scrollView);
}];

```

It’s not possible to prevent a user interaction from taking place when inside an activation callback closure. To learn about preventing a user interaction from taking place, check out the previous section or use [`PDFViewControllerDelegate`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/pdfviewcontrollerdelegate) methods related to tapping on annotations.

Make sure you’re not creating any strong reference cycles when using activation conditions and callbacks. If you’re adding them in a subclass of [`PDFViewController`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/pdfviewcontroller) and you need to call `self` from within, make sure to capture it weakly using `[weak self]` (or using a `__weak` variable in Objective-C). For more information about strong reference cycles in closures, check out Apple’s [Automatic Reference Counting](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/automaticreferencecounting/#Strong-Reference-Cycles-for-Closures) article.

## Working with custom gesture recognizers

User interaction components were designed to work seamlessly with your own gesture recognizers. They provide a set of functions you can use to set up both failure and simultaneous recognition relationships between them and your own gesture recognizers.

To avoid conflicts with Nutrient’s built-in interactions, specify what should take priority by using these APIs to set up relationships:

- If your gesture recognizer should have priority, use [`InteractionComponent.require(toFail:)`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/interactioncomponent/require(tofail:)).

- If the built-in interaction should have priority, use [`UIGestureRecognizer.require(toFail:)`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/uikit/uigesturerecognizer/require(tofail:)).

- If both should activate for the same touch, use [`InteractionComponent.allowSimultaneousRecognition(with:)`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/interactioncomponent/allowsimultaneousrecognition(with:)).

For example, to add a long-press gesture recognizer that takes priority over selecting text and images but should only begin if selecting an annotation failed, you can write the following:

### SWIFT

```swift

// Create your gesture recognizer.
let longPressGestureRecognizer = UILongPressGestureRecognizer()
longPressGestureRecognizer.addTarget(self, action: #selector(longPressGestureRecognizerDidChangeState))

longPressGestureRecognizer.delegate = self

// Set up the failure requirements with other components.
longPressGestureRecognizer.require(toFail: interactions.selectAnnotation)
interactions.allTextInteractions.require(toFail: longPressGestureRecognizer)

// Add your gesture recognizer to the document view controller's view.
documentViewController?.view.addGestureRecognizer(gestureRecognizer)

// Decide whether your gesture recognizer should begin.
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
    return /* condition */
}

// Perform your action.
@objc func longPressGestureRecognizerDidChangeState(_ gestureRecognizer: UIGestureRecognizer) {
    /* action */
}

```

### OBJECTIVE-C

```objc

// Create your gesture recognizer.
UILongPressGestureRecognizer *longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] init];
[longPressGestureRecognizer addTarget:self action:@selector(longPressGestureRecognizerDidChangeState)];
longPressGestureRecognizer.delegate = self;

// Set up the failure requirements with other components.
[longPressGestureRecognizer pspdf_requireGestureRecognizersInComponentToFail:interactions.selectAnnotation];
[interactions.selectAnnotation requireGestureRecognizerToFail:longPressGestureRecognizer];

// Add your gesture recognizer to the document view controller's view.
[documentViewController.view addGestureRecognizer:longPressGestureRecognizer];

// Decide whether your gesture recognizer should begin.

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
    return /* condition */
}

// Perform your action.

- (void)longPressGestureRecognizerDidChangeState:(UIGestureRecognizer *)gestureRecognizer {
    /* action */
}

```

Using the [`gestureRecognizerShouldBegin(_:)`](https://developer.apple.com/documentation/uikit/uigesturerecognizerdelegate/1624213-gesturerecognizershouldbegin) delegate method is crucial if you’re setting up requirements between the built-in interaction components and your own gesture recognizer. If you don’t implement it, your gesture recognizer will never fail. This, in turn, effectively blocks the interaction component that depends on it from ever proceeding. To learn more, check out Apple’s articles on [coordinating multiple gesture recognizers](https://developer.apple.com/documentation/uikit/touches_presses_and_gestures/coordinating_multiple_gesture_recognizers) and the [gesture recognizer state machine](https://developer.apple.com/documentation/uikit/touches_presses_and_gestures/implementing_a_custom_gesture_recognizer/about_the_gesture_recognizer_state_machine).

You can have your gesture recognizer work simultaneously with the built-in interaction components, but this may create a confusing user experience where two actions happen for one tap. For example, to add a double-tap gesture recognizer that triggers alongside smart zoom, write the following:

### SWIFT

```swift

// Create your gesture recognizer.
let doubleTapGestureRecognizer = UITapGestureRecognizer()
doubleTapGestureRecognizer.addTarget(self, action: #selector(doubleTapGestureRecognizerDidChangeState))

doubleTapGestureRecognizer.numberOfTapsRequired = 2

// Set up the simultaneous recognition relationship with the smart zoom component.
interactions.smartZoom.allowSimultaneousRecognition(with: doubleTapGestureRecognizer)

// Add your gesture recognizer to the document view controller's view.
documentViewController?.view.addGestureRecognizer(doubleTapGestureRecognizer)

// Perform your action.
@objc func doubleTapGestureRecognizerDidChangeState(_ gestureRecognizer: UIGestureRecognizer) {
    /* action */
}

```

### OBJECTIVE-C

```objc

// Create your gesture recognizer.
UITapGestureRecognizer *doubleTapGestureRecognizer = [[UITapGestureRecognizer alloc] init];
[doubleTapGestureRecognizer addTarget:self action:@selector(doubleTapGestureRecognizerDidChangeState)];
doubleTapGestureRecognizer.numberOfTapsRequired = 2;

// Set up the simultaneous recognition relationship with the smart zoom component.
[interactions.smartZoom allowSimultaneousRecognitionWithGestureRecognizer:doubleTapGestureRecognizer];

// Add your gesture recognizer to the document view controller's view.
[documentViewController.view addGestureRecognizer:doubleTapGestureRecognizer];

// Perform your action.

- (void)doubleTapGestureRecognizerDidChangeState:(UIGestureRecognizer *)gestureRecognizer {
    /* action */
}

```

Not all user interaction components are backed by gesture recognizers, and some of them may be backed by gesture recognizers just on one specific version of iOS. Make sure to thoroughly read the [documentation of individual components](https://www.nutrient.io/api/ios/documentation/pspdfkitui/pdfviewcontroller/interactions) before using them, and keep an eye on our [changelog](https://www.nutrient.io/guides/ios/changelog.md) for any changes related to user interactions.

### Dynamic gesture recognizer relationships

If your gesture recognizer uses dynamic failure or simultaneous recognition relationship resolution, you can use [`contains(_:)`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/interactioncomponent/contains(_:)) to check whether or not a received gesture recognizer is managed by Nutrient:

### SWIFT

```swift

// Require failure if the given gesture recognizer is part of any component.
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool {
    return interactions.allInteractions.contains(otherGestureRecognizer)
}

// Allow simultaneous recognition if the given gesture recognizer is part of a text selection component.
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
    return interactions.allTextInteractions.contains(otherGestureRecognizer)
}

```

### OBJECTIVE-C

```objc

// Require failure if the given gesture recognizer is part of any component.

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
    return [interactions.allInteractions containsGestureRecognizer:otherGestureRecognizer];
}

// Allow simultaneous recognition if the given gesture recognizer is part of a text selection component.

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
    return [interactions.allTextInteractions containsGestureRecognizer:otherGestureRecognizer];
}

```

### Reimplementing existing user interactions

The [`interactions`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/pdfviewcontroller/interactions) property provides a selection of methods that can be used from within your custom gesture recognizers’ actions and delegate methods to effectively reimplement certain user interactions using your own means.

For example, to use a double-tap gesture recognizer to select annotations, you must first disable the default [`selectAnnotation`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/documentviewinteractions/selectannotation) user interaction component, then evaluate its activation conditions in the [`gestureRecognizerShouldBegin(_:)`](https://developer.apple.com/documentation/uikit/uigesturerecognizerdelegate/1624213-gesturerecognizershouldbegin) delegate method, and finally, call [`tryToSelectAnnotation(at:in:)`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/documentviewinteractions/trytoselectannotation(at:in:)) to commit the action:

### SWIFT

```swift

// Create your gesture recognizer.
let doubleTapGestureRecognizer = UITapGestureRecognizer()
doubleTapGestureRecognizer.addTarget(self, action: #selector(doubleTapGestureRecognizerDidChangeState))

doubleTapGestureRecognizer.delegate = self
doubleTapGestureRecognizer.numberOfTapsRequired = 2

// Disable the default component.
interactions.selectAnnotation.isEnabled = false

// Set up the failure requirements with other components.
interactions.allInteractions.require(toFail: doubleTapGestureRecognizer)

// Add your gesture recognizer to the document view controller's view.
documentViewController?.view.addGestureRecognizer(doubleTapGestureRecognizer)

// Ask the default component if it can activate at the given location.
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
    let view = gestureRecognizer.view!
    let point = gestureRecognizer.location(in: view)
    return interactions.selectAnnotation.canActivate(at: point, in: view)
}

// Try to select an annotation at the given location.
@objc func doubleTapGestureRecognizerDidChangeState(_ gestureRecognizer: UIGestureRecognizer) {
    if gestureRecognizer.state ==.ended {
        let view = gestureRecognizer.view!
        let point = gestureRecognizer.location(in: view)
        interactions.tryToSelectAnnotation(at: point, in: view)
    }
}

```

### OBJECTIVE-C

```objc

// Create your gesture recognizer.
UITapGestureRecognizer *doubleTapGestureRecognizer = [[UITapGestureRecognizer alloc] init];
[doubleTapGestureRecognizer addTarget:self action:@selector(doubleTapGestureRecognizerDidChangeState)];
doubleTapGestureRecognizer.delegate = self;
doubleTapGestureRecognizer.numberOfTapsRequired = 2;

// Disable the default component.
interactions.selectAnnotation.enabled = NO;

// Set up the failure requirements with other components.
[interactions.allInteractions requireGestureRecognizerToFail:doubleTapGestureRecognizer];

// Add your gesture recognizer to the document view controller's view.
[documentViewController.view addGestureRecognizer:doubleTapGestureRecognizer];

// Ask the default component if it can activate at the given location.

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
    UIView *view = gestureRecognizer.view;
    CGPoint point = [gestureRecognizer locationInView:view];
    return [interactions.selectAnnotation canActivateAtPoint:point inCoordinateSpace:view];
}

// Try to select an annotation at the given location.

- (void)doubleTapGestureRecognizerDidChangeState:(UIGestureRecognizer *)gestureRecognizer {
    if (gestureRecognizer.state == UIGestureRecognizerStateEnded) {
        UIView *view = gestureRecognizer.view;
        CGPoint point = [gestureRecognizer locationInView:view];
        [interactions tryToSelectAnnotationAtPoint:point inCoordinateSpace:view];
    }
}

```

Calling the [`canActivate(at:in:)`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/interactioncomponent/canactivate(at:in:)) method will ignore the user interaction component’s [`isEnabled`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/interactioncomponent/isenabled) property, but it will still evaluate its activation conditions. This can prove incredibly useful in advanced use cases where you might want to reimplement a certain user interaction while retaining the custom activation logic.

## Customization examples

### Observing tap and long-press gestures

To observe tap or long-press gestures (or any other gesture, for that matter) without interfering with Nutrient’s built-in interactions (e.g. for analytics), use your own gesture recognizer and set up its simultaneous relationship with other user interaction components:

### SWIFT

```swift

// Create your tap gesture recognizer.
let tapGestureRecognizer = UITapGestureRecognizer()
tapGestureRecognizer.addTarget(self, action: #selector(tapGestureRecognizerDidChangeState))

// Create your long-press gesture recognizer.
let longPressGestureRecognizer = UILongPressGestureRecognizer()
longPressGestureRecognizer.addTarget(self, action: #selector(longPressGestureRecognizerDidChangeState))

// Trigger both at the same time so we don't interfere with built-in interactions.
// If you want one gesture to take priority over the other, set up failure relationships instead of using `allowSimultaneousRecognition`.
interactions.allInteractions.allowSimultaneousRecognition(with: tapGestureRecognizer)
interactions.allInteractions.allowSimultaneousRecognition(with: longPressGestureRecognizer)

// Add your gesture recognizer to the document view controller's view.
documentViewController?.view.addGestureRecognizer(tapGestureRecognizer)
documentViewController?.view.addGestureRecognizer(longPressGestureRecognizer)

// Log the tap gesture.
@objc func tapGestureRecognizerDidChangeState(_ gestureRecognizer: UIGestureRecognizer) {
    if gestureRecognizer.state ==.ended {
            let point = gestureRecognizer.location(in: gestureRecognizer.view!)
            print("Tapped at point: \(point)")
        }
    }
}

// Log the long-press gesture.
@objc func longPressGestureRecognizerDidChangeState(_ gestureRecognizer: UIGestureRecognizer) {
    if gestureRecognizer.state ==.began {
            let point = gestureRecognizer.location(in: gestureRecognizer.view!)
            print("Long-press began at point: \(point)")
        }
    } else if gestureRecognizer.state ==.ended {
            let point = gestureRecognizer.location(in: gestureRecognizer.view!)
            print("Long-press ended at point: \(point)")
        }
    }
}

```

### OBJECTIVE-C

```objc

// Create your tap gesture recognizer.
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] init];
[tapGestureRecognizer addTarget:self action:@selector(tapGestureRecognizerDidChangeState)];

// Create your long-press gesture recognizer.
UITapGestureRecognizer *longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] init];
[longPressGestureRecognizer addTarget:self action:@selector(longPressGestureRecognizerDidChangeState)];

// Set up the failure requirements with other components.
[interactions.allInteractions allowSimultaneousRecognitionWithGestureRecognizer:tapGestureRecognizer];
[interactions.allInteractions allowSimultaneousRecognitionWithGestureRecognizer:longPressGestureRecognizer];

// Add your gesture recognizer to the document view controller's view.
[documentViewController.view addGestureRecognizer:tapGestureRecognizer];
[documentViewController.view addGestureRecognizer:longPressGestureRecognizer];

// Log the tap gesture.

- (void)tapGestureRecognizerDidChangeState:(UIGestureRecognizer *)gestureRecognizer {
    if (gestureRecognizer.state == UIGestureRecognizerStateEnded) {
        CGPoint point = [gestureRecognizer locationInView:gestureRecognizer.view];
        NSLog(@"Tapped at point: %@", NSStringFromCGPoint(point));
    }
}

// Log the long-press gesture.

- (void)tapGestureRecognizerDidChangeState:(UIGestureRecognizer *)gestureRecognizer {
    if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
        CGPoint point = [gestureRecognizer locationInView:gestureRecognizer.view];
        NSLog(@"Long-press began at point: %@", NSStringFromCGPoint(point));
    } else if (gestureRecognizer.state == UIGestureRecognizerStateEnded) {
        CGPoint point = [gestureRecognizer locationInView:gestureRecognizer.view];
        NSLog(@"Long-press ended at point: %@", NSStringFromCGPoint(point));
    }
}

```

### Excluding annotations from being tappable

There are four user interaction components that are responsible for recognizing touches over annotations: [`selectAnnotation`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/documentviewinteractions/selectannotation), [`transformAnnotation`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/documentviewinteractions/transformannotation), [`editAnnotation`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/documentviewinteractions/editannotation), and [`openLinkAnnotation`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/documentviewinteractions/openlinkannotation). You can add activation conditions to appropriate user interaction components to exclude certain annotations from participating:

### SWIFT

```swift

// Prevent ink annotations from being selectable.
interactions.selectAnnotation.addActivationCondition { context, point, coordinateSpace in
    return!(context.annotation is InkAnnotation)
}

// Prevent annotations in a certain PDF rect from being transformable.
interactions.transformAnnotation.addActivationCondition { context, point, coordinateSpace in
    let pdfRect = CGRect(x: 0, y: 0, width: 400, height: 200)
    let pdfPoint = context.pageView.pdfCoordinateSpace.convert(point, from: coordinateSpace)
    return!pdfRect.contains(pdfPoint)
}

// Prevent free text annotations from being editable.
interactions.editAnnotation.addActivationCondition { context, point, coordinateSpace in
    return!(context.annotation is FreeTextAnnotation)
}

// Prevent opening links anywhere except on the first page.
interactions.openLinkAnnotation.addActivationCondition { context, point, coordinateSpace in
    return context.pageView.pageIndex == 0
}

```

### OBJECTIVE-C

```objc

// Prevent ink annotations from being selectable.
[interactions.selectAnnotation addActivationCondition:^BOOL(PSPDFAnnotationSelectionContext *context, CGPoint point, id<UICoordinateSpace> coordinateSpace) {
    return![context.annotation isKindOfClass:PSPDFInkAnnotation.class];
}];

// Prevent annotations in a certain PDF rect from being transformable.
[interactions.transformAnnotation addActivationCondition:^BOOL(PSPDFAnnotationSelectionContext *context, CGPoint point, id<UICoordinateSpace> coordinateSpace) {
    CGRect pdfRect = CGRectMake(0, 0, 400, 200);
    CGPoint pdfPoint = [context.pageView.pdfCoordinateSpace convertPoint:point fromCoordinateSpace:coordinateSpace];
    return!CGRectContainsPoint(pdfRect, pdfPoint);
}];

// Prevent free text annotations from being editable.
[interactions.editAnnotation addActivationCondition:^BOOL(PSPDFAnnotationSelectionContext *context, CGPoint point, id<UICoordinateSpace> coordinateSpace) {
    return![context.annotation isKindOfClass:PSPDFFreeTextAnnotation.class];
}];

// Prevent opening links anywhere except on the first page.
[interactions.openLinkAnnotation addActivationCondition:^BOOL(PSPDFAnnotationSelectionContext<PSPDFLinkAnnotation *> *context, CGPoint point, id<UICoordinateSpace> coordinateSpace) {
    return context.pageView.pageIndex == 0;
}];

```

## Further reading

For more information about the user interaction components API, check out the documentation of the [`DocumentViewInteractions`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/documentviewinteractions) protocol and the [`InteractionComponent`](https://www.nutrient.io/api/ios/documentation/pspdfkitui/interactioncomponent) class.

To learn more about working with multiple gesture recognizers, check out the articles on [coordinating multiple gesture recognizers](https://developer.apple.com/documentation/uikit/touches_presses_and_gestures/coordinating_multiple_gesture_recognizers) and the [gesture recognizer state machine](https://developer.apple.com/documentation/uikit/touches_presses_and_gestures/implementing_a_custom_gesture_recognizer/about_the_gesture_recognizer_state_machine).

If you want to learn more about working with multiple coordinate spaces, check out our [coordinate space conversions](https://www.nutrient.io/guides/ios/faq/coordinate-spaces.md) guide.

The user interaction handling mechanism described in this guide has been available since Nutrient iOS SDK 9.5. If you’re migrating from version 9.4 or lower, check out the [migration guide](https://www.nutrient.io/guides/ios/migration-guides/pspdfkit-9-5-migration-guide.md#migration-cases-for-handling-user-interactions), which showcases various migration cases in more detail.
---

## Related pages

- [Selecting text in our iOS viewer](/guides/ios/features/text-selection.md)
- [Drag and drop text or images in our iOS viewer](/guides/ios/features/drag-and-drop.md)
- [Trackpad and mouse support in our iOS viewer](/guides/ios/features/trackpad-and-mouse-support.md)
- [Keyboard shortcuts in our iOS viewer](/guides/ios/features/keyboard-shortcuts.md)
- [Customize zooming options in our iOS viewer](/guides/ios/miscellaneous/zooming.md)

