探索如何通过创建一个掷虚拟骰子的应用程序来使用 @State
属性和按钮更新应用程序的用户界面。添加功能以增加或减少屏幕上骰子的数量,以便玩不同类型的游戏。
用状态更新用户界面
步骤 1
在 Xcode 中创建一个名为 DiceRoller 的 iOS 应用项目。
步骤 2
创建一个名为 DiceView 的 SwiftUI 视图文件。
步骤 3
将主体代码替换为骰子的图像。
步骤 4
向视图添加一个属性,以表示骰子上的点数。
struct DiceView: View {
var numberOfPips: Int = 1
var body: some View {
Image(systemName: "die.face.1")
步骤 5
该属性被标记为关键字 var
,这意味着您可以为其分配新值。此视图是动态的;当人们掷骰子时,您将更改该属性的值。
步骤 6
使用字符串插值来显示骰子图像,使用您新属性的值。
步骤 7
使用修饰符来增加图像的大小。.resizable
修饰符告诉图像它可以拉伸以填充任何可用空间。您不希望骰子填充所有可用空间,因此通过设置其框架大小来限制图像。
var body: some View {
Image(systemName: "die.face.\(numberOfPips)")
.resizable()
.frame(width: 100, height: 100)
}
}
//
// DiceView.swift
// DiceRoller
//
//
//
import SwiftUI
struct DiceView: View {
var body: some View {
Image(systemName: "die.face.1")
}
}
#Preview {
DiceView()
}
步骤 1
将图像嵌入到一个 VStack
中,以便您可以在其下方添加按钮。
var body: some View {
VStack {
Image(systemName: "die.face.\(numberOfPips)")
.resizable()
步骤 2
在VStack
内部,在Image
及其修饰符下,开始输入Button
。代码补全会为您提供几个建议;选择带有title
和action
的选项。
步骤 3
将第一个占位符替换为字符串 "Roll"
。
.resizable()
.frame(width: 100, height: 100)
Button("Roll", action: () -> Void)
}
}
步骤 4
第二个参数,action: () -> Void
,需要一个闭包,当人们点击按钮时执行代码。按 Tab 选择占位符,然后按 Return。
步骤 5
将最后一个占位符替换为代码,以选择骰子的随机点数。
您的代码中有一个错误,您将在下一部分通过将 number
更改为 @State
属性来修复它。
步骤 1
将number
设置为@State
属性。然后点击“Roll”按钮几次,检查图像是否变化。
步骤 2
为按钮添加边框,以使其与图像区分开。
步骤 3
要使旧骰子图像过渡到新图像时淡出,请使用with
来动画化变化。
//
// DiceView.swift
// DiceRoller
//
//
//
import SwiftUI
struct DiceView: View {
private var numberOfPips: Int = 1
var body: some View {
VStack {
Image(systemName: "die.face.\(numberOfPips)")
.resizable()
.frame(width: 100, height: 100)
Button("Roll") {
numberOfPips = Int.random(in: 1...6)
}
.buttonStyle(.bordered)
}
}
}
#Preview {
DiceView()
}
创建一个动态骰子显示
通过创建另一个属性来添加选择骰子数量的功能。用@State
标记该属性可以确保在骰子数量变化时界面更新。
步骤 1
在Content
中,用一个标题替换VStack
的内容。
var body: some View {
VStack {
Text("Dice Roller")
.font(.largeTitle.lowercaseSmallCaps())
}
.padding()
步骤 2
添加一个HStack
,其中包含三个Dice
实例。尝试掷每个骰子。
Text("Dice Roller")
.font(.largeTitle.lowercaseSmallCaps())
HStack {
DiceView()
DiceView()
DiceView()
}
}
.padding()
步骤 3
要能够显示任意数量的骰子,请使用 For
视图。通过使用从 1 到 3 的范围重复 Dice
三次。手动输入代码;For
为许多不同的用途提供代码补全选项。
步骤 4
1...3
范围是静态的。为了使其适应任意数量的骰子,您将再次使用视图状态。添加一个状态属性以表示骰子的数量。
struct ContentView: View {
private var numberOfDice: Int = 1
var body: some View {
VStack {
步骤 5
使用新属性使范围动态。
步骤 6
在For
视图和HStack
下方,添加两个按钮以增加和减少骰子的数量。
}
}
HStack {
Button("Remove Dice") {
numberOfDice -= 1
}
Button("Add Dice") {
numberOfDice += 1
}
}
.padding()
}
.padding()
步骤 7
将骰子的数量减少到一个,然后点击移除骰子按钮。预览崩溃,因为范围 1...0
是无效的。
步骤 8
为了防止人们在只有一个 Dice
时点击“移除骰子”按钮,您可以 禁用 该按钮以防止崩溃,并给人们一个按钮无响应的视觉提示。当 number
的值为 1 时,使用 .disabled
修饰符来禁用“移除骰子”按钮。
步骤 9
骰子的图像固定为 100x100 点,因此屏幕上只能显示三个骰子图像。使用 .disabled
修饰符与添加骰子按钮一起,防止人们拥有超过三个骰子。
步骤 10
使用with
动画化骰子数量的变化。
//
// ContentView.swift
// DiceRoller
//
//
//
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
Text("Dice Roller")
.font(.largeTitle.lowercaseSmallCaps())
}
.padding()
}
}
#Preview {
ContentView()
}
调整界面以支持更多骰子
使用灵活的宽度和高度,使骰子图像能够根据屏幕上的骰子数量动态调整大小。
步骤 1
将骰子限制增加到五个,然后点击添加骰子,直到有五个骰子。
步骤 2
将Content
预览固定,然后切换到Dice
。使用灵活的框架以允许骰子图像缩小,并点击添加骰子,直到再次有五个骰子。
Image(systemName: "die.face.\(numberOfPips)")
.resizable()
.frame(maxWidth: 100, maxHeight: 100)
Button("Roll") {
步骤 3
现在骰子图像具有灵活的宽度和高度,HStack
可以将它们缩小以适应屏幕。但是当有四个或五个骰子时,由于HStack
上下没有任何限制其高度的内容,它们会在垂直方向上被拉伸。为防止这种情况,将骰子图像的纵横比设置为 1,然后点击添加骰子,直到再次有五个骰子。
.resizable()
.frame(maxWidth: 100, maxHeight: 100)
.aspectRatio(1, contentMode: .fit)
Button("Roll") {
//
// ContentView.swift
// DiceRoller
//
//
//
import SwiftUI
struct ContentView: View {
private var numberOfDice: Int = 1
var body: some View {
VStack {
Text("Dice Roller")
.font(.largeTitle.lowercaseSmallCaps())
HStack {
ForEach(1...numberOfDice, id: \.description) { _ in
DiceView()
}
}
HStack {
Button("Remove Dice") {
withAnimation {
numberOfDice -= 1
}
}
.disabled(numberOfDice == 1)
Button("Add Dice") {
withAnimation {
numberOfDice += 1
}
}
.disabled(numberOfDice == 5)
}
.padding()
}
.padding()
}
}
#Preview {
ContentView()
}
在按钮标签中使用图像
自定义添加和移除骰子按钮以显示图像而不是文本。
步骤 1
在Content
中,为添加骰子按钮添加另一个参数以添加图像。
.disabled(numberOfDice == 1)
Button("Add Dice", systemImage: "plus.circle.fill") {
withAnimation {
numberOfDice += 1
步骤 2
对于这个按钮,一张图片足以告诉人们它的功能。但按钮应该始终有一个文本标签——无论是否可见——以便那些依赖于 VoiceOver 等功能的人可以使用。使用 .label
修饰符隐藏按钮文本。
步骤 3
使用标题字体增大按钮大小。
步骤 4
在“移除骰子”按钮上添加一张图片。
HStack {
Button("Remove Dice", systemImage: "minus.circle.fill") {
withAnimation {
numberOfDice -= 1
//
// ContentView.swift
// DiceRoller
//
//
//
import SwiftUI
struct ContentView: View {
private var numberOfDice: Int = 1
var body: some View {
VStack {
Text("Dice Roller")
.font(.largeTitle.lowercaseSmallCaps())
HStack {
ForEach(1...numberOfDice, id: \.description) { _ in
DiceView()
}
}
HStack {
Button("Remove Dice") {
withAnimation {
numberOfDice -= 1
}
}
.disabled(numberOfDice == 1)
Button("Add Dice", systemImage: "plus.circle.fill") {
withAnimation {
numberOfDice += 1
}
}
.disabled(numberOfDice == 5)
}
.padding()
}
.padding()
}
}
#Preview {
ContentView()
}