iT邦幫忙

2022 iThome 鐵人賽

DAY 14
0
tags: 釣魚術 swift swiftui

雜談

  • 自己挖的坑自己跳
  • 另外一位釣魚大大沒有開賽,我好難過
  • 關於「用嘴巴寫程式」 - iThome 上面有篇文章,討論好的嘴巴寫程式與虛的嘴巴寫程式

拆解欲開發的功能

  • 我們接續先前釣點地圖功能的實作,有一個功能是長按地圖畫面 > 是否新增私房釣點?
  • [x] 長按手勢 【Day 13】
  • [x] 跳出對話框(是否新增釣點?新增/取消)或是功能選單(新增釣點/.../取消) 【Day 13】
  • [ ] 如果要新增釣點的話,就要取得手指按下地點的經緯度
  • [ ] 製作一個介面讓使用者輸入名稱、並將經緯度和名稱一併存起來
  • [x] 載入地圖時把圖釘加上去 【Day 14】
  • [ ] 從檔案或是資料庫撈取座標

今日開發進度

  • 接續昨天的長按跳出表單後,理論上我該接續寫「抓取座標」的功能,只不過抓取座標後,還要把他畫在地圖上、存到檔案或資料庫裡。
  • 我腦中想像不出檔案裡面要放哪些格式啦,所以先來畫畫圖釘,這樣等我畫完之後,我就知道要怎麼存資料了。

MapMarker

  • 因為我要放上圖釘,查了關鍵字,看到了 MapMarker 的用法
  • 官方文件這麼描述的:A balloon-shaped annotation that marks a map location.
  • 就是一個氣球形狀的標記,看圖比較快瞭解在說什麼

MapAnnotation

  • 在我的認知上,MapMarkerMapAnnotation 這兩者幾乎是一樣的,差異就在 MapAnnotation 可以客製化他的圖釘樣式
  • 直接看兩者文件附上的範例程式碼比對一下就不難發現
  • 客製化的圖釘樣式則是長得像下圖:

實作手法

一個可以擺放圖釘資料的 struct - PinLocation

  • 關於那些重複出現的元件,例如在 List 或 ForEach 去迭代的內容,SwiftUI 需要識別出迭代物間的不同,因此常用的做法便是在這些元件中,插入一個獨一無二UUID(),並且使之符合Identifiable protocol。

    • 好比,全台灣有好幾個人名字都叫羅志祥
    • 這些羅志祥都有相同的身高和體重,那怎麼區別他們之間的不同?
    • 看他們會不會唱獨一無二? 或者是空幹?
    • 上述方法可能都相同,無法識別。唯獨他們的身分證字號,理論上是不會重複的。

    羅志祥:翁立 翁立 友友友

    翁立友:...

    struct PinLocation: Identifiable {
        let id = UUID()
        var name: String
        var image: String
        var coordinate: CLLocationCoordinate2D
    
        init(name: String, image: String, coordinate: CLLocationCoordinate2D) {
            self.name = name
            self.image = image
            self.coordinate = coordinate
        }
    
        init() {
            self.name = "秘密釣點 - 五股聖母宮"
            self.image = "default"
            self.coordinate = CLLocationCoordinate2D(latitude:25.1125, longitude:121.4582)
        }
    }
    
    
  • 因為預計這些圖釘之間,會有不同的座標、名字、和客製化的釣點圖片,所以先把圖釘內容的格式訂成上面那樣。

修改繪製 MapView 程式碼

  • 先看完整程式碼片段
struct MapView: View {
    // 用來記錄長按手勢是否被觸發
    @State private var isLongPressed = false
    @StateObject private var viewModel = FishingLocationModel()
    @State private var annotatedPin: PinLocation = PinLocation(
        name: "林口發電廠", image:"", coordinate: CLLocationCoordinate2D(latitude: 25.121356, longitude: 121.295589))
    @State private var annotatedPin2: PinLocation = PinLocation(
        name: "林口發電廠2", image:"", coordinate: CLLocationCoordinate2D(latitude: 25.125, longitude: 121.3))

    var body: some View {
        ZStack(alignment: .topTrailing) {
            Map(coordinateRegion: $viewModel.region,
                showsUserLocation: true,
                annotationItems: [annotatedPin, annotatedPin2]) { item in
                    // MapMarker(coordinate: item.coordinate, tint: .red)
                    MapAnnotation(coordinate: item.coordinate) {
                        Image(systemName: "hand.thumbsup.circle.fill")
                            .resizable()
                            .foregroundColor(.red)
                            .background(Color.white)
                            .clipShape(Circle())
                    }
                }
                .edgesIgnoringSafeArea(.all)
                .gesture(DragGesture())
                .onLongPressGesture {
                    isLongPressed.toggle()
                }.actionSheet(isPresented: $isLongPressed) {
                    ActionSheet(title: Text("新增私房釣點嗎?"),
                                message: nil,
                                buttons: [
                                    .default(Text("新增釣點")) {
                                        // Yes
                                    },
                                    .cancel()
                                ])
                }
            LocationButton(.currentLocation) {
                viewModel.requestAllowOnceLocationPermission()
            }
            .foregroundColor(.white)
            .cornerRadius(15)
            .labelStyle(.iconOnly)
            .symbolVariant(.fill)
            .padding(10)
        }
    }
}

其中,製作圖釘實例的方式

@State private var annotatedPin: PinLocation = PinLocation(
        name: "林口發電廠", image:"", coordinate: CLLocationCoordinate2D(latitude: 25.121356, longitude: 121.295589))
  • 其實就是餵三個參數給 PinLocation struct,產生的實利指派給 annotatedPin
    • 地點名稱
    • 地點圖片
    • 地點座標
  • 另外一個地點,產生的實例指派給 annotatedPin2

結論與心得

  • 接下來,我們要把資料和程式切割開來。簡單的做法,就是存成檔案,裡面放資料。
  • 然後要寫一支函式讀取檔案,變成陣列。
  • 並且放圖釘的時候,讀取陣列以繪製。

上一篇
【Day 13】Swift 擷取螢幕手勢
下一篇
【Day 15】Swift UI - 重構 FishingLocationView / SecretLocation / 使用 switch case
系列文
無法成為釣魚大師也要努力摸魚!!辣個吃魚神器 APP38
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言