SwiftUI:如何调整大小以适应 Button 以扩展以填充 VStack 或 HStack 父视图?

SwiftUI: how to size to fit a Button to expand to fill a VStack or HStack parent View?

我正在尝试创建 2 个等宽的按钮,一个垂直放置在另一个按钮上方。它应该是这样的:

我在 VStack 中放置了 2 Buttons,它会自动扩展到较大按钮的宽度。我想要做的是扩展按钮的宽度以填充 VStack 的宽度,但这是我得到的:

VStack(alignment: .center, spacing: 20) {

    NavigationLink(destination: CustomView()) {
        Text("Button")
    }.frame(height: 44)
        .background(Color.primary)

    Button(action: { self.isShowingAlert = true }) {
        Text("Another Button")
    }.frame(height: 44)
        .background(Color.primary)

}.background(Color.secondary)

设置 VStack 的宽度会扩展它,但按钮不会扩展以适合:

VStack(alignment: .center, spacing: 20) {
    ...
}.frame(width: 320)
    .background(Color.secondary)

所以我的问题是:

除了手动设置布局中每个项目的框架外,还有什么方法可以做到这一点吗?

我宁愿不必一一指定,因为这将变得难以管理。

设置.infinitymaxWidthframe(minWidth: maxWidth: minHeight:) API可用于使子视图展开以填充:

VStack(alignment: .center, spacing: 20) {

    NavigationLink(destination: CustomView()) {
        Text("Button")
    }.frame(minWidth: 100, maxWidth: .infinity, minHeight: 44)
        .background(Color.primary)

    Button(action: { self.isShowingAlert = true }) {
        Text("Another Button")
    }.frame(minWidth: 100, maxWidth: .infinity, minHeight: 44)
        .background(Color.primary)

}.frame(width: 340)
    .background(Color.secondary)

您必须在按钮内的 Text 本身上使用带有 maxWidth: .infinity 的框架修饰符,这将迫使 Button 变得尽可能宽:

VStack(alignment: .center, spacing: 20) {

    NavigationLink(destination: CustomView()) {
        Text("Button")
            .frame(maxWidth: .infinity, height: 44)
    }
    .background(Color.primary)

    Button(action: { self.isShowingAlert = true }) {
        Text("Another Button")
            .frame(maxWidth: .infinity, height: 44)
    }
    .background(Color.primary)

}.background(Color.secondary)

这在 iOS 中有效,但在使用默认按钮样式的 macOS 中无效,它使用 AppKit 的 NSButton,因为它拒绝变得更宽(或更高)。 macOS 中的技巧是在你的按钮上使用 .buttonStyle() 修饰符(或 NavigationLink)并制作你自己的自定义按钮样式,如下所示:

struct MyButtonStyle: ButtonStyle {
    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .background(configuration.isPressed ? Color.blue : Color.gray)
    }
}

您必须将框架修饰符应用于 Text 视图而不是按钮本身的原因是按钮更愿意坚持其内容的大小而不是包含的视图建议的大小按钮。这意味着如果您将框架修饰符应用于按钮而不是其中的 Text,按钮实际上将保持与 Text.frame 返回的视图相同的大小是将扩展以填充包含它的视图的宽度的按钮,因此您将无法 tap/click Text 视图边界之外的按钮。