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

SwiftUI自定义键盘适配Modifier导致Form出现白色空白问题求助

SwiftUI Form键盘弹出时出现空白区域问题

问题描述

在SwiftUI的Form视图中使用自定义View Modifier实现键盘弹出时上移视图,避免文本框被遮挡,此前功能正常,但现在键盘弹出时,键盘与文本框之间出现奇怪的白色空白区域。

问题演示

  • 使用Modifier后异常情况:
    键盘弹出后出现空白区域
  • 未使用Modifier时(键盘遮挡文本框):
    未使用Modifier时键盘遮挡文本框

相关代码

MainView

var body: some View {
    NavigationStack{
        ZStack{
            // 根据索引切换视图
            switch selectedIndex {
            case 0 : Text("HOME")
            case 1 : Logbook(dm: dm)
            case 2 : AddFlightView(dm: dm)
            default: Text("Default")
            }
            // 底部TabBar覆盖层
            VStack{
                Spacer()
                BottomBar(selectedIndex: $selectedIndex, items: $items)
                    .cornerRadius(15)
                    .padding(.horizontal)
                    .shadow(color: Color.darkTextColorMain.opacity(0.1), radius: 10,
                            x: 10,
                            y: 5)
            }
        }
        .navigationTitle(titleChange(selectedIndex: selectedIndex))
    }
}

AddFlightView

var body: some View {
    Form{
        Section("Flight") {
            Picker("选择 ", selection: $selected) {
                ForEach(DutyType.allCases,id: \.self) { type in
                    Text(stringPicker(dutyType:type))
                }
            }
            DatePicker(selection: $flightDate, displayedComponents: .date) {
                Text("选择日期")
            }.environment(\.timeZone, TimeZone(abbreviation: "UTC")!)
        }
        
        Section("Departure and Destination") {
            HStack{
                Text("出发机场")
                TextField(text: $departure_Apt) {
                    Text("出发机场")
                }.multilineTextAlignment(.trailing)
            }
            HStack{
                Text("到达机场")
                TextField(text: $arrival_Apt) {
                    Text("到达机场")
                }.multilineTextAlignment(.trailing)
            }
        }
        
        Section("时间选择"){
            DatePicker(selection: $chockoff, displayedComponents: .hourAndMinute) {
                Text("滑出时间 \(convertDateToString(date: chockoff))")
            }.environment(\.timeZone, TimeZone(abbreviation: "UTC")!)
            DatePicker(selection: $chockin, in: convertToUTCDate(dateToConvert: Date.now)... , displayedComponents: .hourAndMinute) {
                Text("UTC选择时间: \(convertDateToString(date: chockin))")
            }.environment(\.timeZone, TimeZone(abbreviation: "UTC")!)
            
            TextField("添加", text: $test)
//                        .textContentType(.oneTimeCode)
                .keyboardType(.numberPad)
            Spacer()
        }
    }
    .modifier(Keyboard())
}

Keyboard ViewModifier

struct Keyboard : ViewModifier {
    @State var offset: CGFloat = 0
    func body(content: Content) -> some View {
        content.padding(.bottom,offset).onAppear(perform: {
            NotificationCenter.default.addObserver(forName: UIResponder.keyboardDidShowNotification, object: nil, queue: .main) { notification in
                let val = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as! CGRect
                let height = val.height
                
                self.offset = height
            }
            
            NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillHideNotification, object: nil, queue: .main) { notification in
                self.offset = 0
            }
        })
    }
}

问题原因及解决方法

核心原因

自定义Modifier直接给Form添加了等于键盘高度的底部padding,但SwiftUI的Form本身已内置键盘适配逻辑(尤其是在NavigationStack中),两者叠加导致视图过度上移,出现空白区域。另外,keyboardDidShow获取的键盘高度包含设备底部安全区域高度(如带HomeIndicator的机型),而Form内置适配已处理该部分,重复添加会造成多余偏移。

解决方法

方法1:移除自定义Modifier,依赖SwiftUI内置适配

直接删掉.modifier(Keyboard()),同时给底部自定义TabBar添加忽略键盘安全区域的设置,确保Form内置适配能正确计算可用空间:

BottomBar(selectedIndex: $selectedIndex, items: $items)
    .cornerRadius(15)
    .padding(.horizontal)
    .shadow(color: Color.darkTextColorMain.opacity(0.1), radius: 10, x: 10, y: 5)
    .ignoresSafeArea(.keyboard) // 添加此行

同时建议移除AddFlightView中Time Selection Section里的Spacer(),避免Form内部出现多余空白。

方法2:修复自定义Modifier的偏移计算

如果必须保留自定义Modifier,需修正偏移量计算逻辑,减去安全区域高度:

struct Keyboard: ViewModifier {
    @State private var keyboardHeight: CGFloat = 0
    
    func body(content: Content) -> some View {
        content
            .padding(.bottom, keyboardHeight)
            .onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification)) { notification in
                guard let userInfo = notification.userInfo,
                      let frame = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else { return }
                let safeAreaBottom = UIApplication.shared.windows.first?.safeAreaInsets.bottom ?? 0
                keyboardHeight = frame.height - safeAreaBottom
            }
            .onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillHideNotification)) { _ in
                keyboardHeight = 0
            }
    }
}

内容的提问来源于stack exchange,提问作者Damiano Miazzi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 16:45:29