Removing highlight annotation with PDFKit
Asked Answered
F

3

0

I am successfully adding a highlight annotation to a pdf using swift and PDFKit, but I am unable to figure out how to let the user remove the highlight again.

The user can select the text normally, and then choose "Highlight" or "Remove highlight" from the UIMenu.

To customise the pdfView when selecting text I have changed the menu that appears - first by removing the default actions:

extension PDFView {
    override public func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        return false
    }
}

Then in viewDidLoad() I've set my custom UIMenuItems:

let menuItem1 = UIMenuItem(title: "Highlight", action: #selector(highlightSelection(_:)))        
let menuItem2 = UIMenuItem(title: "Remove highlight", action: #selector(removeHighlightSelection(_:)))
UIMenuController.shared.menuItems = [menuItem1, menuItem2]

When selecting highlight:

@objc func highlightSelection(_ sender: UIMenuItem) {
            let selections = pdfViewer.currentSelection?.selectionsByLine()
            guard let page = selections?.first?.pages.first else { return }

            selections?.forEach({ selection in
                let highlight = PDFAnnotation(bounds: selection.bounds(for: page), forType: .highlight, withProperties: nil)
                highlight.color = .yellow
                page.addAnnotation(highlight)
            })
    }

So far, so good - all working fine to this point. Text is highlighted and annotation created.

Now comes my issue:

When I select the highlighted text I want the user to be able to remove the highlight annotation by tapping "Remove highlight", but I simply cannot figure out how to remove just the annotation that hides "behind" the selected text.

This code is working, but removing all annotations on the entire page:

@objc func removeHighlightSelection(_ sender: UIMenuItem) {
        let selections = pdfViewer.currentSelection?.selectionsByLine()
        guard let page = selections?.first?.pages.first else { return }

        let annotationsToRemove = page.annotations

        for annotation in annotationsToRemove {
            page.removeAnnotation(annotation)
            print("Removed: \(annotation)")
        }
    }

So, how do I remove just the selected highlight annotation?

By the way - I know that the whole menu-thing is not really relevant, but I hope that somebody will find this question when working with highlight annotations and then be able to use that part.

Thanks, Emil.

Footsore answered 29/10, 2019 at 22:53 Comment(0)
F
2

Okay, I actually figured it out after a while.

I decided the following approach which works for removing highlight annotation(s):

1: Get all annotations on the page.

2: Detect which annotations are part of the current selection by checking if the bounds.origin of the annotation is within the selection bounds.

3: Check if selected annotation(s) is/are of type "Highlight" and delete only these.

4: Remove the annotation(s).

5: Don't forget to save the changes at some point.

//Remove highlight annotations that are part of the current selection.
@objc func removeHighlightSelection(_ sender: UIMenuItem) {
    let selection = PDFSelection.init(document: pdfViewer.document!)
    selection.add(pdfViewer.currentSelection!)
    let selectionBounds = selection.bounds(for: pdfViewer.currentPage!)
    let annotations = pdfViewer.currentPage?.annotations
    let annotationsToDelete = NSMutableArray()

    for annotation in annotations! {
        let annotationPoint = annotation.bounds.origin
        if selectionBounds.contains(annotationPoint) {
            annotationsToDelete.add(annotation)
            print(annotationsToDelete)
        }
    }

    for annotation in annotationsToDelete {
        let onlyHighlight = annotation as! PDFAnnotation
        if onlyHighlight.type == "Highlight" {
            pdfViewer.currentPage?.removeAnnotation(onlyHighlight)
            print("Removed highlight annotation: \(onlyHighlight)")
        }
    }
}
Footsore answered 1/11, 2019 at 18:59 Comment(0)
P
5

observe this notification: PDFViewAnnotationHitNotification here: https://developer.apple.com/documentation/foundation/nsnotification/name/1504809-pdfviewannotationhit

add a target to the notification listener

when the annotation is pressed, return the dictionary value from the userInfo for PDFViewAnnotationHitNotification of "PDFAnnotationHit" and you'll have the exact annotation that was pressed, once you have this annotation, delete it.

Proximate answered 29/10, 2019 at 23:12 Comment(1)
Thanks for your help. I was able to use your answer for another problem I had, but in the end I solved this problem in another way. I've posted my solution as an answer.Hickerson
F
2

Okay, I actually figured it out after a while.

I decided the following approach which works for removing highlight annotation(s):

1: Get all annotations on the page.

2: Detect which annotations are part of the current selection by checking if the bounds.origin of the annotation is within the selection bounds.

3: Check if selected annotation(s) is/are of type "Highlight" and delete only these.

4: Remove the annotation(s).

5: Don't forget to save the changes at some point.

//Remove highlight annotations that are part of the current selection.
@objc func removeHighlightSelection(_ sender: UIMenuItem) {
    let selection = PDFSelection.init(document: pdfViewer.document!)
    selection.add(pdfViewer.currentSelection!)
    let selectionBounds = selection.bounds(for: pdfViewer.currentPage!)
    let annotations = pdfViewer.currentPage?.annotations
    let annotationsToDelete = NSMutableArray()

    for annotation in annotations! {
        let annotationPoint = annotation.bounds.origin
        if selectionBounds.contains(annotationPoint) {
            annotationsToDelete.add(annotation)
            print(annotationsToDelete)
        }
    }

    for annotation in annotationsToDelete {
        let onlyHighlight = annotation as! PDFAnnotation
        if onlyHighlight.type == "Highlight" {
            pdfViewer.currentPage?.removeAnnotation(onlyHighlight)
            print("Removed highlight annotation: \(onlyHighlight)")
        }
    }
}
Footsore answered 1/11, 2019 at 18:59 Comment(0)
P
1

if you are using UISearchBar to highlight the text just use these methods

1- to remove older annotations

  func removeAllAnnotations() {
    guard let document = self.baseView.document else { return }

    for i in 0..<document.pageCount {
        if let page = document.page(at: i) {
            let annotations = page.annotations
            for annotation in annotations {
                page.removeAnnotation(annotation)
            }
        }
    }
}

2- add new annotation

func highlight(searchTerms: [String]?)
{
   searchTerms?.forEach { term in
      let selections = baseView?.document?.findString(term, withOptions: [.caseInsensitive])
      selections?.forEach { selection in

        for page in selection.pages{
            let highlight = PDFAnnotation(bounds: selection.bounds(for: page), forType: .highlight, withProperties: nil)
           highlight.endLineStyle = .square
           highlight.color = UIColor.orange.withAlphaComponent(0.5)
           highlightsAnotation.append(highlight)
           page.addAnnotation(highlight)
        }
      }
   }
}

call these methods in UISearchBarDelegates like

 func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    removeAllAnnotations()
    highlight(searchTerms: [searchText])
}
Privative answered 25/2, 2020 at 12:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.