Drag and Drop

When drag and drop was introduced in iOS 11, we made it a priority to support and incorporate this capability, beginning with PSPDFKit 7 for iOS. Now users can drag and drop various elements from and to an application that integrates PSPDFKit.

Drag Interactions

There are various elements users can initiate a drag from. The following interactions are currently possible with PSPDFKit:

  • Dragging images embedded on a document page.
  • Dragging text from a document page.

Drop Interactions

Additionally, users can drop elements on a document page, and these elements are then converted into PDF annotations. Here is the list of drop interactions that are currently supported:

  • Dropping text on a document page. The text will be converted into a free text annotation.
  • Dropping an image on a document page. The image will be converted into an image stamp annotation.
  • Dropping a PDF on a document page. The PDF will be converted into an image stamp annotation of the first page of the dropped document.

Customizing Drag and Drop

All drag-and-drop interactions are enabled by default. However, you can selectively control specific drag-and-drop components using PSPDFDragAndDropConfiguration. This might be interesting for you if you provide an application that serves documents with sensitive data.

PSPDFDragAndDropConfiguration can be constructed the same way as the main PSPDFConfiguration class. To customize a drag-and-drop configuration, you can set a PSPDFDragAndDropConfiguration object to the dragAndDropConfiguration property of PSPDFConfiguration, like so:

Copy
1
2
3
4
5
6
7
let configuration = PSPDFConfiguration { builder in
    let dragAndDropConfiguration = PSPDFDragAndDropConfiguration { dragAndDropConfigurationBuilder in
        // Customize the drag-and-drop configuration.
    }
    builder.dragAndDropConfiguration = dragAndDropConfiguration
}
let pdfController = PSPDFViewController(document: document, configuration: configuration)
Copy
1
2
3
4
5
6
7
PSPDFConfiguration *configuration = [PSPDFConfiguration configurationWithBuilder:^(PSPDFConfigurationBuilder *builder) {
    PSPDFDragAndDropConfiguration *dragAndDropConfiguration = [PSPDFDragAndDropConfiguration configurationWithBuilder:^(PSPDFDragAndDropConfigurationBuilder *dragAndDropConfigurationBuilder) {
        // Customize the drag-and-drop configuration.
    }];
    builder.dragAndDropConfiguration = dragAndDropConfiguration;
}];
PSPDFViewController *pdfController = [[PSPDFViewController alloc] initWithDocument:document configuration:configuration];

Control Drag Elements

The configuration of elements that users can initiate a drag from can be controlled via allowedDragTypes. By default, all types are allowed.

If you only want to allow dragging text from a document, you can configure this as follows:

1
dragAndDropConfigurationBuilder.allowedDragTypes = .text
1
dragAndDropConfigurationBuilder.allowedDragTypes = PSPDFDragTypeText;

Control Drag Targets

Drags that were initiated from a source application can be dropped either into the same application or into another application.

To restrict dragging inside the source application, you can disable allowDraggingToExternalApps.

Control Drop Elements

Configuring elements that users can drop onto a document page can be controlled via allowedDropTypes. By default, all types are accepted.

If you only want to accept dropping images and PDFs onto a document, you can configure this as follows:

1
dragAndDropConfigurationBuilder.acceptedDropTypes = [.image, .PDF]
1
dragAndDropConfigurationBuilder.acceptedDropTypes = PSPDFDropTypeImage | PSPDFDropTypePDF;

Control Drop Targets

Drop elements can be dropped on document pages, which can be customized via allowedDropTargets. By default, this is allowed for drags from any other page in the document, apart from the current one, and for drags from an external application.

To allow drops from all targets, including the document page where the drag was initiated from, use the following code:

1
dragAndDropConfigurationBuilder.allowedDropTargets = .all
1
dragAndDropConfigurationBuilder.allowedDropTargets = PSPDFDropTargetAll;

Custom Interactions

In case the built-in drag-and-drop support is not meeting your requirements, you can also handle drag-and-drop interactions completely yourself. Reasons for this might be to validate the interactions or to create custom annotations for a drop.

In such a case, you can use your own drag-and-drop interactions instead of using our default ones. This can be done by adding your custom interactions to a PSPDFPageView subclass and handling the drag or drop there. Additionally, you might want to disable our default interactions, so as to not cause conflicts with your custom interactions via PSPDFDragAndDropConfiguration.

To add a custom interaction for handling drops, you can use the following logic:

Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class PageView: PSPDFPageView {
    override init(frame: CGRect) {
        super.init(frame: frame)

        let dropInteraction = UIDropInteraction(delegate: self)
        self.addInteraction(dropInteraction)
    }
}

extension PageView: UIDropInteractionDelegate {

    func dropInteraction(_ interaction: UIDropInteraction, canHandle session: UIDropSession) -> Bool {
        return true
    }

    func dropInteraction(_ interaction: UIDropInteraction, sessionDidUpdate session: UIDropSession) -> UIDropProposal {
        return UIDropProposal(operation: .copy)
    }

    func dropInteraction(_ interaction: UIDropInteraction, performDrop session: UIDropSession) {
        // Handle drop
    }
}

let configuration = PSPDFConfiguration { builder in
    let dragAndDropConfiguration = PSPDFDragAndDropConfiguration { dragAndDropBuilder in
        dragAndDropBuilder.allowDraggingToExternalApps = false
        dragAndDropBuilder.acceptedDropTypes = []
        dragAndDropBuilder.allowedDragTypes = []
        dragAndDropBuilder.allowedDropTargets = []
    }
    builder.dragAndDropConfiguration = dragAndDropConfiguration

    builder.overrideClass(PSPDFPageView.self, with: PageView.self)
}

let controller = PSPDFViewController(document: document, configuration: configuration)
Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
@interface PSCPageView : PSPDFPageView <UIDropInteractionDelegate> @end
@implementation PSCPageView

- (instancetype)initWithFrame:(CGRect)frame {
    if ((self = [super initWithFrame:frame])) {
        UIDropInteraction *dropInteraction = [[UIDropInteraction alloc] initWithDelegate:self];
        [self addInteraction:dropInteraction];
    }
    return self;
}

- (BOOL)dropInteraction:(UIDropInteraction *)interaction canHandleSession:(id<UIDropSession>)session {
    return YES;
}

- (UIDropProposal *)dropInteraction:(UIDropInteraction *)interaction sessionDidUpdate:(id<UIDropSession>)session {
    return [[UIDropProposal alloc] initWithDropOperation:UIDropOperationCopy];
}

- (void)dropInteraction:(UIDropInteraction *)interaction performDrop:(id<UIDropSession>)session {
    // Handle drop
}

@end

PSPDFConfiguration *configuration = [PSPDFConfiguration configurationWithBuilder:^(PSPDFConfigurationBuilder *builder) {
    PSPDFDragAndDropConfiguration *dragAndDropConfiguration = [PSPDFDragAndDropConfiguration configurationWithBuilder:^(PSPDFDragAndDropConfigurationBuilder *dragAndDropBuilder) {
        dragAndDropBuilder.allowDraggingToExternalApps = NO;
        dragAndDropBuilder.acceptedDropTypes = PSPDFDropTypeNone;
        dragAndDropBuilder.allowedDragTypes = PSPDFDragTypeNone;
        dragAndDropBuilder.allowedDropTargets = PSPDFDropTargetNone;
    }];
    builder.dragAndDropConfiguration = dragAndDropConfiguration;

    [builder overrideClass:PSPDFPageView.class withClass:PSCPageView.class];
}];
PSPDFViewController *controller = [[PSCKioskPDFViewController alloc] initWithDocument:document configuration:configuration];