SwiftUI 革新了开发者构建 iOS、macOS、watchOS 和 tvOS 用户界面的方式。
上一篇 SwiftUI 布局 介绍了 SwiftUI 中使用 VStack
和 HStack
及ZStack
进行布局。
今天我们介绍 SwiftUI 提供的强大组件之一是 ScrollView
,它让创建可滚动内容变得轻而易举。
在本全面教程中,我们将深入了解 ScrollView
,并指导您构建一个令人惊叹的轮播图界面。
通过本指南,您将拥有一个灵活且动态的 UI 组件,提升您 SwiftUI 应用的用户体验。
目录
- SwiftUI 入门
- 创建卡片式 UI
- 准备图像资源
- 实现 CardView
- 初步布局:使用 VStack
- 引入 ScrollView 进行垂直滚动
- 构建水平轮播图界面
- 优化 ScrollView 外观
- 分组视图内容以简化代码
- 自动调整文本大小
- 完善轮播图界面
- 总结
SwiftUI 入门
在深入了解 ScrollView
之前,确保您对 SwiftUI 的基础知识有一个扎实的理解。
如果您是 SwiftUI 新手或需要复习基础概念,
建议查看 SwiftUI 基础 以掌握基础知识。
在本教程中,我们将使用 ContentView.swift
并创建一个单独的 CardView.swift
来保持代码的清晰和组织性。
创建卡片式 UI
首先,我们创建一个卡片视图,作为轮播图界面的构建模块。卡片视图通常包含图像和描述性文本。
- 打开 Xcode,使用 App 模板在 iOS 下创建一个新项目。
- 命名您的项目为
SwiftUIScrollView
(或任何您喜欢的名称),并确保选择 SwiftUI 作为界面选项。 - 组织代码:不将所有内容都编码在
ContentView.swift
中,而是为卡片创建一个单独的 SwiftUI 视图。
创建 CardView.swift
- 在 项目导航器中,右键点击并选择 新建文件。
- 选择 SwiftUI View 并命名为
CardView
。 - 将文件保存到您的项目目录中。
首先,CardView.swift
初始内容如下:
import SwiftUI
struct CardView: View {
var body: some View {
Text("Card View")
}
}
struct CardView_Previews: PreviewProvider {
static var previews: some View {
CardView()
}
}
准备图像资源
在实现卡片视图之前,我们需要准备和导入必要的图像。
- 下载示例图像:如果您没有自己的图像,可以从 SwiftUIScrollViewImages.zip 下载示例图像。
- 导入图像:
- 解压下载的压缩包。
- 打开项目中的 Assets.xcassets。
- 将所有图像拖放到资产目录中。
实现 CardView
现在,让我们构建包含图像和文本描述的 CardView
。
步骤 1:添加图像
将占位文本替换为图像视图:
struct CardView: View {
var body: some View {
Image("swiftui-button")
.resizable()
.aspectRatio(contentMode: .fit)
}
}
步骤 2:添加文本描述
将文本视图封装在 VStack
中,以显示类别、标题和作者:
struct CardView: View {
var body: some View {
VStack {
Image("swiftui-button")
.resizable()
.aspectRatio(contentMode: .fit)
HStack {
VStack(alignment: .leading) {
Text("SwiftUI")
.font(.headline)
.foregroundColor(.secondary)
Text("Drawing a Border with Rounded Corners")
.font(.title)
.fontWeight(.black)
.foregroundColor(.primary)
.lineLimit(3)
Text("Written by Simon Ng".uppercased())
.font(.caption)
.foregroundColor(.secondary)
}
Spacer()
}
.padding()
}
.cornerRadius(10)
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(Color(.sRGB, red: 150/255, green: 150/255, blue: 150/255, opacity: 0.1), lineWidth: 1)
)
.padding([.top, .horizontal])
}
}
解释
- VStack:垂直排列图像和文本。
- HStack 与 Spacer:将文本对齐到左侧。
- 修饰符:
resizable()
、aspectRatio
、font
、foregroundColor
、lineLimit
、cornerRadius
、overlay
和padding
增强了 UI 的外观和响应性。
初步布局:使用 VStack
现在,我们在 ContentView.swift
中使用 VStack
来排列多个 CardView
。
初步尝试会发现所有卡片堆叠在一起,显得比较拥挤。
示例代码
struct ContentView: View {
var body: some View {
VStack {
CardView(
image: "swiftui-button",
category: "SwiftUI",
heading: "Drawing a Border with Rounded Corners",
author: "Ng"
)
CardView(
image: "macos-programming",
category: "macOS",
heading: "Building a Simple Editing App",
author: "Theodoropoulos"
)
CardView(
image: "flutter-app",
category: "Flutter",
heading: "Building a Complex Layout with Flutter",
author: "Tan"
)
CardView(
image: "natural-language-api",
category: "iOS",
heading: "What's New in Natural Language API",
author: "Kambampati"
)
}
}
}
结果
使用 VStack
布局多个卡片时,所有卡片会垂直堆叠在一起。如果卡片数量较多,所有内容会挤在一起,且卡片之间可能显得过于拥挤。
引入 ScrollView 进行垂直滚动
为了让用户能够滚动查看所有卡片,我们引入 ScrollView
并将 VStack
包裹在其中。
这样,用户可以在垂直方向上滚动浏览卡片。
修改 ContentView.swift
struct ContentView: View {
var body: some View {
ScrollView {
VStack {
CardView(
image: "swiftui-button",
category: "SwiftUI",
heading: "Drawing a Border with Rounded Corners",
author: "Ng"
)
CardView(
image: "macos-programming",
category: "macOS",
heading: "Building a Simple Editing App",
author: "Theodoropoulos"
)
CardView(
image: "flutter-app",
category: "Flutter",
heading: "Building a Complex Layout with Flutter",
author: "Tan"
)
CardView(
image: "natural-language-api",
category: "iOS",
heading: "What's New in Natural Language API",
author: "Kambampati"
)
}
}
}
}
结果
将 VStack
包裹在 ScrollView
中后,卡片变得可滚动,用户可以通过上下滑动来查看所有内容。
然而,这种垂直滚动方式在某些场景下可能不够直观,特别是当需要展示多张图片时。
构建水平轮播图界面
除了垂直滚动,我们还可以将 ScrollView
设置为水平滚动,以创建类似轮播图的界面。
这种布局方式特别适合展示多个卡片,用户可以通过左右滑动来浏览。
修改 ContentView.swift
为水平滚动
struct ContentView: View {
var body: some View {
ScrollView(.horizontal) {
HStack {
CardView(
image: "swiftui-button",
category: "SwiftUI",
heading: "Drawing a Border with Rounded Corners",
author: "Ng"
)
.frame(width: 300)
CardView(
image: "macos-programming",
category: "macOS",
heading: "Building a Simple Editing App",
author: "Theodoropoulos"
)
.frame(width: 300)
CardView(
image: "flutter-app",
category: "Flutter",
heading: "Building a Complex Layout with Flutter",
author: "Tan"
)
.frame(width: 300)
CardView(
image: "natural-language-api",
category: "iOS",
heading: "What's New in Natural Language API",
author: "Kambampati"
)
.frame(width: 300)
}
}
}
}
关键更改
- 水平
ScrollView
:通过传递.horizontal
指定ScrollView
为水平滚动。 HStack
:将堆栈视图从VStack
更改为HStack
,以并排排列卡片。- 固定宽度:为每个
CardView
设置宽度为 300 点,以保持一致性并防止卡片过于拥挤。
结果
您的轮播图现在应水平排列卡片,允许用户通过左右滑动来浏览。这种布局更加直观,特别适合展示多张图片或信息卡片。
优化 ScrollView 外观
默认情况下,ScrollView
显示一个滚动指示器,这可能不符合您的设计偏好。您可以隐藏它以获得更简洁的外观。
隐藏滚动指示器
ScrollView(.horizontal, showsIndicators: false) {
// HStack 包含 CardViews
}
通过将 showsIndicators
设置为 false
,滚动指示器将被隐藏,使界面更加简洁。
分组视图内容以简化代码
为了避免对每个 CardView
重复使用 .frame(width: 300)
修饰符,可以使用 Group
视图来集体应用修饰符。
重构带有 Group 的 HStack
HStack {
Group {
CardView(
image: "swiftui-button",
category: "SwiftUI",
heading: "Drawing a Border with Rounded Corners",
author: "Ng"
)
CardView(
image: "macos-programming",
category: "macOS",
heading: "Building a Simple Editing App",
author: "Theodoropoulos"
)
CardView(
image: "flutter-app",
category: "Flutter",
heading: "Building a Complex Layout with Flutter",
author: "Tan"
)
CardView(
image: "natural-language-api",
category: "iOS",
heading: "What's New in Natural Language API",
author: "Kambampati"
)
}
.frame(width: 300)
}
优点
- 简洁代码:通过分组相似视图,减少重复代码。
- 易于维护:对分组视图应用修饰符确保所有分组视图的一致性。
自动调整文本大小
有时,文本内容可能过长,导致截断。SwiftUI 提供了修饰符来优雅地处理这种情况。
实现 .minimumScaleFactor
在 CardView.swift
中,调整标题文本:
Text(heading)
.font(.title)
.fontWeight(.black)
.foregroundColor(.primary)
.lineLimit(3)
.minimumScaleFactor(0.5)
解释
.minimumScaleFactor(0.5)
:允许文本缩小至其原始大小的 50%,以适应可用空间,防止截断。
完善轮播图界面
整合所有组件,完善您的轮播图界面。
完整的 ContentView.swift
import SwiftUI
struct ContentView: View {
@State private var currentDate = Date()
private var formattedDate: String {
let formatter = DateFormatter()
formatter.dateFormat = "EEEE, MMM d"
return formatter.string(from: currentDate)
}
var body: some View {
VStack {
// 头部区域
HStack(spacing: 18) {
VStack(alignment: .leading) {
Text("\(formattedDate)")
.font(.headline)
.foregroundColor(.secondary)
Text("Your Reading")
.font(.largeTitle)
.fontWeight(.black)
}
Spacer()
}
.padding()
// 轮播图 ScrollView
ScrollView(.horizontal, showsIndicators: false) {
HStack {
Group {
CardView(
image: "swiftui-button",
category: "SwiftUI",
heading: "Drawing a Border with Rounded Corners",
author: "Ng"
)
CardView(
image: "macos-programming",
category: "macOS",
heading: "Building a Simple Editing App",
author: "Hal"
)
CardView(
image: "flutter-app",
category: "Flutter",
heading: "Building a Complex Layout in Flutter",
author: "Hal"
)
CardView(
image: "natural-language-api",
category: "iOS",
heading: "Adding Speech Recognition to Your App",
author: "Hal"
)
}
.frame(width: 300)
}
}
Spacer()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
完整的 CardView.swift
import SwiftUI
struct CardView: View {
var image: String
var category: String
var heading: String
var author: String
var body: some View {
VStack {
Image(image)
.resizable()
.aspectRatio(contentMode: .fit)
HStack {
VStack(alignment: .leading) {
Text(category)
.font(.headline)
.foregroundColor(.secondary)
Text(heading)
.font(.title)
.fontWeight(.black)
.foregroundColor(.primary)
.lineLimit(3)
.minimumScaleFactor(0.5)
Text("Written by: \(author)".uppercased())
.font(.caption)
.foregroundColor(.secondary)
}
Spacer()
}
.padding()
}
.cornerRadius(10)
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(Color(.sRGB, red:150/255, green: 150/255, blue: 150/255, opacity: 0.1), lineWidth: 1)
)
.padding([.top, .horizontal])
}
}
struct CardView_Previews: PreviewProvider {
static var previews: some View {
CardView(
image: "swiftui-button",
category: "SwiftUI",
heading: "Drawing a Border with Rounded Corners",
author: "Ng"
)
}
}
总结
恭喜您!您已经成功在 SwiftUI 中使用 ScrollView
实现了一个可滚动的轮播图界面。
通过以下步骤,您不仅学会了如何使用 VStack
和 HStack
进行布局,还掌握了如何通过垂直和水平滚动来优化用户体验:
- 初步布局:使用
VStack
排列多个卡片,发现卡片过于拥挤。 - 引入
ScrollView
:将VStack
包裹在ScrollView
中,实现垂直滚动。 - 构建水平滚动:将
ScrollView
设置为水平滚动,并使用HStack
排列卡片,创建轮播图效果。 - 优化外观:隐藏滚动指示器,使用
Group
简化代码,自动调整文本大小,确保界面整洁美观。
通过创建一个灵活的 CardView
并优化布局,您构建了一个动态组件,提升了应用的互动性。
记住,持续练习和尝试不同的 SwiftUI 组件,将进一步提升您的技能。