# IOS ## 各種連結 + [我的程式碼](https://github.com/Popcorn0924-0924/IOS-3-MARVEL/tree/main/00857202_3) + [ch10](https://drive.google.com/file/d/1Eclomt3FfBF887oUcvTB2D0GVHajJbD8/view) + [ch9](https://trello.com/c/WTTQiSbU/29-%E4%BD%BF%E7%94%A8-swiftui-%E5%89%B5%E4%BD%9C-crud-%E7%B4%80%E9%8C%84app) + [binding](https://drive.google.com/file/d/1wDVGyRbEefaFfzeJ1fykXkuihBV13aYN/view) + [random](https://medium.com/%E6%B5%B7%E5%A4%A7-ios-app-%E7%A8%8B%E5%BC%8F%E8%A8%AD%E8%A8%88/bonus-%E4%BA%82%E6%95%B8%E7%B7%B4%E7%BF%92%E4%B9%8B%E5%88%B0%E5%BA%95%E8%A6%81%E5%B9%B9%E5%98%9B-29063ff8b5b4) + [動畫](https://medium.com/%E5%BD%BC%E5%BE%97%E6%BD%98%E7%9A%84-swift-ios-app-%E9%96%8B%E7%99%BC%E5%95%8F%E9%A1%8C%E8%A7%A3%E7%AD%94%E9%9B%86/swiftui-%E7%9A%84-animation-%E5%8B%95%E7%95%AB-2f8eb72d2756) + [SwiftUI 選時間的歲月神偷 — DatePicker](https://medium.com/%E5%BD%BC%E5%BE%97%E6%BD%98%E7%9A%84-swift-ios-app-%E9%96%8B%E7%99%BC%E5%95%8F%E9%A1%8C%E8%A7%A3%E7%AD%94%E9%9B%86/swiftui-%E9%81%B8%E6%99%82%E9%96%93%E7%9A%84%E6%AD%B2%E6%9C%88%E7%A5%9E%E5%81%B7-datepicker-22491c08bc93) + [SwiftUI 選擇項目的 Picker & 我要選李白](https://medium.com/%E5%BD%BC%E5%BE%97%E6%BD%98%E7%9A%84-swift-ios-app-%E9%96%8B%E7%99%BC%E5%95%8F%E9%A1%8C%E8%A7%A3%E7%AD%94%E9%9B%86/swiftui-%E9%81%B8%E6%93%87%E9%A0%85%E7%9B%AE%E7%9A%84-picker-%E6%88%91%E8%A6%81%E9%81%B8%E6%9D%8E%E7%99%BD-aabd95adc601) + [SwiftUI 設計 UI 元件樣式的各種方法 ](https://medium.com/%E5%BD%BC%E5%BE%97%E6%BD%98%E7%9A%84-swift-ios-app-%E9%96%8B%E7%99%BC%E5%95%8F%E9%A1%8C%E8%A7%A3%E7%AD%94%E9%9B%86/swiftui-%E8%A8%AD%E8%A8%88-ui-%E5%85%83%E4%BB%B6%E6%A8%A3%E5%BC%8F%E7%9A%84%E5%90%84%E7%A8%AE%E6%96%B9%E6%B3%95-5350da28bc89) + [SwiftUI 擅長展開 & 折疊的 DisclosureGroup](https://medium.com/%E5%BD%BC%E5%BE%97%E6%BD%98%E7%9A%84-swift-ios-app-%E9%96%8B%E7%99%BC%E5%95%8F%E9%A1%8C%E8%A7%A3%E7%AD%94%E9%9B%86/swiftui-%E6%93%85%E9%95%B7%E5%B1%95%E9%96%8B-%E6%8A%98%E7%96%8A%E7%9A%84-disclosuregroup-8a41010fb4d9) + [利用 SwiftUI 繪製同時填滿顏色和線條的形狀](https://medium.com/%E5%BD%BC%E5%BE%97%E6%BD%98%E7%9A%84-swift-ios-app-%E9%96%8B%E7%99%BC%E5%95%8F%E9%A1%8C%E8%A7%A3%E7%AD%94%E9%9B%86/%E5%88%A9%E7%94%A8-swiftui-%E7%B9%AA%E8%A3%BD%E5%90%8C%E6%99%82%E5%A1%AB%E6%BB%BF%E9%A1%8F%E8%89%B2%E5%92%8C%E7%B7%9A%E6%A2%9D%E7%9A%84%E5%BD%A2%E7%8B%80-86f0faee556d) + [SwiftUI 調整元件位置的幾種方法](https://medium.com/%E5%BD%BC%E5%BE%97%E6%BD%98%E7%9A%84-swift-ios-app-%E9%96%8B%E7%99%BC%E5%95%8F%E9%A1%8C%E8%A7%A3%E7%AD%94%E9%9B%86/swiftui-%E8%AA%BF%E6%95%B4%E5%85%83%E4%BB%B6%E4%BD%8D%E7%BD%AE%E7%9A%84%E5%B9%BE%E7%A8%AE%E6%96%B9%E6%B3%95-f925e884cfd1) + [利用 NavigationView & NavigationLink 切換頁面](https://medium.com/%E5%BD%BC%E5%BE%97%E6%BD%98%E7%9A%84-swift-ios-app-%E9%96%8B%E7%99%BC%E5%95%8F%E9%A1%8C%E8%A7%A3%E7%AD%94%E9%9B%86/%E5%88%A9%E7%94%A8-navigationview-navigationlink-%E5%88%87%E6%8F%9B%E9%A0%81%E9%9D%A2-3a062833230f) + [利用 SwiftUI 的 PageTabViewStyle 實現分頁照片瀏覽](https://medium.com/%E5%BD%BC%E5%BE%97%E6%BD%98%E7%9A%84-swift-ios-app-%E9%96%8B%E7%99%BC%E5%95%8F%E9%A1%8C%E8%A7%A3%E7%AD%94%E9%9B%86/%E5%88%A9%E7%94%A8-swiftui-%E7%9A%84-pagetabviewstyle-%E5%AF%A6%E7%8F%BE%E5%88%86%E9%A0%81%E7%85%A7%E7%89%87%E7%80%8F%E8%A6%BD-cf307285ef20) + [格子狀排列的 LazyVGrid & LazyHGrid](https://medium.com/%E5%BD%BC%E5%BE%97%E6%BD%98%E7%9A%84-swift-ios-app-%E9%96%8B%E7%99%BC%E5%95%8F%E9%A1%8C%E8%A7%A3%E7%AD%94%E9%9B%86/%E6%A0%BC%E5%AD%90%E7%8B%80%E6%8E%92%E5%88%97%E7%9A%84-lazyvgrid-lazyhgrid-338a21a7afc3) + [link](https://medium.com/%E5%BD%BC%E5%BE%97%E6%BD%98%E7%9A%84-swift-ios-app-%E9%96%8B%E7%99%BC%E5%95%8F%E9%A1%8C%E8%A7%A3%E7%AD%94%E9%9B%86/swiftui-%E9%BB%9E%E9%81%B8%E6%89%93%E9%96%8B%E9%80%A3%E7%B5%90%E7%9A%84-link-%E6%8C%89%E9%88%95-2b0c382f5468) + [讓 SwiftUI List 的 row 有多個可點選的 NavigationLink](https://medium.com/%E5%BD%BC%E5%BE%97%E6%BD%98%E7%9A%84-swift-ios-app-%E9%96%8B%E7%99%BC%E5%95%8F%E9%A1%8C%E8%A7%A3%E7%AD%94%E9%9B%86/%E8%AE%93-swiftui-list-%E7%9A%84-row-%E6%9C%89%E5%A4%9A%E5%80%8B-navigationlink-64e9b8ca6751) + [SwiftUI 讓 scaledToFill 圖片等於螢幕寬度的方法](https://medium.com/%E5%BD%BC%E5%BE%97%E6%BD%98%E7%9A%84-swift-ios-app-%E9%96%8B%E7%99%BC%E5%95%8F%E9%A1%8C%E8%A7%A3%E7%AD%94%E9%9B%86/swiftui-%E8%AE%93%E5%9C%96%E7%89%87%E7%AD%89%E6%96%BC%E8%9E%A2%E5%B9%95%E5%AF%AC%E5%BA%A6-%E8%A8%AD%E5%AE%9A%E6%AF%94%E4%BE%8B%E7%9A%84%E6%96%B9%E6%B3%95-9e4ef427585e) + [SwiftUI 維持元件理想尺寸的 fixedSize (修正文字切掉問題)](https://medium.com/%E5%BD%BC%E5%BE%97%E6%BD%98%E7%9A%84-swift-ios-app-%E9%96%8B%E7%99%BC%E5%95%8F%E9%A1%8C%E8%A7%A3%E7%AD%94%E9%9B%86/swiftui-%E7%B6%AD%E6%8C%81%E5%85%83%E4%BB%B6%E7%90%86%E6%83%B3%E5%B0%BA%E5%AF%B8%E7%9A%84-fixedsize-bce6d2442f92) + [利用 Stack,Rectangle & overlay 實現元件一樣大,固定比例 & 照片牆](https://medium.com/%E5%BD%BC%E5%BE%97%E6%BD%98%E7%9A%84-swift-ios-app-%E9%96%8B%E7%99%BC%E5%95%8F%E9%A1%8C%E8%A7%A3%E7%AD%94%E9%9B%86/%E5%88%A9%E7%94%A8-stack-rectangle-overlay-%E5%AF%A6%E7%8F%BE%E5%85%83%E4%BB%B6%E4%B8%80%E6%A8%A3%E5%A4%A7-%E5%9B%BA%E5%AE%9A%E6%AF%94%E4%BE%8B-%E7%85%A7%E7%89%87%E7%89%86-dfe0923983aa) + [SwiftUI 裁切形狀的 clipShape & mask](https://medium.com/%E5%BD%BC%E5%BE%97%E6%BD%98%E7%9A%84-swift-ios-app-%E9%96%8B%E7%99%BC%E5%95%8F%E9%A1%8C%E8%A7%A3%E7%AD%94%E9%9B%86/swiftui-%E8%A3%81%E5%88%87%E5%BD%A2%E7%8B%80%E7%9A%84-clipshape-mask-4fc49b34141) + [調整元件階層的 SwiftUI zIndex ](https://medium.com/%E5%BD%BC%E5%BE%97%E6%BD%98%E7%9A%84-swift-ios-app-%E9%96%8B%E7%99%BC%E5%95%8F%E9%A1%8C%E8%A7%A3%E7%AD%94%E9%9B%86/%E8%AA%BF%E6%95%B4%E5%85%83%E4%BB%B6%E9%9A%8E%E5%B1%A4%E7%9A%84-swiftui-zindex-72c0c6fc5b1a) + [用狀態設計 SwiftUI 畫面 — 認識 @State property,binding & Toggle](https://medium.com/%E5%BD%BC%E5%BE%97%E6%BD%98%E7%9A%84-swift-ios-app-%E9%96%8B%E7%99%BC%E5%95%8F%E9%A1%8C%E8%A7%A3%E7%AD%94%E9%9B%86/%E7%94%A8%E7%8B%80%E6%85%8B%E8%A8%AD%E8%A8%88-swiftui-%E7%95%AB%E9%9D%A2-%E8%AA%8D%E8%AD%98-state-property-binding-27fea6885ead) + [fullScreenCover()](https://www.hackingwithswift.com/quick-start/swiftui/how-to-present-a-full-screen-modal-view-using-fullscreencover) + [SwiftUI List Row 的 button 點選](https://medium.com/%E5%BD%BC%E5%BE%97%E6%BD%98%E7%9A%84-swift-ios-app-%E9%96%8B%E7%99%BC%E5%95%8F%E9%A1%8C%E8%A7%A3%E7%AD%94%E9%9B%86/swiftui-list-row-%E7%9A%84-button-%E9%BB%9E%E9%81%B8-af13892c95ca) + [plist 設定 iOS App 的 Launch screen](https://medium.com/%E5%BD%BC%E5%BE%97%E6%BD%98%E7%9A%84-swift-ios-app-%E9%96%8B%E7%99%BC%E5%95%8F%E9%A1%8C%E8%A7%A3%E7%AD%94%E9%9B%86/%E4%BD%BF%E7%94%A8-plist-%E8%A8%AD%E5%AE%9A-ios-app-%E7%9A%84-launch-screen-a1781a6217f) ## 程式 > [color=#ed6f21]程式碼解釋 :::spoiler 1. 建個列表 ``` @ObservedObject var timeData = MyTimeData()//綁定MyTimeData(),若MyTimeData()改變列表跟著變 @State private var showEditMyTime = false//修改的按鈕 ``` 2.timeData.myTimes為MyTimeData中第13 行 Published var myTimes = [MyTime]()//綁struct ``` ForEach(timeData.myTimes) { (mytime) in NavigationLink(destination: MyTimeEditor(myTimesData: self.timeData, editMyTime: mytime)) { MyTimeRow(myTime: mytime)//型態 ``` 3.點右上+可眺新增畫面(sheet) ``` .navigationBarItems(leading: EditButton() , trailing: Button(action: { self.showEditMyTime = true }) { Image(systemName: "plus.circle.fill") }) .sheet(isPresented: $showEditMyTime) { NavigationView { MyTimeEditor(myTimesData: self.timeData) } ``` 4.MyTimeEditor ![](https://i.imgur.com/n8A7PFb.png) + @Environment(\.presentationMode) var presentationMode & self.presentationMode.wrappedValue.dismiss()可返回 ``` @Environment(\.presentationMode) var presentationMode var myTimesData: MyTimeData @State private var name = "" @State private var course = "" @State private var type = "" @State private var date = Date() @State private var time = 0 @State private var isDone = false var editMyTime: MyTime? ``` 5.MyTimeEditor ![](https://i.imgur.com/QGFTrlM.png) ![](https://i.imgur.com/JB1Lcwv.png) ``` .navigationBarItems(trailing: Button("Save") { let myTime = MyTime(name: self.name, course: self.course, type: self.type, date: self.dateFormatter.string(from: self.date), time: self.time, isDone: self.isDone) if let editMyTime = self.editMyTime { let index = self.myTimesData.myTimes.firstIndex { $0.id == editMyTime.id }! self.myTimesData.myTimes[index] = myTime } else { self.myTimesData.myTimes.insert(myTime, at: 0) } self.presentationMode.wrappedValue.dismiss() }) ``` ::: > [color=#ed6f21]重要(在第七章Data binding) :::spoiler https://drive.google.com/file/d/1wDVGyRbEefaFfzeJ1fykXkuihBV13aYN/view + date [10years程式碼](https://github.com/hannn0919/2020_iOS_bonus2/blob/master/2020_iOS_bonus2/selfView.swift) [10years程式碼](https://github.com/00757001/00757001-10years/blob/main/00757001-10years/ContentView.swift) ``` struct TenYearImage: View { let width: CGFloat let selectDate: Date let brightnessAmount: Double var year: Int { return Calendar.current.component(.year, from: selectDate) } var body: some View { Image("peter\(year)") .resizable() .scaledToFill() .frame(width: width, height: width / 4 * 3) .clipped() .brightness(brightnessAmount) } } ``` + slider ``` struct BrightnessSlider: View { @Binding var brightnessAmount: Double var body: some View { HStack { Text("亮度") Slider(value: $brightnessAmount, in: 0...1, minimumValueLabel: Image(systemName: "sun.max.fill").imageScale(.small), maximumValueLabel: Image(systemName: "sun.max.fill").imageScale(.large)) { Text("") } } } } ``` + WheelPickerStyle SegmentedPickerStyle ``` ``` + 動態顯示的 List / Form 欄位 +![](https://i.imgur.com/UK743Xl.png) ``` struct ContentView: View { @State private var buyPhone = true @State private var selectPhone = "iPhone 11 Pro Max" let phones = ["iPhone 11 Pro Max", "iPhone 11 Pro", "iPhone 11"] var body: some View { Form { Toggle("開發 iOS App 要買 iPhone 嗎", isOn: $buyPhone) if buyPhone { VStack(alignment: .leading) { Text("我要買") Picker("買 iPhone", selection: $selectPhone) { ForEach(phones, id: \.self) { (phone) in Text(phone) } } .pickerStyle(SegmentedPickerStyle()) } } } } } ``` + sheet ``` struct ContentView: View { @State private var showSecondPage = false var body: some View { Button("show second page") { showSecondPage = true } .sheet(isPresented: $showSecondPage) { SecondView(showSecondPage: self. $showSecondPage) } } } struct SecondView: View { @Binding var showSecondPage: Bool var body: some View { Button("close") { showSecondPage = false } } } struct SecondView_Previews: PreviewProvider { static var previews: some View { SecondView(showSecondPage: .constant(true)) } } ``` ::: > [color=#ed6f21]重要(在第九章CRUD App) :::spoiler [老師參考](https://medium.com/%E5%BD%BC%E5%BE%97%E6%BD%98%E7%9A%84%E8%A9%A6%E7%85%89-%E5%8B%87%E8%80%85%E7%9A%84-100-%E9%81%93-swift-ios-app-%E8%AC%8E%E9%A1%8C/90-%E4%BD%BF%E7%94%A8-swiftui-%E5%89%B5%E4%BD%9C-crud-%E7%B4%80%E9%8C%84app-2fcbf20088d2) [學姊參考](https://medium.com/%E6%B5%B7%E5%A4%A7-ios-app-%E7%A8%8B%E5%BC%8F%E8%A8%AD%E8%A8%88/crud%E7%B4%80%E9%8C%84-%E6%99%82%E9%96%93%E7%9A%84%E6%94%AF%E9%85%8D%E8%80%85-244ecf8ce887) + 以 @Published 決定哪些 property 變化時要通知畫面更新 ``` class LoversData: ObservableObject { @Published var lovers = [Lover]() } 宣告 lovers 時加上 @Published, 代表 lovers 有變化時會通知觀察 LoversData 的 view, 觀察 LoversData 的 view 將更新畫面 ``` + ToolbarItem ``` .toolbar(content: { ToolbarItem(placement: .navigationBarTrailing) { Button(action: { }, label: { Image(systemName: "plus.circle.fill") }) } }) ``` + editor ``` struct LoverEditor: View { @State private var name = "" @State private var weight = 30 @State private var trueHeart = true var body: some View { NavigationView { Form { TextField("名字", text: $name) Stepper("體重 \(weight)", value: $weight, in: 30...100) Toggle("真心", isOn: $trueHeart) } .navigationBarTitle("Add new lover") .toolbar(content: { ToolbarItem { Button("Save") { } } }) } } } ``` 宣告 ::: > [color=#ed6f21]算數(在第二章程式親密接觸不重要啦) :::spoiler https://drive.google.com/file/d/1JKODOKSRg_2XGmobLE6wOt1-5S8TGmfy/view ``` func addNumber(startNumber:Int, endNumber:Int) -> Int { var sum = 0 sum = startNumber + endNumber return sum } var sum1 = addNumber(startNumber:1, endNumber: 100) var sum2 = addNumber(startNumber:200, endNumber: 300) var sum3 = sum1 + sum2 ``` 因為 List 比較適合顯示內容,Form 比較適合呈現輸入的表單 ::: > [color=#ed6f21]圖(在第三章初體驗&繪圖不重要啦) :::spoiler https://drive.google.com/file/d/1ELMpwksl8EZji6mNIOSS3rE2KGEsq-Y7/view ``` struct ContentView: View { var body: some View { Image("Death on the Nile") .resizable() .scaledToFill() .frame(width: 300, height: 300) .background(Color.black) .clipShape(Circle()) .shadow(radius: 10) } } ``` ``` ZStack { 德國國旗 Path(CGRect(x: 10, y: 10, width: 200, height: 50)) .fill(Color(red: 0, green: 0, blue: 0)) Path(CGRect(x: 10, y: 60, width: 200, height: 50)) .fill(Color(red: 1, green: 0, blue: 0)) Path(CGRect(x: 10, y: 110, width: 200, height: 50)) .fill(Color(red: 1, green: 1, blue: 0)) } ``` ``` VStack { Circle() .frame(width: 200, height: 200) Ellipse() .frame(width: 200, height: 100) Capsule() .frame(width: 200, height: 100) RoundedRectangle(cornerRadius: 30) .frame(width: 200, height: 100) } ``` ``` struct ContentView: View { var body: some View { Path { (path) in path.move(to: CGPoint(x: 0, y: 0)) path.addLine(to: CGPoint(x: 20, y: 300)) path.addLine(to: CGPoint(x: 300, y: 300)) } .fill(Color(red: 1, green: 0, blue: 0)) } } ``` ``` VStack { Path(ellipseIn: CGRect(x: 10, y: 10, width: 100, height: 100)) Path(ellipseIn: CGRect(x: 10, y: 130, width: 200, height: 100)) Path(roundedRect: CGRect(x: 10, y: 260, width: 200, height: 100), cornerRadius: 20) } ``` ``` //曲線 Path { (path) in path.move(to: CGPoint(x: 157, y: 68)) path.addQuadCurve(to: CGPoint(x: 89, y: 56), control: CGPoint(x: 139, y: 34)) path.addQuadCurve(to: CGPoint(x: 75, y: 56), control: CGPoint(x: 82, y: 57)) path.addQuadCurve(to: CGPoint(x: 13, y: 66), control: CGPoint(x: 35, y: 37)) path.addQuadCurve(to: CGPoint(x: 0, y: 109), control: CGPoint(x: 0, y: 82)) path.addQuadCurve(to: CGPoint(x: 43, y: 197), control: CGPoint(x: 1, y: 169)) } .stroke() ``` ``` struct ice: Shape { func path(in rect: CGRect) -> Path { Path{(path) in path.move(to:CGPoint(x: 300, y: 124)) path.addLine(to:CGPoint(x: 270, y: 124)) path.addLine(to:CGPoint(x: 265, y: 154)) path.addLine(to:CGPoint(x: 295, y: 150)) path.addLine(to:CGPoint(x: 300, y: 124)) } } } Group{ ice().stroke(Color(red: 230/255, green: 230/255, blue: 230/255),lineWidth:6) .frame(width: 300, height: 450, alignment: .center) ice().stroke(Color(red: 230/255, green: 230/255, blue: 230/255),lineWidth:6) .frame(width: 300, height: 350, alignment: .center) ice().stroke(Color(red: 230/255, green: 230/255, blue: 230/255),lineWidth:6) .frame(width: 270, height: 300, alignment: .center) ice().stroke(Color(red: 230/255, green: 230/255, blue: 230/255),lineWidth:6) .frame(width: 200, height: 440, alignment: .center) ice().stroke(Color(red: 230/255, green: 230/255, blue: 230/255),lineWidth:6) .frame(width: 300, height: 350, alignment: .center) ice().stroke(Color(red: 230/255, green: 230/255, blue: 230/255),lineWidth:6) .frame(width: 370, height: 420, alignment: .center) ice().stroke(Color(red: 230/255, green: 230/255, blue: 230/255),lineWidth:6) .frame(width: 100, height: 490, alignment: .center) ice().stroke(Color(red: 230/255, green: 230/255, blue: 230/255),lineWidth:6) .frame(width: 100, height: 360, alignment: .center) } ``` ::: > [color=#ed6f21]換頁(button) :::spoiler leading & trailing - 語言順序為由左到右時,leading 為左,trailing 為右 top & bottom - top 為從上,bottom置底 VStack:垂直 HStack:水平 HStack:重疊 ``` struct ContentView: View { var body: some View { VStack(alignment: .leading, spacing: 50) { Image("pic") .resizable() .scaledToFill() .frame(width: 200.0, height: 100.0) .clipped() Text("我要一步一步學App") .background(Color.yellow) } .frame(width: 400) .background(Color.green) } } ``` NavigationView ``` NavigationView { VStack { NavigationLink(destination: RightPersonView()) { Text("對的時間點") } Image(systemName: "clock") .resizable() .scaledToFit() .frame(width: 200, height: 200) } .navigationTitle("那個人是你嗎") } ``` tab ``` struct AppView: View { var body: some View { TabView { SongList() .tabItem { Image(systemName: "music.house.fill") Text("情歌") } ContentView() .tabItem { Image(systemName: "info.circle.fill") Text("About") } .accentColor(.orange) } } } ``` 滑動分頁(各種聯結有利用 SwiftUI 的 PageTabViewStyle 實現分頁照片瀏覽 ![](https://i.imgur.com/Wu03XVV.png) ``` struct ContentView: View { @State private var currentPage = 0 var body: some View { VStack { Text("哈利波特在第\(currentPage+1)頁") TabView(selection: $currentPage) { ForEach(1..<8) { (index) in Image("harry\(index)") .resizable() .scaledToFit() } } .tabViewStyle(PageTabViewStyle()) .indexViewStyle(PageIndexViewStyle(backgroundDisplayMode: .always)) } } } ``` 按按鈕分頁 ![](https://i.imgur.com/VrBAI4k.png) ``` struct ContentView: View { @State private var currentPage = 0 var body: some View { VStack { Text("哈利波特在第\(currentPage+1)頁") Button(action: { currentPage = (currentPage + 1) % 7 }, label: { Image(systemName: "arrow.right.circle.fill") .resizable() .frame(width: 40, height: 40) }) TabView(selection: $currentPage) { ForEach(1..<8) { (index) in Image("harry\(index)") .resizable() .scaledToFit() } } .tabViewStyle(PageTabViewStyle()) .indexViewStyle(PageIndexViewStyle(backgroundDisplayMode: .always)) } } } ``` 捲動的 scroll view預設上下捲動 ``` struct DemoView: View { var body: some View { ScrollView { Color.yellow .frame(height: 200) Color.yellow .frame(height: 200) Color.yellow .frame(height: 200) Color.yellow .frame(height: 200) Color.yellow .frame(height: 200) } } } ``` 水平捲動 ``` ScrollView(.horizontal, showsIndicators: false) { HStack(spacing: 20) { Image("peter0") .resizable() .scaledToFill() .frame(width: 200) .clipped() Image("peter1") .resizable() .scaledToFill() .frame(width: 200) .clipped() Image("peter2") .resizable() .scaledToFill() .frame(width: 200) .clipped() } .frame(height: 200) .padding(.horizontal, 20) } ``` + sheet ``` struct ContentView: View { @State private var showSecondPage = false var body: some View { Button("show second page") { showSecondPage = true } .sheet(isPresented: $showSecondPage) { SecondView(showSecondPage: self. $showSecondPage) } } } 將 ``` ::: > [color=#ed6f21]list(在第四章畫面設計ex 圖的分布怎麼放&list) :::spoiler https://drive.google.com/file/d/1QntgNpR5XFK2frMxDESAZB540xaiUGpU/view ![](https://i.imgur.com/dpIzh7u.png) ::: > [color=#ed6f21]其他() :::spoiler 多行捲動文字的 TextEditor ``` struct ContentView: View { var body: some View { TextEditor(text: .constant(""" 摘一顆蘋果 等你從門前經過 送到你的手中幫你解渴 像夏天的可樂 像冬天的可可 你是對的時間對的角色 已經約定過 一起過下個週末 你的小小情緒對我來說 我也不知為何 傷口還沒癒合 你就這樣闖進我的心窩 """ )) .accentColor(.clear) .frame(width: 200, height: 200) } } ``` 動畫(第五章) ``` struct ContentView: View { @State private var show = false var body: some View { VStack { if show { Image("蒙娜麗莎") .transition(.opacity) } } .animation(.easeInOut(duration: 5)) .onAppear { self.show = true } } } ``` 點選 button 出現 / 消失 ``` struct ContentView: View { @State private var show = false var body: some View { VStack { Button(show ? "hide" : "show") { self.show.toggle() } if show { Image("蒙娜麗莎") .transition(.opacity) } else { Image("蒙娜麗莎") .hidden() } } .animation(.easeInOut(duration: 5)) } } 圖片不顯示時依然佔著空間 ``` [**?!**](https://medium.com/%E5%BD%BC%E5%BE%97%E6%BD%98%E7%9A%84-swift-ios-app-%E9%96%8B%E7%99%BC%E6%95%99%E5%AE%A4/%E7%B0%A1%E6%98%93%E8%AA%AA%E6%98%8Eswift-4-optional-7da19051e835) [**?!2**](https://www.appcoda.com.tw/swift-optional-intro/) ?裝在盒子裡 ![](https://i.imgur.com/o6hAkP7.png) !解包裝 ![](https://i.imgur.com/TilDHIl.png) ?? ![](https://i.imgur.com/NgPP78e.png) ![](https://i.imgur.com/gqScnEO.png) ![](https://i.imgur.com/BmW3EBF.png) ![](https://i.imgur.com/Jj0ac2n.png) ::: > [color=#ed6f21]考古 :::spoiler :::