我们将通过构建基本的UI结构来启动我们的应用程序,这将会是两个标签告诉用户该做什么,然后是三个显示三个世界国家的国旗按钮。
首先,找到这个项目的资源并将它们拖到您的资源目录中。这意味着在Xcode中打开Assets.xcapets,然后从project2文件文件夹中拖入标记图像。你会注意到这些图片是以他们的国家命名的,还有@2x或@3x–这些是双分辨率和三分辨率的图片,可以处理不同类型的iPhone屏幕。
接下来,我们需要两个属性来存储我们的游戏数据:一个要在游戏中显示的所有国家图像的数组,再加上一个整数来存储哪个国家图像是正确的。
var countries = ["Estonia", "France", "Germany", "Ireland", "Italy", "Nigeria", "Poland", "Russia", "Spain", "UK", "US"]
var correctAnswer = Int.random(in: 0...2)
Int.random(in:)
方法会自动选择一个随机数,这在这里是完美的——我们将使用它来决定应该点击哪个国家的国旗。
在我们的身体里,我们需要把我们的游戏提示放在一个垂直的堆栈中,所以让我们从这个开始:
var body: some View {
VStack {
Text("Tap the flag of")
Text(countries[correctAnswer])
}
}
下面我们想有我们的可点击标志按钮,虽然我们可以把它们添加到同一个VStack
,我们实际上可以创建第二个VStack
,以便我们有更多的控制间距。
我们刚刚在上面创建的VStack
包含两个文本视图,并且没有间隔,但是如果国旗之间有30个间隔点,将会看起来更好。
所以,首先将这个ForEach
循环直接添加到我们刚刚创建的VStack
的末尾下面:
ForEach(0 ..< 3) { number in
Button(action: {
// flag was tapped
}) {
Image(self.countries[number])
.renderingMode(.original)
}
}
renderingMode(.original)
修饰语告诉SwiftUI渲染原始图像像素,而不是尝试将其重新着色为按钮。
现在我们遇到了一个问题:我们的body
属性试图发送回两个视图,一个VStack
和一个ForEach
,但这是不允许的。这是我们的第二个VStack
将进入:我希望你把原来的VStack
和下面的ForEach
包装成一个新的VStack
,这次间隔30点。
所以你的代码应该是这样的:
var body: some View {
VStack(spacing: 30) {
VStack {
Text("Tap the flag of")
// etc
}
ForEach(0 ..< 3) { number in
// etc
}
}
}
有两个这样的垂直堆栈可以让我们更精确地定位:外部堆栈将其视图间隔30个点,而内部堆栈没有间隔。
这足以让您对我们的用户界面有一个基本的了解,而且您已经看到它看起来不太好了——一些标志中有白色,它们与背景融为一体,所有标志都垂直居中在屏幕上。
稍后我们会回来对UI进行润色,但现在让我们使用一种蓝色的背景色,以便更容易看到标志。因为这意味着在我们的外部VStack
后面放置一些东西,所以我们也需要使用ZStack
。是的,我们会在一个ZStack
中的另一个VStack
中有一个VStack
,这是非常正常的。
首先在外部VStack
周围放置一个ZStack
,如下所示:
var body: some View {
ZStack {
// previous VStack code
}
}
现在把这个放在ZStack
里面,然后紧接着放VStack
:
Color.blue.edgesIgnoringSafeArea(.all)
edgesIgnoringSafeArea()
修饰符确保颜色直接进入屏幕边缘。
既然我们有了较深的背景色,我们应该给文本一些较亮的颜色,以便它更突出:
Text("Tap the flag of")
.foregroundColor(.white)
Text(countries[correctAnswer])
.foregroundColor(.white)
我们将要做的最后一个更改,至少现在是将外部VStack
中的所有内容向上推,这样UI就位于屏幕顶部。这与直接在ForEach
结束后添加间隔视图一样简单:
Spacer()