SwiftUI:如何在Sheet弹出时立即聚焦TextField?
解决SwiftUI Sheet与键盘同步弹出的问题
你的问题根源在于onAppear是在Sheet完全展示并完成动画后才触发,导致TextField获取焦点、弹出键盘的动作滞后于Sheet的显示。要实现两者同步,你可以通过同步状态变更与Sheet的动画事务来解决,具体有两种可行方案:
方案一:通过绑定状态与事务同步触发
将焦点状态从ContentView传递到SearchView,在触发Sheet展示的同时,用同一个动画事务同步设置焦点状态,让Sheet的弹出和键盘的唤起处于同一动画周期:
struct ContentView: View { @State var showSearch = false @State private var searchFocus = false var body: some View { Button { // 创建默认动画事务,确保状态变更同步 let transaction = Transaction(animation: .default) withTransaction(transaction) { showSearch = true searchFocus = true } } label: { Text("Search") } .sheet(isPresented: $showSearch) { SearchView(searchFocus: $searchFocus) } } } struct SearchView: View { @State var searchTerm = "" @Binding var searchFocus: Bool var body: some View { TextField("Search", text: $searchTerm) .focused($searchFocus) } }
方案二:利用Sheet的presentation回调(iOS 16+)
如果你的项目适配iOS 16及以上,可以使用sheet的onPresented回调,在Sheet开始展示时立即设置焦点,这个时机比onAppear更早:
struct ContentView: View { @State var showSearch = false var body: some View { Button { showSearch = true } label: { Text("Search") } .sheet(isPresented: $showSearch) { SearchView() } } } struct SearchView: View { @State var searchTerm = "" @FocusState private var searchFocus: Bool var body: some View { TextField("Search", text: $searchTerm) .focused($searchFocus) .presentationDetents([.medium, .large]) // 需指定detent才能触发onPresented .onPresented { searchFocus = true } } }
注意:方案二中必须为Sheet指定presentationDetents,否则onPresented回调不会在合适的时机触发。
这两种方法都能让键盘与Sheet同步弹出,消除滞后的卡顿感。
内容的提问来源于stack exchange,提问作者Ritchie
相关产品推荐
相关产品推荐

