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

iOS 16中SwiftUI Menu异常行为的解决方案求助

iOS 16 SwiftUI Menu 键盘弹出错位问题的解决办法

问题场景

以下SwiftUI代码在iOS 15上运行正常,但在iOS 16设备中,当键盘弹出时,底部的Menu会出现帧异常、错位的问题,点击Menu后情况更严重。尝试过添加.fixedSize()等常见方案,均无效。

@State private var textInput = ""

var body: some View {
    VStack {
        TextEditor(text: $textInput)
            .padding()
            .border(.blue, width: 1)
        
        HStack {
            Button("Bottom button") { print("Button pressed") }
            .padding()
            .border(.green, width: 1)
            
            Spacer()
            
            Menu("Bottom Menu") {
                Button("Menu option 1") { print("Option 1 pressed") }
                Button("Menu option 2") { print("Option 2 pressed") }
            }
            .padding()
            .border(.red, width: 1)

        }
        .background(.gray)
    }
}

左侧为iOS 16异常表现,右侧为iOS 15正常表现:
iOS 16与iOS 15 Menu布局对比

可行解决办法

方案一:将底部操作栏移入Toolbar(推荐)

利用系统Toolbar的原生布局逻辑,让底部组件自动适配键盘弹出场景,从根源避免布局错乱:

@State private var textInput = ""

var body: some View {
    NavigationStack {
        TextEditor(text: $textInput)
            .padding()
            .border(.blue, width: 1)
            .toolbar {
                ToolbarItem(placement: .bottomBar) {
                    HStack {
                        Button("Bottom button") { print("Button pressed") }
                            .padding()
                            .border(.green, width: 1)
                        
                        Spacer()
                        
                        Menu("Bottom Menu") {
                            Button("Menu option 1") { print("Option 1 pressed") }
                            Button("Menu option 2") { print("Option 2 pressed") }
                        }
                        .padding()
                        .border(.red, width: 1)
                    }
                    .background(.gray)
                }
            }
    }
}

方案二:给Menu设置固定尺寸

通过固定Menu的宽高,强制布局系统保持其尺寸稳定,避免键盘弹出时的布局重计算错误:

@State private var textInput = ""

var body: some View {
    VStack {
        TextEditor(text: $textInput)
            .padding()
            .border(.blue, width: 1)
        
        HStack {
            Button("Bottom button") { print("Button pressed") }
            .padding()
            .border(.green, width: 1)
            
            Spacer()
            
            Menu("Bottom Menu") {
                Button("Menu option 1") { print("Option 1 pressed") }
                Button("Menu option 2") { print("Option 2 pressed") }
            }
            .padding()
            .border(.red, width: 1)
            .frame(width: 120, height: 44) // 根据实际需求调整尺寸
        }
        .background(.gray)
    }
}

方案三:动态记录Menu原始尺寸

通过GeometryReader在视图加载时记录Menu的原始尺寸,后续强制使用该尺寸,适配动态布局场景:

@State private var textInput = ""
@State private var menuSize: CGSize = .zero

var body: some View {
    VStack {
        TextEditor(text: $textInput)
            .padding()
            .border(.blue, width: 1)
        
        HStack {
            Button("Bottom button") { print("Button pressed") }
                .padding()
                .border(.green, width: 1)
            
            Spacer()
            
            Menu("Bottom Menu") {
                Button("Menu option 1") { print("Option 1 pressed") }
                Button("Menu option 2") { print("Option 2 pressed") }
            }
            .padding()
            .border(.red, width: 1)
            .background(
                GeometryReader { proxy in
                    Color.clear
                        .onAppear {
                            menuSize = proxy.size
                        }
                }
            )
            .frame(width: menuSize.width, height: menuSize.height)
        }
        .background(.gray)
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 21:46:07