SwiftUI TextField捕获粘贴文本异常:PasteboardObserver未触发且内容为空
问题描述
我创建了PasteboardObserver类,用于捕获TextField的粘贴文本并修改isCodePasted布尔值,但该类内的所有打印语句均未触发,无法检测粘贴操作;不过在CUINDPasteValidationTextField视图中,onReceive(pasteboardObserver.$pastedCode)的打印语句能执行,但获取到的pastedCode始终为空。请问如何正确捕获粘贴文本并修改isCodePasted的状态?
相关代码
PasteboardObserver 类
import SwiftUI import UIKit import Combine class PasteboardObserver: ObservableObject { @Published var pastedCode: String = "" @Published var isCodePasted: Bool = false private var cancellable: AnyCancellable? init() { self.cancellable = NotificationCenter.default.publisher(for: UIPasteboard.changedNotification) .sink { _ in DispatchQueue.main.async { print("Pasteboard changed") if let string = UIPasteboard.general.string { print("Pasted string: \(string)") self.pastedCode = string self.isCodePasted = true } else { print("No string found in pasteboard") } } } } }
CUINDPasteValidationTextField 视图
struct CUINDPasteValidationTextField: View { var body: some View { VStack(alignment: .leading) { HStack { CUINDTextField(text: $text, focused: $focused, placeholder: placeholder, fontColor: style.fontColor ) .onReceive(pasteboardObserver.$pastedCode) { pastedCode in print("foo pasted") print(pastedCode) } } } } }
问题分析与解决方案
核心问题
UIPasteboard.changedNotification仅在剪贴板内容被主动修改时触发(比如用户复制新内容),而用户在TextField内执行粘贴操作时,系统只是将剪贴板内容插入输入框,并不会修改剪贴板本身,因此Observer内的通知监听完全失效。
另外pastedCode为空但onReceive触发,大概率是因为PasteboardObserver实例被重复创建或生命周期管理错误,导致初始化时默认空字符串触发了订阅,但实际未捕获到有效内容。
正确实现方案(推荐)
直接在自定义TextField的底层UITextField中重写粘贴方法,精准捕获输入框的粘贴操作:
1. 修改自定义TextField的UIViewRepresentable实现
假设你的CUINDTextField是基于UIViewRepresentable封装的UITextField,添加粘贴回调:
struct CUINDTextField: UIViewRepresentable { @Binding var text: String @Binding var focused: Bool let placeholder: String let fontColor: Color // 添加粘贴回调,用于传递粘贴内容 var onPaste: ((String) -> Void)? func makeUIView(context: Context) -> UITextField { let textField = UITextField() textField.placeholder = placeholder textField.textColor = UIColor(fontColor) textField.delegate = context.coordinator return textField } func updateUIView(_ uiView: UITextField, context: Context) { uiView.text = text uiView.isFirstResponder = focused } func makeCoordinator() -> Coordinator { Coordinator(self) } class Coordinator: NSObject, UITextFieldDelegate { let parent: CUINDTextField init(_ parent: CUINDTextField) { self.parent = parent } // 允许粘贴操作 override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { return action == #selector(paste(_:)) || super.canPerformAction(action, withSender: sender) } // 捕获粘贴动作并处理 override func paste(_ sender: Any?) { guard let pasteboardText = UIPasteboard.general.string else { super.paste(sender) return } // 将粘贴内容插入输入框 if let textField = parent.uiView { if let selectedRange = textField.selectedTextRange { textField.replace(selectedRange, withText: pasteboardText) parent.text = textField.text ?? "" } else { parent.text += pasteboardText } } // 通知父视图粘贴事件 parent.onPaste?(pasteboardText) super.paste(sender) } } }
2. 在视图中使用并更新状态
修正PasteboardObserver的生命周期管理,通过回调更新状态:
struct CUINDPasteValidationTextField: View { @State var text: String = "" @State var focused: Bool = false let placeholder: String let style: SomeStyle // 替换为你的实际样式类型 // 用@StateObject保证Observer实例生命周期稳定 @StateObject private var pasteboardObserver = PasteboardObserver() var body: some View { VStack(alignment: .leading) { HStack { CUINDTextField(text: $text, focused: $focused, placeholder: placeholder, fontColor: style.fontColor, onPaste: { pastedString in // 直接更新Observer状态 pasteboardObserver.pastedCode = pastedString pasteboardObserver.isCodePasted = true print("捕获到粘贴内容: \(pastedString)") }) .onReceive(pasteboardObserver.$pastedCode) { pastedCode in print("foo pasted") print(pastedCode) } } } } }
内容的提问来源于stack exchange,提问作者Mert Köksal
相关产品推荐
相关产品推荐

