Swift+PDFKit实现iOS PDF单词点击发音的代码修改求助
Hey there! Let's get that word-click-to-speak feature up and running for your iOS PDF reader. You're already halfway there with the PDF display and speech synthesis—we just need to bridge the gap between tapping a word and triggering the audio. Here's how to modify your ViewController.swift:
Step-by-Step Explanation & Modified Code
First, we'll add a tap gesture recognizer to catch user taps on the PDFView. Then we'll convert the tap's screen coordinates to PDF page coordinates, grab the tapped word, and pass it to your speech synthesizer.
import UIKit import PDFKit import AVFoundation class ViewController: UIViewController { @IBOutlet weak var pdfView: PDFView! // Make the speech synthesizer a class property to avoid recreating it on every tap private let speechSynth = AVSpeechSynthesizer() override func viewDidLoad() { super.viewDidLoad() // Load your PDF document as before if let url = Bundle.main.url(forResource: "pdf", withExtension: "pdf"), let pdfDocument = PDFDocument(url: url) { pdfView.autoScales = true pdfView.document = pdfDocument // Tell the PDFView we want to select text by whole words pdfView.selectionMode = .byWord } // Add a tap gesture recognizer to handle word taps let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handlePDFTap(_:))) pdfView.addGestureRecognizer(tapGesture) } @objc private func handlePDFTap(_ gesture: UITapGestureRecognizer) { // Get the tap location on the screen let tapPoint = gesture.location(in: pdfView) // Convert the screen point to a point within the PDF page guard let tappedPage = pdfView.page(for: tapPoint, nearest: true), let pageBounds = tappedPage.bounds(for: pdfView.displayBox) else { return // Exit if we can't find the tapped page } let pdfCoordinatePoint = pdfView.convert(tapPoint, to: tappedPage, for: pageBounds) // Grab the word at the tapped coordinate // The `within` parameter creates a small "hit box" to account for slight tap inaccuracies guard let wordSelection = tappedPage.selection(for: pdfCoordinatePoint, at: .word, within: CGSize(width: 10, height: 10)) else { return // Exit if no word was found at the tap location } // Extract the text of the selected word guard let wordToSpeak = wordSelection.string else { return } // Trigger speech synthesis for the word let utterance = AVSpeechUtterance(string: wordToSpeak) utterance.voice = AVSpeechSynthesisVoice(language: "en-US") speechSynth.speak(utterance) } }
Key Details to Note
- Speech Synthesizer as Class Property: We moved
speechSynthto a class-level variable so we don't create a new synthesizer instance every time the user taps a word—this is more efficient. - PDF Selection Mode: Setting
pdfView.selectionMode = .byWordensures the PDFView prioritizes selecting entire words when tapped. - Coordinate Conversion: Screen coordinates don't directly map to PDF page coordinates, so we use
convert(_:to:for:)to translate the tap position correctly. - Hit Box Adjustment: The
within: CGSize(width: 10, height: 10)parameter lets users tap slightly off-center of a word and still have it recognized. You can adjust this size if needed (bigger = more forgiving taps).
Important Caveat
This works only with text-based PDFs—scanned PDFs (which are just images) won't have selectable text, so you won't be able to extract words from them.
内容的提问来源于stack exchange,提问作者user8460166

