Skip to content

Instantly share code, notes, and snippets.

@samdods
Created October 9, 2019 09:57
Show Gist options
  • Save samdods/b7b13269f49c31a79e996425412e5676 to your computer and use it in GitHub Desktop.
Save samdods/b7b13269f49c31a79e996425412e5676 to your computer and use it in GitHub Desktop.
Snippet of the SelectableLabel.swift for a blog post on Speak Selection
final class SelectableLabel: UILabel {
// 1...
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupTextSelection()
}
private func setupTextSelection() {
layer.addSublayer(selectionOverlay)
let longPress = UILongPressGestureRecognizer(target: self, action: #selector(didLongPress))
addGestureRecognizer(longPress)
isUserInteractionEnabled = true
NotificationCenter.default.addObserver(self, selector: #selector(didHideMenu), name: UIMenuController.didHideMenuNotification, object: nil)
}
private let selectionOverlay: CALayer = {
let layer = CALayer()
layer.cornerRadius = 8
layer.backgroundColor = UIColor.black.withAlphaComponent(0.14).cgColor
layer.isHidden = true
return layer
}()
// 2...
@objc private func didHideMenu(_ notification: Notification) {
selectionOverlay.isHidden = true
}
// 3...
@objc private func didLongPress(_ gesture: UILongPressGestureRecognizer) {
guard let text = text, !text.isEmpty else { return }
becomeFirstResponder()
let menu = menuForSelection()
if !menu.isMenuVisible {
selectionOverlay.isHidden = false
menu.setTargetRect(textRect(), in: self)
menu.setMenuVisible(true, animated: true)
}
}
private func textRect() -> CGRect {
let inset: CGFloat = -4
return textRect(forBounds: bounds, limitedToNumberOfLines: numberOfLines).insetBy(dx: inset, dy: inset)
}
private func menuForSelection() -> UIMenuController {
let menu = UIMenuController.shared
menu.menuItems = [
UIMenuItem(title: "Copy", action: #selector(copyText)),
UIMenuItem(title: "Speak", action: #selector(speakText))
]
return menu
}
// 4...
@objc private func copyText(_ sender: Any?) {
cancelSelection()
let board = UIPasteboard.general
board.string = text
}
@objc private func speakText(_ sender: Any?) {
cancelSelection()
guard let text = text, !text.isEmpty else { return }
if #available(iOS 10.0, *) {
try? AVAudioSession.sharedInstance().setCategory(.playback, mode: .spokenAudio, options: .duckOthers)
}
// 5...
let speechSynthesizer = AVSpeechSynthesizer.forSpeakSelection
if speechSynthesizer.isSpeaking { speechSynthesizer.stopSpeaking(at: .word) }
let utterance = AVSpeechUtterance(string: text)
speechSynthesizer.speak(utterance)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment