「这是我参与2022首次更文挑战的第5天,活动详情查看:2022首次更文挑战」
使用 Size Class 创建不同的布局
SwiftUI 通过使用Size Class 来创建不同的布局。 要使用它们,首先创建一个将存储其值的 @Environment 对象,然后在需要时检查该属性的值,查找 .compact 或 .regular 大小类。
struct ContentView: View {
@Environment(.horizontalSizeClass) var horizontalSizeClass
var body: some View {
if horizontalSizeClass == .compact {
Text("Compact")
} else {
Text("Regular")
}
}
}
Size Class是通过使用 VStack 或 HStack 为您的内容使您的用户界面智能地适应可用空间的好方法。 例如,如果您有很多空间,您可能会水平放置东西,但当空间有限时切换到垂直布局。
使用Size Class来自动的切换Vstack 和 HStack
SwiftUI 可以监控当前的大小类来决定应该如何布局,例如从空间充足时的 HStack 切换到空间受限时的 VStack。
可以编写一个新的 AdaptiveStack 视图,它会自动为我们在水平和垂直布局之间切换。 这使得在 iPad 上创建出色的布局变得更加简单,
struct AdaptiveStack<Content: View>: View {
@Environment(\.horizontalSizeClass) var sizeClass
let horizontalAlignment: HorizontalAlignment
let verticalAlignment: VerticalAlignment
let spacing: CGFloat?
let content: () -> Content
init(horizontalAlignment: HorizontalAlignment = .center, verticalAlignment: VerticalAlignment = .center, spacing: CGFloat? = nil, @ViewBuilder content: @escaping () -> Content) {
self.horizontalAlignment = horizontalAlignment
self.verticalAlignment = verticalAlignment
self.spacing = spacing
self.content = content
}
var body: some View {
Group {
if sizeClass == .compact {
VStack(alignment: horizontalAlignment, spacing: spacing, content: content)
} else {
HStack(alignment: verticalAlignment, spacing: spacing, content: content)
}
}
}
}
struct ContentView: View {
var body: some View {
AdaptiveStack {
Text("Horizontal when there's lots of space")
Text("but")
Text("Vertical when space is restricted")
}
}
}
-
首先,在自定义View 监听 HorizontalSizeClass,以便每次大小类更改时都会更新它。
-
并且为提供了单独存储水平和垂直对齐的参数,因此您可以准确控制布局应如何适应。
-
有一个可选的 CGFloat 值用于间距,因为这就是 VStack 和 HStack 的工作方式。 如果你想要更多的控制,你可以添加 HorizontalSpacing 和 verticalSpacing 属性。
-
content 属性是一个不接受参数并返回某种内容的函数,最终将依赖该内容来创建他们的布局。
-
我们的初始化程序将它们全部隐藏起来以备后用。
-
在 body 属性中,可以读取水平尺寸类,然后在 VStack 或 HStack 中包装对 content() 的调用。
ScrollView 使用
SwiftUI 的 ScrollView 允许开发者相对轻松地创建视图的滚动容器,因为它会自动调整自身大小以适应我们放置在其中的内容,并且还会自动添加额外的插图以避开安全区域。
ScrollView {
VStack(spacing: 20) {
ForEach(0..<10) {
Text("Item ($0)")
.foregroundColor(.white)
.font(.largeTitle)
.frame(width: 200, height: 200)
.background(Color.red)
}
}
}
.frame(height: 350)
默认情况下,滚动视图是垂直的,但可以通过传入 .horizontal 作为第一个参数来控制轴。 因此,我们可以将之前的示例翻转为水平的,如下所示:
ScrollView(.horizontal) {
HStack(spacing: 20) {
ForEach(0..<10) {
Text("Item ($0)")
.foregroundColor(.white)
.font(.largeTitle)
.frame(width: 200, height: 200)
.background(Color.red)
}
}
}
可以使用 [.horizontal, .vertical] 同时指定两个轴。
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 20) {
ForEach(0..<10) {
Text("Item ($0)")
.foregroundColor(.white)
.font(.largeTitle)
.frame(width: 200, height: 200)
.background(Color.red)
}
}
}
将ScrollView滑动到指定位置
如果想以编程方式让 SwiftUI 的 ScrollView 移动到特定位置,你应该在其中嵌入一个 ScrollViewReader。 这提供了一个 scrollTo() 方法,该方法可以移动到父滚动视图内的任何视图,只需提供其锚点。
例如,这会在垂直滚动视图中创建 100 个彩色框,当您按下按钮时,它将直接滚动到 ID 为 8 的框:
struct ContentView: View {
let colors: [Color] = [.red, .green, .blue]
var body: some View {
ScrollView {
ScrollViewReader { value in
Button("Jump to #8") {
value.scrollTo(8)
}
.padding()
ForEach(0..<100) { i in
Text("Example (i)")
.font(.title)
.frame(width: 200, height: 200)
.background(colors[i % colors.count])
.id(i)
}
}
}
.frame(height: 350)
}
}
为了更好地控制滚动,您可以指定第二个参数称为锚点,以控制滚动完成后目标视图的位置。
例如,这将滚动到与以前相同的视图,但这次将该视图放在顶部:
struct ContentView: View {
let colors: [Color] = [.red, .green, .blue]
var body: some View {
ScrollView {
ScrollViewReader { value in
Button("Jump to #8") {
value.scrollTo(8, anchor: .top)
}
.padding()
ForEach(0..<100) { i in
Text("Example (i)")
.font(.title)
.frame(width: 200, height: 200)
.background(colors[i % colors.count])
.id(i)
}
}
}
.frame(height: 350)
}
}