SwiftUI封装macOS NSSearchField输入文字过长时滚动失效、光标卡滞问题
macOS 11 版本下SwiftUI未原生提供搜索组件,封装NSSearchField后出现文本超出输入框宽度时无法自动横向滚动、光标无法移动到可视范围外的问题,和原生TextField的对比如下:
问题原因
updateNSView方法更新逻辑不合理:每次绑定的text值变化时直接全量覆盖NSSearchField的stringValue,会强制重置输入框内部的光标位置、文本滚动偏移,打断原生的自动滚动逻辑- 初始化
NSSearchField时未显式开启文本横向滚动配置
修复后的完整实现代码
import SwiftUI struct SearchBar: NSViewRepresentable { private var placeholder: String @Binding var text: String init(_ placeholder: String, text: Binding<String>) { self.placeholder = placeholder _text = text } class Coordinator: NSObject, NSSearchFieldDelegate { @Binding var text: String init(text: Binding<String>) { _text = text } func controlTextDidChange(_ obj: Notification) { if let searchField = obj.object as? NSSearchField { text = searchField.stringValue } } } func makeCoordinator() -> SearchBar.Coordinator { return Coordinator(text: $text) } func makeNSView(context: NSViewRepresentableContext<SearchBar>) -> NSSearchField { let searchField = NSSearchField(frame: .zero) searchField.delegate = context.coordinator searchField.placeholderString = placeholder // 显式开启文本横向滚动、关闭自动换行 searchField.cell?.wraps = false searchField.cell?.isScrollable = true return searchField } func updateNSView(_ nsView: NSSearchField, context: NSViewRepresentableContext<SearchBar>) { // 仅当外部绑定值与输入框当前内容不一致时才更新,避免打断输入状态 guard nsView.stringValue != text else { return } nsView.stringValue = text } } struct SearchBar_Previews: PreviewProvider { @State private static var text = "" static var previews: some View { SearchBar("Search", text: $text) } }
改动说明
- 初始化
NSSearchField时添加cell属性配置,开启文本横向滚动能力、关闭自动换行 - 优化
updateNSView更新逻辑,仅在外部绑定值与输入框当前内容不同时才赋值,避免无意义的全量覆盖打断用户输入时的原生交互状态
内容的提问来源于stack exchange,提问作者Hamer
相关产品推荐
相关产品推荐

