100 Days of SwiftUI(DAY 69(Project14 part 2))

MapKitとSwiftUIの統合
Integrating MapKit with SwiftUI

import SwiftUI
import MapKit

struct MapView: UIViewRepresentable {
    func makeUIView(context: UIViewRepresentableContext<MapView>) -> MKMapView {
        let mapView = MKMapView()
        return mapView
    }

    func updateUIView(_ view: MKMapView, context: UIViewRepresentableContext<MapView>) {
    }
}

import SwiftUI

struct ContentView: View {
    var body: some View {
        MapView()
        .edgesIgnoringSafeArea(.all)
        
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

MapKitコーディネーターとの通信
Communicating with a MapKit coordinator

MKMapViewをSwiftUI に埋め込むのは簡単ですが、マップで何か便利なことをしたい場合は、コーディネーターを導入する必要があります。これは、マップビューのデリゲートとして機能し、SwiftUIとの間でデータを受け渡しできるクラスです。

UIImagePickerControllerと同様に、これは、から継承するネストされたクラスを作成し、NSObjectビューまたはビューコントローラーが動作するすべてのデリゲートプロトコルに準拠させ、親の構造体への参照を与えて、データをSwiftUIに戻すことができるようにすることを意味します。


class Coordinator: NSObject, MKMapViewDelegate {
    var parent: MapView

    init(_ parent: MapView) {
        self.parent = parent
    }
}

func makeCoordinator() -> Coordinator {
    Coordinator(self)
}

mapView.delegate = context.coordinator

これで構成が完了しました。つまり、コーディネーターにマップビューでのアクティビティに応答させるメソッドを追加できるようになります。コーディネーターはマップビューのデリゲートであることを忘れないでください。つまり、何か興味深いことが起こったときに、マップが移動したとき、ロードが開始して終了したとき、ユーザーがマップ上にいるとき、マップピンがタッチされたときに通知されます。等々。


マーカーの外観をカスタマイズする場合は、コーディネーターcoordinatorを元に戻す必要があります。マップビューはコーディネーターでと呼ばれる特定のメソッドを探し、mapView(_:viewFor:)存在する場合は呼び出されます。これにより、カスタムの注釈ビューを作成できますが、ここでもAppleは、の形式で優れた代替手段を提供しMKPinAnnotationViewます。

MapKitは、コーディネータークラスを自動的に調べて、これらの通知のどれについて通知するかを確認します。これは、関数シグネチャを使用して行われます。正確な名前とパラメータリストを持つメソッドが見つかると、それが呼び出されます。

reuseIdentifier
nil上記の再利用識別子として指定したので、ビューを再利用したくありません。これは、単に学習しているときは問題ありません。現実的には、ほんの一握りのピンだけを使用するときはいつでもかまいませんが、後で、より効率的なルートを紹介します。つまり、ビューを再利用します。

//
//  MapView.swift
//  BucketList
//
//  Created by Naoki Abe on 2020/08/25.
//  Copyright © 2020 Naoki Abe. All rights reserved.
//

import SwiftUI
import MapKit

struct MapView: UIViewRepresentable {
    
    class Coordinator: NSObject, MKMapViewDelegate {
        var parent: MapView

        init(_ parent: MapView) {
            self.parent = parent
        }
        //マップビューが表示領域を変更
        func mapViewDidChangeVisibleRegion(_ mapView: MKMapView) {
            print(mapView.centerCoordinate)
        }
        //メソッドはマップビューと注釈を渡され、その注釈を表示するために使用する正しいビューを返す必要があります
        func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
            let view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: nil)
            view.canShowCallout = true
            return view
        }
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    func makeUIView(context: Context) -> MKMapView {
        let mapView = MKMapView()
        mapView.delegate = context.coordinator

        let annotation = MKPointAnnotation()
        annotation.title = "London"
        annotation.subtitle = "Capital of England"
        annotation.coordinate = CLLocationCoordinate2D(latitude: 51.5, longitude: 0.13)
        mapView.addAnnotation(annotation)

        return mapView
    }

    func updateUIView(_ view: MKMapView, context: UIViewRepresentableContext<MapView>) {
    }
}


struct ContentView: View {
    var body: some View {
        MapView()
        .edgesIgnoringSafeArea(.all)

    }
}

SwiftUIでTouch IDとFace IDを使用する
Using Touch ID and Face ID with SwiftUI

Info.plist
Scroll through the list of keys until you find “Privacy – Face ID Usage Description” and give it the value “We need to unlock your data.


import SwiftUI
import LocalAuthentication


struct ContentView: View {
    @State private var isUnlocked = false
    
    func authenticate() {
        let context = LAContext()
        var error: NSError?

        // check whether biometric authentication is possible
        if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
            // it's possible, so go ahead and use it
            let reason = "We need to unlock your data."

            context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) { success, authenticationError in
                // authentication has now completed
                DispatchQueue.main.async {
                    if success {
                        // authenticated successfully
                        self.isUnlocked = true
                    } else {
                        // there was a problem
                    }
                }
            }
        } else {
            // no biometrics
        }
    }
    
    var body: some View {
        VStack {
            if self.isUnlocked {
                Text("Unlocked")
            } else {
                Text("Locked")
            }
        }
        .onAppear(perform: authenticate)
        
    }
}