给定以下代码:

import SwiftUI

struct ContentView: View {
  var body: some View {
    VStack(alignment: .leading) {
      Text("Title")
        .font(.title)

      Text("Content")
        .lineLimit(nil)
        .font(.body)

      Spacer()
    }
    .background(Color.red)
  }
}

#if DEBUG
struct ContentView_Previews : PreviewProvider {
  static var previews: some View {
    ContentView()
  }
}
#endif

它的结果是这个接口:

我怎样才能使VStack填充屏幕的宽度,即使标签/文本组件不需要全宽度?


我发现的一个技巧是在结构中插入一个空的HStack,如下所示:

VStack(alignment: .leading) {
  HStack {
    Spacer()
  }
  Text("Title")
    .font(.title)

  Text("Content")
    .lineLimit(nil)
    .font(.body)

  Spacer()
}

产生所需的设计:

有没有更好的办法?


当前回答

有更好的办法!

为了让VStack填充它的父文件的宽度,你可以使用一个几何阅读器并设置框架。(.relativeWidth(1.0)应该工作,但显然不是现在)

struct ContentView : View {
    var body: some View {
        GeometryReader { geometry in
            VStack {
                Text("test")
            }
                .frame(width: geometry.size.width,
                       height: nil,
                       alignment: .topLeading)
        }
    }
}

为了让VStack成为实际屏幕的宽度,你可以在设置框架时使用uisscreen .main.bounds.width,而不是使用GeometryReader,但我猜你可能想要父视图的宽度。

此外,这种方式有一个额外的好处,就是不需要在VStack中添加空格,如果你添加了一个带有Spacer()的HStack,因为它是VStack的内容,这可能会发生(如果你有空格)。

更新-没有更好的方法了!

在检查了被接受的答案后,我意识到被接受的答案实际上是行不通的!乍一看,它似乎工作,但如果你更新VStack有一个绿色背景,你会注意到VStack仍然是相同的宽度。

struct ContentView : View {
    var body: some View {
        NavigationView {
            VStack(alignment: .leading) {
                Text("Hello World")
                    .font(.title)
                Text("Another")
                    .font(.body)
                Spacer()
                }
                .background(Color.green)
                .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .topLeading)
                .background(Color.red)
        }
    }
}

这是因为.frame(…)实际上是在向视图层次结构中添加另一个视图,而该视图最终会填满屏幕。然而,VStack仍然没有。

这个问题在我的回答中似乎也一样,可以使用与上面相同的方法进行检查(在.frame(…)之前和之后放置不同的背景颜色。看起来实际上扩大VStack的唯一方法是使用间隔器:

struct ContentView : View {
    var body: some View {
        VStack(alignment: .leading) {
            HStack{
                Text("Title")
                    .font(.title)
                Spacer()
            }
            Text("Content")
                .lineLimit(nil)
                .font(.body)
            Spacer()
        }
            .background(Color.green)
    }
}

其他回答

尝试使用下面选项的.frame修饰符:

.frame(
      minWidth: 0,
      maxWidth: .infinity,
      minHeight: 0,
      maxHeight: .infinity,
      alignment: .topLeading
    )
struct ContentView: View {
  var body: some View {
    VStack(alignment: .leading) {
      Text("Hello World")
        .font(.title)
      Text("Another")
        .font(.body)
      Spacer()
    }
    .frame(
      minWidth: 0,
      maxWidth: .infinity,
      minHeight: 0,
      maxHeight: .infinity,
      alignment: .topLeading
    )
    .background(Color.red)
  }
}

这被描述为一个灵活的框架(请参阅文档),它将拉伸以填充整个屏幕,当它有额外的空间时,它将在其中居中其内容。

这里有另一种方法可以节省你的项目时间:

与其他不可重用的答案相比,代码和可重用性要少得多!


extension View {
    
    var maxedOut: some View {
        
        return Color.clear
            .overlay(self, alignment: .center)

    }
    
    func maxedOut(color: Color = Color.clear, alignment: Alignment = Alignment.center) -> some View {
        
        return color
            .overlay(self, alignment: alignment)
        
    }
    
}

用例:

struct ContentView: View {

    var body: some View {

        Text("Hello, World!")
            .maxedOut
            .background(Color.blue)
        
        Text("Hello, World!")
            .maxedOut(color: Color.red)
  
    }
}

有更好的办法!

为了让VStack填充它的父文件的宽度,你可以使用一个几何阅读器并设置框架。(.relativeWidth(1.0)应该工作,但显然不是现在)

struct ContentView : View {
    var body: some View {
        GeometryReader { geometry in
            VStack {
                Text("test")
            }
                .frame(width: geometry.size.width,
                       height: nil,
                       alignment: .topLeading)
        }
    }
}

为了让VStack成为实际屏幕的宽度,你可以在设置框架时使用uisscreen .main.bounds.width,而不是使用GeometryReader,但我猜你可能想要父视图的宽度。

此外,这种方式有一个额外的好处,就是不需要在VStack中添加空格,如果你添加了一个带有Spacer()的HStack,因为它是VStack的内容,这可能会发生(如果你有空格)。

更新-没有更好的方法了!

在检查了被接受的答案后,我意识到被接受的答案实际上是行不通的!乍一看,它似乎工作,但如果你更新VStack有一个绿色背景,你会注意到VStack仍然是相同的宽度。

struct ContentView : View {
    var body: some View {
        NavigationView {
            VStack(alignment: .leading) {
                Text("Hello World")
                    .font(.title)
                Text("Another")
                    .font(.body)
                Spacer()
                }
                .background(Color.green)
                .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .topLeading)
                .background(Color.red)
        }
    }
}

这是因为.frame(…)实际上是在向视图层次结构中添加另一个视图,而该视图最终会填满屏幕。然而,VStack仍然没有。

这个问题在我的回答中似乎也一样,可以使用与上面相同的方法进行检查(在.frame(…)之前和之后放置不同的背景颜色。看起来实际上扩大VStack的唯一方法是使用间隔器:

struct ContentView : View {
    var body: some View {
        VStack(alignment: .leading) {
            HStack{
                Text("Title")
                    .font(.title)
                Spacer()
            }
            Text("Content")
                .lineLimit(nil)
                .font(.body)
            Spacer()
        }
            .background(Color.green)
    }
}

编辑:答案更新为使用.frame的简单(更好)方法

只要使用帧修饰器!

struct Expand: View {
    var body: some View {
        VStack(alignment: .leading) {
            Text("Title")
                .font(.title)
            
            Text("Content")
                .lineLimit(nil)
                .font(.body)
        }
        .frame(maxWidth:.infinity,maxHeight:.infinity,alignment:.topLeading)
        .background(Color.red)
    }
}

注意-你甚至不需要VStack中的spacer !

注意2:如果你不想在顶部和底部使用白色,那么在背景中使用:

Color.red.edgesIgnoringSafeArea(.all)

使用这个

.edgesIgnoringSafeArea(.all)