# #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 %} -->