「这是我参与2022首次更文挑战的第3天,活动详情查看:2022首次更文挑战」
给View指定大小
默认情况下,SwiftUI 的视图只占用它们需要的空间,但如果你想改变它,你可以使用 frame() 修饰符来告诉 SwiftUI 你想要什么样的大小范围。
例如:
Button {
print("Button tapped")
} label: {
Text("Welcome")
.frame(minWidth: 0, idealWidth: 100, maxWidth: 200, minHeight: 0, idealHeight: 100, maxHeight: 200, alignment: .center)
.font(.largeTitle)
}
使用padding给view 添加空间
SwiftUI 允许我们使用 padding() 修饰符在视图周围设置单独的填充,从而使视图居于合适的位置。
例如, 下面代码padding()不带任何参数:
VStack {
Text("TOP")
Text("MIDDLE")
.padding()
Text("BOTTOM")
}
效果如下:
可以设置.bottom是的只有填充MIDDLE的底部:
VStack {
Text("TOP")
Text("MIDDLE")
.padding(.bottom)
Text("BOTTOM")
}
当然也可以给数值意味着填充的长度。
使用GeometryReader相对布局
虽然通常最好让 SwiftUI 使用堆栈执行自动布局,但也可以使用 GeometryReader 为我们的视图提供相对于其容器的大小。 例如,如果希望两个View占据屏幕上可用宽度的一半,那么使用硬编码值是不可能的,因为我们事先不知道屏幕宽度是多少。
为了解决这个问题,GeometryReader 为我们提供了一个输入值,告诉我们可用的宽度和高度,然后我们可以将其用于我们需要的任何计算。 所以,如果我们有两个视图,我们希望一个占据屏幕的三分之一,另一个占据三分之二,我们可以这样写:
GeometryReader { geometry in
HStack(spacing: 0) {
Text("Left")
.font(.largeTitle)
.foregroundColor(.black)
.frame(width: geometry.size.width * 0.33)
.background(Color.yellow)
Text("Right")
.font(.largeTitle)
.foregroundColor(.black)
.frame(width: geometry.size.width * 0.67)
.background(Color.blue)
}
}
.frame(height: 50)
忽视 safeArea
默认情况下,SwiftUI 视图将大部分停留在safeArea内——它们将位于屏幕底部,但不会靠近设备顶部的任何凹槽。
如果你想改变它——如果你想让你的视图真正全屏显示,即使这意味着刘海部分遮挡——那么你应该使用 ignoresSafeArea() 修饰符。
返回不同类型的View
SwiftUI 的 body 属性都会自动获得返回不同视图的能力,这要归功于一个名为 @ViewBuilder 的特殊属性。 这是使用 Swift 的结果构建器系统实现的,它了解如何根据应用程序的状态呈现两种不同的视图。然而,这个相同的功能并非自动无处不在,这意味着您创建的任何自定义属性都必须返回相同的视图类型。
有四种方法可以解决此问题。 第一个中方法是将视图用Group包装起来,这样无论你的View是图像还是文本视图,它们都会返回到一个组中:
Group {
if Bool.random() {
Image("laser-show")
.resizable()
.scaledToFit()
} else{
Text("adsdad")
}
}
第二种是使用 AnyView ,我们可以返回它:
var tossResult: some View {
if Bool.random() {
return AnyView(Text("dasdasad").font(.largeTitle))
} else {
return AnyView(Text("adsdad"))
}
}
尽管 Group 和 AnyView 都为我们的布局实现了相同的结果,但在两者之间,通常更倾向于使用 Group,因为它对于 SwiftUI 更有效。
第三种选择是自己将 @ViewBuilder 属性应用于任何需要它的View,如下所示:
@ViewBuilder var tossResult: some View {
if Bool.random() {
Image("laser-show")
.resizable()
.scaledToFit()
} else {
Text("adsdad")
}
}
第四种解决方案,也是大多数情况下效果最好的解决方案,是将View分解为更小的View,然后根据需要将它们组合在一起