SwiftUI:如何调整大小以适应一个按钮,使其扩展到填充VStack或HStack父视图?

24

我正在尝试创建两个等宽的按钮,一个在另一个上方垂直排列。它应该看起来像这样:

Two equal-width buttons positioned vertically with space between them

我在VStack中放置了2个按钮,它们自动扩展到较大按钮的宽度。我想要做的是让按钮的宽度扩展以填充VStack的宽度,但实际上得到的结果是:

VStack auto sizing to largest button

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)

VStack width expands but Buttons do not

所以我的问题是:
除了手动设置布局中每个项目的框架之外,是否有其他方法可以做到这一点?
我宁愿不必指定每一个项目,因为这将变得难以管理。
4个回答

26

.infinity设为maxWidth,使用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)

在这里输入图片描述


8
你需要在按钮内部的文本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中的诀窍是在您的按钮(或NavigationLink)上使用.buttonStyle()修饰符,并像以下方式创建自定义按钮样式:

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

您必须将框架修改器应用于

4

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)
演示:

demo


1
如果您想匹配 VStack 的动态宽度,即仅占用所需的空间(基于子视图的动态宽度),则可以通过向父 VStack 添加 .fixedSize(horizontal:,vertical:) 修饰符来实现。
示例:
var body: some View {
    VStack {
        Button("Log in") { }
            .foregroundColor(.white)
            .padding()
            .frame(maxWidth: .infinity)
            .background(.red)
            .clipShape(Capsule())
        
        Button("Reset Password") { }
            .foregroundColor(.white)
            .padding()
            .frame(maxWidth: .infinity)
            .background(.red)
            .clipShape(Capsule())
    }
    // Tells SwiftUI that the child views should only take up the space they need.
    .fixedSize(horizontal: true, vertical: false)
}

Match dynamic width in VStack


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接