Reputation: 33
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.
Upvotes: 0
Views: 2690
Reputation: 852
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])
}
Upvotes: 1
Reputation: 33
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)")
}
}
}
Upvotes: 2
Reputation: 4646
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.
Upvotes: 5