这篇文章介绍了SwiftUI学习笔记中的第42个项目,宇航员应用程序。作者介绍了如何使用SwiftUI创建一个应用程序,该应用程序显示NASA的航天任务以及参与任务的宇航员。文章还提供了三个挑战,以帮助读者扩展应用程序。最后,作者分享了自己的代码和参考资料。
此内容根据文章生成,并经过人工审核,仅用于文章内容的解释与总结
投诉随着复杂性的增加,犯错的几率也随之增加,Swift在这里是相当不容忍的-就像你现在无疑会看到的那样,即使第20行出现一个小错误也可能导致第5行出现随机错误,这可能是令人沮丧。
好吧,希望今天的报价对你有所启发。我之所以今天特别选择它,是因为最好留给读者阅读,但就是这样:不要惊慌!这些类型的问题很常见,现在解决这些问题的最简单方法是注释掉你最近添加的任何代码,并继续这样做,直到你的代码起作用为止。然后,你可以缓慢地重新引入代码,直到找到导致编译中断的部分,然后对其进行修复。
挑战
最好的学习方法之一是尽可能频繁地编写自己的代码,因此,你应该尝试以下三种方式扩展此应用程序,以确保你完全了解正在发生的事情。
- 将启动日期添加到MissionView任务徽章下方的。
- 修改AstronautView以显示这位宇航员执行的所有任务。
- 在ContentView其中显示一个栏按钮,以在显示发射日期和显示机组人员名称之间切换。
第一个挑战应该是微不足道的,第二个挑战应该是棘手的,最后一个挑战……好吧,我们只能说它将推动你。如果花费的时间比你想象的要长得多,请不要感到惊讶!
我的代码
ContentView.swift
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| import SwiftUI
struct ContentView: View { let astronauts: [Astronaut] = Bundle.main.decode("astronauts.json") let mission: [Mission] = Bundle.main.decode("missions.json") @State private var showCrew = false var body: some View { NavigationView { List(mission) { item in NavigationLink(destination: MissionView(mission: item, astronauts: self.astronauts)) { Image(item.image) .resizable() .scaledToFill() .frame(width: 40, height: 40) VStack(alignment: .leading) { Text(item.displayName) .font(.headline) Text(self.showCrew ? self.membersList(mission: item) : item.formattedLaunchDate) } .padding(.leading) } } .navigationBarTitle("Moonshot") .navigationBarItems(trailing: Button(action: {self.showCrew.toggle()}) { Image(systemName: self.showCrew ? "person.fill" : "timer") }) } } func membersList(mission: Mission) -> String{ var members = "" for crew in mission.crew { members += "\(crew.name) " } return members } }
struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
|
MissionView.swift
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
| import SwiftUI
struct MissionView: View { let mission: Mission struct CrewMember { let role: String let astronaut: Astronaut } let astronauts: [CrewMember]
var body: some View { GeometryReader { geo in ScrollView(.vertical) { VStack { Image(self.mission.image) .resizable() .scaledToFit() .frame(maxWidth: geo.size.width * 0.7) .padding(.top) .padding(.bottom) Text(self.mission.formattedLaunchDate) Text(self.mission.description) .padding() Spacer(minLength: 25) ForEach(self.astronauts, id: \.role){ astMember in NavigationLink(destination: AstronautView(astronaut: astMember.astronaut)) { HStack { Image(astMember.astronaut.id) .resizable() .scaledToFit() .frame(width: 83, height: 60) .clipShape(RoundedRectangle(cornerRadius: 8)) .padding(.leading) VStack(alignment: .leading) { Text(astMember.astronaut.name) .font(.headline) .padding(.bottom, 6) Text(astMember.astronaut.id) .font(.footnote) .foregroundColor(.gray) } Spacer() } }.buttonStyle(PlainButtonStyle()) } } } .navigationBarTitle(Text(self.mission.displayName), displayMode: .inline) } } init(mission: Mission, astronauts: [Astronaut]) { self.mission = mission var matches = [CrewMember]() for member in mission.crew { if let match = astronauts.first(where: { $0.id == member.name}){ matches.append(CrewMember(role: member.role, astronaut: match)) } } self.astronauts = matches } }
struct MissionView_Previews: PreviewProvider { static let missions: [Mission] = Bundle.main.decode("missions.json") static let astronauts: [Astronaut] = Bundle.main.decode("astronauts.json") static var previews: some View { MissionView(mission: missions[0], astronauts: astronauts) } }
|
AstronautView.swift
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
| import SwiftUI
struct AstronautView: View { let astronaut: Astronaut let missions: [Mission] = Bundle.main.decode("missions.json") let missionList: [String] var body: some View { GeometryReader { geo in ScrollView(.vertical) { VStack { Image(self.astronaut.id) .resizable() .scaledToFill() .frame(height: geo.size.width) .frame(maxWidth: geo.size.width) HStack { Text(self.astronaut.name) .font(.largeTitle) .bold() .padding(.leading) Spacer() } .frame(maxWidth: geo.size.width) Text(self.astronaut.description) .padding() .frame(maxWidth: .infinity) Spacer(minLength: 20) HStack { Text("Space program") .font(.largeTitle) .bold() .padding(.leading) Spacer() } .frame(maxWidth: geo.size.width) .padding(.bottom) ForEach(self.missionList, id: \.self){ item in HStack { Text(item) .font(.title) .bold() .padding(.leading) Spacer() } .frame(maxWidth: geo.size.width) } } } } .navigationBarTitle(Text("\(astronaut.id)"), displayMode: .inline) } init(astronaut: Astronaut) { self.astronaut = astronaut var matches = [String]() for mission in self.missions { if mission.crew.first(where: { $0.name == astronaut.id}) != nil{ matches.append(mission.displayName) } } self.missionList = matches } }
struct AstronautView_Previews: PreviewProvider { static let astronauts: [Astronaut] = Bundle.main.decode("astronauts.json")
static var previews: some View { AstronautView(astronaut: astronauts[0]) } }
|
参考资料
查看下一天的SwiftUI学习笔记
关于100days英文课程