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

nxowjjhe  于 2023-03-28  发布在  Swift
关注(0)|答案(2)|浏览(110)

下面是示例项目源代码:sample code

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()
    }
}

当键盘出现时,操作菜单按钮(右下角)向上移动一点,点击菜单将导致奇怪的布局,如GIF所示。
我认为这是一个错误,有什么解决方案可以修复它吗?我用iOS 16和iOS 15测试了上面的代码。

[更新于2022.10.10 11:31 +8]
作为@Saket Kumar的解决方案,我更新了代码如下,即使我给予sizemenu,问题也会重现。
使用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)
        }
    }
}

km0tfn4u

km0tfn4u1#

似乎是SwiftUI的问题。我测试了你的代码,我能够重现这个问题。
我有预感,这种奇怪的行为可能是由TextField的框架和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()
    }

公平的警告。我放的那些框架可能不完全是你想要的。我已经测试了这个代码它工作。

[Just在演示项目中添加了您的代码以模拟它]
我的建议是给予Menu固定的宽度和高度,比如60*60,然后从屏幕宽度中去掉60,考虑到填充,给TextField合适的框架。

ca1c2owp

ca1c2owp2#

使用UIButtonUIMenu似乎可以毫不妥协地解决这个问题,尽管它并不理想。它可以通过**UIViewRepresentable**完成。

相关问题