You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 13:08:06