# #2 蒼鷺與少年電子書 - [medium 連結](https://medium.com/@tonysu1204/2-%E8%92%BC%E9%B7%BA%E8%88%87%E5%B0%91%E5%B9%B4%E9%9B%BB%E5%AD%90%E6%9B%B8-4f2a77c5fccd) - [app 操作影片](https://youtu.be/-_qZBGgseu4) - [github 連結](https://github.com/Ateto1204/Boy-and-Horen-iOS) - [app 分頁截圖](https://drive.google.com/drive/folders/1fWcJGortWpoOHatccTzrU7iLYMTTEOZE?usp=sharing) ## 重點程式碼講解 - 使用 TabView 製作下面有 tab bar 的分頁以及使用 SF Symbol ```swift= TabView { NavigationStack { CharList() } .tabItem { Label("Characters", systemImage: "person.fill") } ContentView() .tabItem { Label("Staffs", systemImage: "person.2.badge.gearshape.fill") } PlotView() .tabItem { Label("Plot", systemImage: "book") } } ``` - 使用 NavigationStack/Link 切換頁面、傳資料到下一頁,navigation bar 上顯示標題 ```swift= NavigationStack { NavigationLink { CharIntro(char: char) } label: { HStack { Image(char.image) .resizable() .scaledToFill() .frame(width: 100, height: 100) .clipShape(RoundedRectangle(cornerRadius: 20)) VStack (alignment: .leading) { Text(char.name) .font(.largeTitle) .foregroundColor(.white) Text("vol. " + char.vol) .foregroundColor(.white) } Spacer() } .toolbar(content: { ToolbarItem(placement: .principal) { Text("人物介紹") .bold() .foregroundColor(.white) } }) .background(IntroView().background) } } ``` - 打開連結的 Link 按鈕 ```swift= HStack { Text("電影分析參考連結:") .foregroundColor(.white) Link("蒼鷺與少年觀影心得", destination: URL(string: "https://www.dcard.tw/f/movie/p/253567740?cid=42388ED3-8E5E-49F7-98C3-97EFEDBB09D1")!) .underline() .foregroundColor(.blue) } .listRowBackground(IntroView().background) ``` - 支援 dark mode、light mode - 上下捲動的 List 裡有水平捲動的 ScrollView ```swift= ScrollView { ScrollView (.horizontal, showsIndicators: false) { Spacer() HStack { Spacer() ForEach(staffs.indices) { index in Button { number = index } label: { StaffRow(staff: staffs[index]) } } } } .listStyle(PlainListStyle()) .background(IntroView().background) } .listStyle(PlainListStyle()) .background(IntroView().background) ``` - 使用 VideoPlayer 播放影片 ```swift= if staffs[number].url != "null" { VideoPlayer(player: AVPlayer(url: Bundle.main.url(forResource: staffs[number].url, withExtension: "mp4")!)) .frame(width: 500, height: 300) .padding(EdgeInsets(top: 20, leading: 20, bottom: 20, trailing: 20)) } ``` - 設定 App Icon & 名稱 ## 加分功能 - 利用 mask 或 clipShape 將圖片裁切特別的形狀 ```swift= Image(staffs[number].image) .resizable() .scaledToFit() .frame(height: 300) .clipShape(RoundedRectangle(cornerRadius: 10)) ``` - 加入音樂或音效 ```swift= struct Music: View { @State public var looper: AVPlayerLooper? @State public var player = AVQueuePlayer() var body: some View { Text("") .onAppear { let url = Bundle.main.url(forResource: "地球儀", withExtension: "mp4")! let playerItem = AVPlayerItem(url: url) self.looper = AVPlayerLooper(player: player, templateItem: playerItem) player.play() } } } ``` ## 其他特色與彩蛋 - 支援直擺和橫擺兩種不同的擺放方式 - 支持 Light Mode & Dark Mode - backgroundColor 使用和原片片尾工作人員跑馬燈相同的底色 ## 心得 加簽這門課程對於剛上大一的我來說是一大挑戰,特別是要在接受程式競賽培訓的同時學習 SwiftUI,過去我主要專注於競程,最大的成就感來自於 AC,而像是 SwiftUI 這種前端的開發和我過去所做的事情差蠻多的,但在學習 SwiftUI 的過程中我發現,與其說是成就感,我更覺得它就像是一種多巴胺,每敲入一行方法,預覽的 UI 就會立即跳出結果,我只能說我的大腦好快樂啊! 而在這次的作業中我覺得最困難的點絕對不是程式碼的撰寫,而是資料素材的準備還有主題的發想以及內容的設計想法,但好在把想法實作出來的過程都還算順利。 <!-- {%hackmd /@Ateto/BJRpsqII9 %} -->