SwiftUI 在 `.safeAreaInset` 中添加 `menu` 导致奇怪的布局问题

ZYi*_*iOS 6 ios swift swiftui safearea ios16

这是示例项目源代码:示例代码

import SwiftUI

struct TestMenuInSafeAreaInset: View {
    @State private var message = ""

    var body: some View {
        VStack {
            Rectangle()
                .fill(Color.blue)
        }
            .safeAreaInset(edge: .bottom) {
                HStack {
                    TextField("Input your message", text: $message)
                        .padding()
                        .background(Color.brown)
                        .cornerRadius(12)
                        .foregroundColor(.white)
                    Menu {
                        Button {

                        } label: {
                            Text("Confirm")
                        }

                        Button {

                        } label: {
                            Text("Cancel")
                        }

                    } label: {
                        Image(systemName: "square.and.arrow.up.fill")
                            .tint(.white)
                            .padding()
                            .background(Color.brown)
                            .cornerRadius(50)
                    }
                }
                .padding()
            }
    }
}

struct TestMenuInSafeAreaInset_Previews: PreviewProvider {
    static var previews: some View {
        TestMenuInSafeAreaInset()
    }
}

Run Code Online (Sandbox Code Playgroud)

当键盘出现时,操作菜单按钮(右下角)会向上移动一点,点击菜单会导致奇怪的布局,如图 gif 所示。

我认为这是一个错误,有什么解决方案可以解决吗?我使用 iOS 16 和 iOS 15 测试了上述代码,具有相同的行为。

正常状态,没问题

当键盘第一次显示时,右侧操作菜单按钮稍微向上推。

[更新于2022年10月10日11:31+8]

作为 @Saket Kumar 的解决方案,我更新了代码如下,即使我将size其提供给menu.

使用 iPhone 14 Pro 模拟器 iOS 16 进行测试。

struct TestMenuInSafeAreaInset: View {
    @State private var message = ""

    var body: some View {
        VStack {
            TextField("Input your user name", text: $message)
                .padding()
                .background(Color.gray.opacity(0.3))
                .cornerRadius(12)
                .padding()
            Spacer()
        }
        .safeAreaInset(edge: .bottom) {
            HStack {
                Spacer()
                    .frame(height: 70)
                Menu {
                    Button {

                    } label: {
                        Text("Confirm")
                    }

                    Button {

                    } label: {
                        Text("Cancel")
                    }
                } label: {
                    Image(systemName: "square.and.arrow.up.fill")
                        .padding()
                        .tint(.white)
                        .background(Color.brown)
                        .cornerRadius(50)
                }
                .frame(width: 50, height: 50)
            }
            .padding(.horizontal, 20)
            .background(Color.blue)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

第一次出现键盘时,菜单图标会向上移动。

sak*_*mar 0

似乎是 SwiftUI 的问题。我测试了您的代码,并且能够重现该问题。

我预感这种奇怪的行为可能是由 TextField 的 Frame 和 Menu 的框架重叠引起的,而 SwiftUI 正试图适应这一点。

所以我尝试手动给他们框架,它似乎解决了问题。

只需更改这部分代码即可。

    .safeAreaInset(edge: .bottom) {
        HStack {
            TextField("Input your message", text: $message)
                .padding()
                .background(Color.brown)
                .cornerRadius(12)
                .foregroundColor(.white)
                .frame(width: UIScreen.main.bounds.width*0.75, height: 50, alignment: .leading)
            Spacer()
            Menu {
                Button {

                } label: {
                    Text("Confirm")
                }

                Button {

                } label: {
                    Text("Cancel")
                }

            } label: {
                Image(systemName: "square.and.arrow.up.fill")
                    .tint(.white)
                    .padding()
                    .background(Color.brown)
                    .cornerRadius(50)
            }.frame(width: UIScreen.main.bounds.width*0.10, height: 50, alignment: .trailing)
        }
        .padding()
    }
Run Code Online (Sandbox Code Playgroud)

公平警告。我放置的那些框架可能不完全符合您的要求。我已经测试过这段代码它有效。

在此输入图像描述

[刚刚在演示项目中添加了您的代码来模拟它]

我的建议是为菜单提供固定的宽度和高度,例如 60*60。然后从屏幕宽度中取出60,作为填充。并为 TextField 提供合适的框架。