Scroll textView along Text-to-Speech speaking highlight word change

27 Views Asked by At

I used Apple's Text-to-Speech to speak text in a UITextView. It is created with SwiftUI but 'UITextView' is used From UIKit because I need the word highlight feature which SwiftUI cannot offer.

The problem is if it is a long text which cross the limit of UITextView, when TTS speaking word is beyond the last line, UITextView doesn't scroll down automatically to show the highlight word. Please refer the the video in below.

I think I should provide speaking word range in updateUIView function, but not sure how to do it. BTW, voiceManager.attributedText is passed from AVSpeechSynthesizerDelegate functions for highlight speaking word.

func makeUIView(context: Context) -> UITextView {
    let textView = UITextView()
    textView.delegate = context.coordinator
    
    textView.font = UIFont(name: "Times New Roman", size: 18)
    textView.textContainerInset = .init(top: 10, left: 10, bottom: 10, right: 10)
    textView.isScrollEnabled = true
    textView.isEditable = true
    textView.isUserInteractionEnabled = true
    textView.backgroundColor = .lightGreen20
    
    return textView
}

func updateUIView(_ uiView: UITextView, context: Context) {
    if !voiceManager.isSpeaking {
        let attStr = NSMutableAttributedString(string: textViewModel.text)
        let pStyle = NSMutableParagraphStyle()
        pStyle.lineSpacing = 3
        attStr.addAttribute(.paragraphStyle, value: pStyle, range: NSMakeRange(0, attStr.length))
        attStr.addAttribute(.font, value: UIFont(name: "TimesNewRomanPS-BoldMT", size: 18)!, range: NSMakeRange(0, attStr.length))
        
        uiView.attributedText = attStr
    } else {
        let attStr = NSMutableAttributedString(attributedString: voiceManager.attributedText!)
        let pStyle = NSMutableParagraphStyle()
        pStyle.lineSpacing = 3
        attStr.addAttribute(.paragraphStyle, value: pStyle, range: NSMakeRange(0, attStr.length))
        attStr.addAttribute(.font, value: UIFont(name: "TimesNewRomanPS-BoldMT", size: 18)!, range: NSMakeRange(0, attStr.length))
        
        uiView.attributedText = attStr
    }
}

// MARK: Delegate functions to highlight text
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, willSpeakRangeOfSpeechString characterRange: NSRange, utterance: AVSpeechUtterance) {
    let mutableAttributedString = NSMutableAttributedString(string: utterance.speechString)
    mutableAttributedString.addAttribute(.backgroundColor, value: UIColor.yellow, range: characterRange)
    
    attributedText = mutableAttributedString
}

func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) {
    attributedText = NSAttributedString(string: utterance.speechString)
    HomeViewState.shared.isSpeaking = false
}

enter image description here

0

There are 0 best solutions below