Streaming is available in most browsers,
and in the Developer app.
-
Get started with Writing Tools
Learn how Writing Tools help users proofread, rewrite, and transform text in your app. Get the details on how Writing Tools interact with your app so users can refine what they have written in any text view. Understand how text is retrieved and processed, and how to support Writing Tools in custom text views.
Chapters
- 0:00 - Introduction
- 3:42 - Native text views
- 7:03 - Controlling behavior
- 8:23 - Protecting ranges
- 9:03 - Custom text views
- 11:44 - Next steps
Resources
Related Videos
WWDC23
WWDC22
WWDC21
WWDC19
-
DownloadArray
-
-
5:28 - Text view delegate methods for Writing Tools
func textViewWritingToolsWillBegin(_ textView: UITextView) { // Take necessary steps to prepare. For example, disable iCloud sync. } func textViewWritingToolsDidEnd(_ textView: UITextView) { // Take necessary steps to recover. For example, reenable iCloud sync. } if !textView.isWritingToolsActive { // Do work that needs to be avoided when Writing Tools is interacting with text view // For example, in the textViewDidChange callback, app may want to avoid certain things when Writing Tools is active }
-
7:11 - Opt-out of the full experience
textView.writingToolsBehavior = .limited textView.writingToolsBehavior = .none
-
7:31 - Specify accepted text formats
textView.writingToolsAllowedInputOptions = [.plainText] textView.writingToolsAllowedInputOptions = [.plainText, .richText, .table]
-
7:55 - WKWebView
// For `WKWebView`, the `default` behavior is equivalent to `.limited` extension WKWebViewConfiguration { @available(iOS 18.0, *) open var writingToolsBehavior: UIWritingToolsBehavior { get set } } extension WKWebViewConfiguration { @available(macOS 15.0, *) open var writingToolsBehavior: NSWritingToolsBehavior { get set } } extension WKWebView { /// @discussion If the Writing Tools behavior on the configuration is `.limited`, this will always be `false`. @available(iOS 18.0, macOS 15.0, *) open var isWritingToolsActive: Bool { get } }
-
8:48 - Protecting ranges
// Returned `NSRange`s are relative to the substring of the textView’s textStorage from `enclosingRange` func textView(_ textView: UITextView, writingToolsIgnoredRangesIn enclosingRange: NSRange) -> [NSRange] { let text = textView.textStorage.attributedSubstring(from: enclosingRange) return rangesInappropriateForWritingTools(in: text) }
-
9:58 - Indicate your text view supports editing
protocol UITextInput { @available(iOS 18.0, macOS 15.0, *) optional var isEditable: Bool { get } }
-
10:58 - Simple view that supports Copy
class CustomTextView: NSView, NSServicesMenuRequestor { required init?(coder: NSCoder) { super.init(coder: coder) self.menu = NSMenu() self.menu?.addItem(NSMenuItem(title: "Custom Text View", action: nil, keyEquivalent: "")) self.menu?.addItem(NSMenuItem(title: "Copy", action: #selector(copy(_:)), keyEquivalent: "")) } override func draw(_ dirtyRect: NSRect) { super.draw(dirtyRect) // Custom text drawing code... } }
-
11:05 - View extension to support Writing Tools
class CustomTextView: NSView, NSServicesMenuRequestor { override func validRequestor(forSendType sendType: NSPasteboard.PasteboardType?, returnType: NSPasteboard.PasteboardType?) -> Any? { if sendType == .string || sendType == .rtf { return self } return super.validRequestor(forSendType: sendType, returnType: returnType) } nonisolated func writeSelection(to pboard: NSPasteboard, types: [NSPasteboard.PasteboardType]) -> Bool { // Write plain text and/or rich text to pasteboard return true } // Implement readSelection(from pboard: NSPasteboard) as well for editable view }
-
-
Looking for something specific? Enter a topic above and jump straight to the good stuff.
An error occurred when submitting your query. Please check your Internet connection and try again.