SwiftUI:如何调整大小以适合按钮以展开以填充VStack或HStack父视图?

cle*_*bit 1 user-interface ios swift swiftui

我正在尝试创建2个等宽的按钮,两个按钮垂直放置。它看起来应该像这样:

两个等宽按钮垂直放置,它们之间有间隔

我将2放置ButtonsVStack其中,它会自动扩展到较大按钮的宽度。我正在尝试做的是将按钮的宽度扩展为,以填充的宽度VStack,但这是我得到的:

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)
Run Code Online (Sandbox Code Playgroud)

设置宽度将其VStack展开,但是按钮无法展开以适合:

VStack(alignment: .center, spacing: 20) {
    ...
}.frame(width: 320)
    .background(Color.secondary)
Run Code Online (Sandbox Code Playgroud)

VStack宽度扩大,但按钮不扩大

所以我的问题是:

除了手动设置布局中每个项目的框架外,还有其他方法吗?

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

小智 9

您必须maxWidth: .infinityText按钮内部使用框架修饰符,这将迫使按钮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)
Run Code Online (Sandbox Code Playgroud)

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

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

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


cle*_*bit 5

设置.infinitymaxWidth,该frame(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)
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明


Moj*_*ini 5

iOS 17

从 iOS 17 开始,正确的方法是使用.containerRelativeFrame修饰符,因为在框架上使用.infinity宽度实际上会将父框架推向无限宽度。

所以它会是这样的:

Button { } label: {
    Text("Match Parent")
        .foregroundStyle(.white)
        .containerRelativeFrame(.horizontal) //  This should be inside the `label` parameter of the `button`. Otherwise it would be NOT touchable
        .padding(-10) //  This is here to make space to the edges. Yes it should have a NEGATIVE value
}
.frame(height: 56)
.background(.red)
Run Code Online (Sandbox Code Playgroud)
演示:

演示