2
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[SwiiftUI] Mapを自動で動かす

Last updated at Posted at 2020-04-30

SwiftUIでMKMapViewを自動で動かしてピンを建てる画面を作りました。
どんどんピンに寄っていきます

完成図

ezgif.com-video-to-gif_320.gif

コード


import SwiftUI
import MapKit
import CoreLocation


struct MovingMapView: View {
    @State var location: CLLocationCoordinate2D = CLLocationCoordinate2D(latitude:35.658577, longitude:139.745451)
    @State var scale: Double = 0.2
    // 移動する地点の座標
    var locations: [CLLocationCoordinate2D]
        = [CLLocationCoordinate2D(latitude:35.658577, longitude:139.695451),
            CLLocationCoordinate2D(latitude:35.658577, longitude:139.645451),
            CLLocationCoordinate2D(latitude:35.658577, longitude:139.595451)]
           
    var body: some View {
        VStack{
            Button(action:{self.move_location()}){
                Text("Move")
            }
            MapView(center_coord:self.$location, scale:self.$scale)
        }
    }
    
    func move_location(){
        DispatchQueue.global(qos: .utility).async{
            for (i, loc) in self.locations.enumerated(){
                // scaleが0.2 → 0.1になるよう遷移
                self.scale = 0.2 - Double(i+1) * (0.2 - 0.1) / Double(self.locations.count)
                self.location = loc
                Thread.sleep(forTimeInterval: 1.0)
            }
        }
    }
}


struct MapView: UIViewRepresentable {
    @Binding var center_coord: CLLocationCoordinate2D
    @Binding var scale: Double
    static var prePosition: CLLocationCoordinate2D?
    
    func makeUIView(context: UIViewRepresentableContext<MapView>) -> MKMapView {
        let view = MKMapView(frame: .zero)
        view.delegate = context.coordinator
        view.showsUserLocation = true
        MapView.self.prePosition = self.center_coord
        return view
    }

    func updateUIView(_ uiView: MKMapView, context: UIViewRepresentableContext<MapView>) {
        // ピンの追加
        let annotation = MKPointAnnotation()
        annotation.coordinate = self.center_coord
        annotation.title = "Wow"
        uiView.addAnnotation(annotation)
        
        // 直線の描画
        let coordinates = [MapView.self.prePosition! , self.center_coord]
        let polyLine = MKPolyline(coordinates: coordinates, count: coordinates.count)
        uiView.addOverlay(polyLine)
        
        // Regionの指定
        let span = MKCoordinateSpan(latitudeDelta:self.scale, longitudeDelta:self.scale)
        let region = MKCoordinateRegion(center:self.center_coord, span:span)
        uiView.setRegion(region, animated:true)
        
        MapView.self.prePosition = self.center_coord
    }
    
    func makeCoordinator() -> MapView.Coordinator {
        return MapView.Coordinator(parent: self)
    }
    
    class Coordinator: NSObject, MKMapViewDelegate {

        var parent : MapView!
        init(parent: MapView){
            self.parent = parent
        }

        // annoattionタップ時のメソッド(現在は未設定)
        func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
        }
        
        // addOverlay時のメソッド
        func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
            if let polyline = overlay as? MKPolyline {
                let polylineRenderer = MKPolylineRenderer(polyline: polyline)
                polylineRenderer.strokeColor = .red
                polylineRenderer.lineWidth = 2.0
                return polylineRenderer
            }
            return MKOverlayRenderer()
        }
    }
}

解説

MovingMapView

  • Stateプロパティ
    @State var location: CLLocationCoordinate2D = CLLocationCoordinate2D(latitude:35.658577, longitude:139.745451)
    @State var scale: Double = 0.2

location: 中心座標, scale: 縮尺. これらの値を変化させて地図の表示を更新させる。

  • move_locationメソッド
func move_location(){
        DispatchQueue.global(qos: .utility).async{
            for (i, loc) in self.locations.enumerated(){
                // scaleが0.2 → 0.1になるよう遷移
                self.scale = 0.2 - Double(i+1) * (0.2 - 0.1) / Double(self.locations.count)
                self.location = loc
                Thread.sleep(forTimeInterval: 1.0)
            }
        }
    }

DispatchQueueを使って、メインスレッドとは別のスレッドで一定間隔で非同期に値を更新させる。

MapView

UIKitのMKMapViewを利用します。

  • UpdateUIViewメソッド
func updateUIView(_ uiView: MKMapView, context: UIViewRepresentableContext<MapView>) {
        // ピンの追加
        let annotation = MKPointAnnotation()
        annotation.coordinate = self.center_coord
        annotation.title = "Wow"
        uiView.addAnnotation(annotation)

        // 直線の描画
        let coordinates = [MapView.self.prePosition! , self.center_coord]
        let polyLine = MKPolyline(coordinates: coordinates, count: coordinates.count)
        uiView.addOverlay(polyLine)

        // Regionの指定
        let span = MKCoordinateSpan(latitudeDelta:self.scale, longitudeDelta:self.scale)
        let region = MKCoordinateRegion(center:self.center_coord, span:span)
        uiView.setRegion(region, animated:true)

        MapView.self.prePosition = self.center_coord
    }

MovingMapViewのlocationかscaleが変化すると、このメソッドが呼び出され、ピンと直線を引き、地図表示を更新する。

2
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?