选区变化时通过NSViewRepresentable传递NSTextView值至SwiftUI父视图
Great question! You don’t need to create a custom delegate or new notification—you can actually get the NSTextView instance directly from the notification object passed to textViewDidChangeSelection. Here’s how to modify your coordinator to access the text view and update your bindings:
Updated Coordinator Implementation
class Coordinator: NSObject, NSTextViewDelegate { var parent: TextViewMacOS init(_ parent: TextViewMacOS) { self.parent = parent } func textViewDidChangeSelection(_ notification: Notification) { // Retrieve the text view from the notification object guard let textView = notification.object as? NSTextView else { return } // Update typing attributes binding let newTypingAttributes = textView.typingAttributes // Optional: Check for changes to avoid redundant SwiftUI re-renders if parent.currentTypingAttributes != newTypingAttributes { DispatchQueue.main.async { self.parent.currentTypingAttributes = newTypingAttributes } } // Get attributes at the current selection position let selectedRange = textView.selectedRange() guard let textStorage = textView.textStorage else { // Fallback to typing attributes if textStorage is unavailable DispatchQueue.main.async { self.parent.currentTextAttributes = newTypingAttributes } return } // Handle edge case where selection is at the end of the text let attributePosition = min(selectedRange.lowerBound, textStorage.length - 1) var effectiveRange = NSRange() let newTextAttributes = textStorage.attributes(at: attributePosition, effectiveRange: &effectiveRange) // Optional: Check for changes before updating binding if parent.currentTextAttributes != newTextAttributes { DispatchQueue.main.async { self.parent.currentTextAttributes = newTextAttributes } } } }
Key Details Explained
- Retrieve the text view: The notification’s
objectproperty is theNSTextViewthat triggered the selection change, so we safely cast it to access its properties. - Main thread safety: We wrap binding updates in
DispatchQueue.main.asyncto ensure UI-related changes happen on the main thread (critical for SwiftUI state updates). - Edge case handling:
- If
textStorageis nil, we fall back to using the current typing attributes. - If the selection is at the very end of the text, we adjust the position to the last character to get valid attributes.
- If
- Redundant update prevention: Comparing the new attributes to the current binding value helps avoid unnecessary SwiftUI re-renders. Note that comparing dictionaries with
Anyvalues can be limited—if you need precise equality checks, consider comparing specific attributes (like.font,.foregroundColor) instead of the entire dictionary.
Don’t Forget to Set the Delegate
Make sure you assign the coordinator as the text view’s delegate in your makeNSView method:
public func makeNSView(context: Context) -> NSTextView { let textView = NSTextView() textView.delegate = context.coordinator // Add your other text view setup here (e.g., text storage, layout manager) return textView }
内容的提问来源于stack exchange,提问作者santi.gs
相关产品推荐
相关产品推荐

