Swift UI中如何自定义键盘与文本框之间的间距
Swift UI中如何自定义键盘与文本框之间的间距
嘿,我之前也碰到过这个问题!SwiftUI里确实没有像UIKit那样直接给个属性就能调键盘和输入框间距的方法,但咱们可以通过监听键盘高度,手动给ScrollView加额外空间来实现,亲测好用~
方法一:自定义视图修饰符,动态调整底部间距
这个方法是通过监听键盘的显示/隐藏通知,获取键盘高度,然后给ScrollView加上「键盘高度+额外间距」的底部padding,让输入框和键盘之间留出你想要的空间。
首先,我们需要一个监听键盘高度的ObservableObject:
import SwiftUI import Combine class KeyboardHeightObserver: ObservableObject { @Published var keyboardHeight: CGFloat = 0 private var cancellables = Set<AnyCancellable>() init() { // 监听键盘弹出通知 NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification) .compactMap { $0.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect } .map { $0.height } .assign(to: \.keyboardHeight, on: self) .store(in: &cancellables) // 监听键盘收起通知 NotificationCenter.default.publisher(for: UIResponder.keyboardWillHideNotification) .map { _ in CGFloat(0) } .assign(to: \.keyboardHeight, on: self) .store(in: &cancellables) } }
接着写一个自定义的ViewModifier,把这个监听逻辑封装进去:
struct KeyboardAdjustableScrollViewModifier: ViewModifier { @ObservedObject private var keyboardObserver = KeyboardHeightObserver() let extraSpacing: CGFloat // 你想要的额外间距 func body(content: Content) -> some View { content .padding(.bottom, keyboardObserver.keyboardHeight + extraSpacing) .animation(.easeOut(duration: 0.3), value: keyboardObserver.keyboardHeight) // 加上动画更顺滑 } } // 给View扩展一个便捷方法,方便调用 extension View { func keyboardAdjustable(extraSpacing: CGFloat = 20) -> some View { self.modifier(KeyboardAdjustableScrollViewModifier(extraSpacing: extraSpacing)) } }
最后在你的ScrollView上直接用这个修饰符就行:
ScrollView { VStack(spacing: 16) { ForEach(1...20, id: \.self) { index in TextField("输入框 \(index)", text: .constant("")) .textFieldStyle(RoundedBorderTextFieldStyle()) .padding(.horizontal) } } } .keyboardAdjustable(extraSpacing: 30) // 这里设置你需要的额外间距,比如30pt
方法二:结合ScrollViewReader精准控制滚动位置
如果你需要更精准地控制某个输入框的滚动位置,可以用ScrollViewReader,在点击输入框时主动滚动到目标位置,并留出额外间距。
示例代码:
struct ContentView: View { @State private var activeTextFieldId: Int? @State private var keyboardHeight: CGFloat = 0 let extraSpacing: CGFloat = 30 // 自定义额外间距 var body: some View { ScrollViewReader { proxy in ScrollView { VStack(spacing: 16) { ForEach(1...20, id: \.self) { index in TextField("输入框 \(index)", text: .constant("")) .textFieldStyle(RoundedBorderTextFieldStyle()) .padding(.horizontal) .id(index) // 给每个输入框设置唯一id .onTapGesture { activeTextFieldId = index } } } } // 监听输入框激活状态,滚动到对应位置 .onChange(of: activeTextFieldId) { id in guard let id = id else { return } withAnimation { // 锚点设为bottom,再结合键盘高度+额外间距调整 proxy.scrollTo(id, anchor: .bottom) } } // 监听键盘高度变化 .onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification)) { notification in guard let frame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else { return } keyboardHeight = frame.height } .onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillHideNotification)) { _ in keyboardHeight = 0 } // 同样加上底部padding来预留空间 .padding(.bottom, keyboardHeight + extraSpacing) } } }
小提示
SwiftUI默认的自动滚动是系统内部处理的,我们没法直接修改那个默认间距,所以通过监听键盘高度手动调整是最可靠的方式,原理和UIKit里调整UIScrollView的contentInset其实是一样的~
内容来源于stack exchange
相关产品推荐
相关产品推荐

