繁体   English   中英

如何在当前位置设置图钉,将图钉用作地理围栏,在输入时提醒用户,然后全部重置/重新开始?

[英]How do I set a pin on Current Location, use Pin as Geofence, alert user onEnter, then reset all / start over again?

我是一名产品设计师,试图提出一个基于位置的提醒概念来验证一个相当早期的想法。 我可以在 Figma 中对所有这些屏幕进行原型设计,但实时位置和上下文警报是我假设的基础,所以在这里我努力在 SwiftUI 中实现这一目标 😅

https://www.figma.com/proto/jxYwPbqe4oqsXBbf6CZDDi/Location-Reminder-Spec?page-id=0%3A1&node-id=1%3A189&viewport=161%2C384%2C0.1270111054182052

我一直在从各种教程(Ray Wenderlich、Hacking Swift、Apple 的 Swift UI)和关于位置等的片段中拼凑出来,但大多数教程都有更多的对象和视图以及我不需要的其他东西,这是使我的 MVP 拼贴方法变得复杂。

到目前为止,我有一个 MKMapView 以我的用户位置坐标为中心,并且我已经显示了我的按钮。

我在想

  • 如何使用来自用户位置的坐标创建 CLCircularRegion?

  • 如何使用来自用户位置的坐标在地图上放置 MKMapAnnotation 以及如何在按下通知内的按钮后删除注释?

有了上述内容,我想我将能够理清如何触发通知并在 Enter 上显示通知。

到目前为止,我在项目中有 4 个文件...

LocationManager.swift

import Foundation
import MapKit
import CoreLocation

class LocationManager: NSObject, CLLocationManagerDelegate, ObservableObject {
    @Published var region = MKCoordinateRegion()
    private let manager = CLLocationManager()
        override init() {
                super.init()
                manager.delegate = self
                manager.desiredAccuracy = kCLLocationAccuracyBest
                manager.requestWhenInUseAuthorization()
                manager.startUpdatingLocation()
        }
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        locations.last.map{
            region = MKCoordinateRegion(
                center: CLLocationCoordinate2D(latitude: $0.coordinate.latitude, longitude: $0.coordinate.longitude),
                span: MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5)
            )
        }
    }
}

extension CLLocation {
    var latitude: Double {
        return self.coordinate.latitude
    }
    
    var longitude: Double {
        return self.coordinate.longitude
    }
}

内容视图.swift

import CoreLocation
import MapKit
import SwiftUI

struct ContentView: View {
    @StateObject var manager = LocationManager()
    @State private var locations = [MKPointAnnotation] ()
    
    
var body: some View {
    VStack {
        HStack {
            Text("Location Reminder")
                .font(.largeTitle)
                .bold()
                .foregroundColor(.black)
            Spacer()
        }
        .padding()

        ZStack (alignment: .bottomTrailing) {
            Map(coordinateRegion: $manager.region,
                showsUserLocation: true)
                .ignoresSafeArea()
            ReminderButton()
                .padding()
            }
        }
    }
}


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

ReminderButton.swift

import Foundation
import SwiftUI

struct ReminderButton: View {
    
    var body: some View {
        VStack {
            Spacer()
                Button(action: {
            }) {
                HStack {
                    Image(systemName: "plus.circle.fill")
                        .resizable()
                        .frame(width: 40, height: 40)
                    Text("Add a Reminder")
                }
                .padding()
                .background(Color.white)
                .cornerRadius(40)
                .shadow(color: .gray, radius: 0.2, x: 1, y: 1)
            }
        }
    }
}

我有一个名为Geofence.swift的空文件,我计划在其中创建一个 CLCircularRegion 并在 Enter 上设置通知/警报等。

感谢任何和所有帮助/建议/建议。 如果有办法改进我的帖子和/或它是否属于其他地方,也请 LMK。

import SwiftUI
import MapKit
import CoreLocation
struct SingleLocationView: View {
    @StateObject var manager = LocationManager()
    @State private var locations = [PinnedLocation] ()
    @State var userTrackingMode: MapUserTrackingMode = .follow
    let radius: CGFloat = 160 //meters approx 0.1 miles
    var body: some View {
        
        VStack {
            HStack {
                VStack{
                    Text("Location Reminder")
                        .font(.largeTitle)
                        .bold()
                        .foregroundColor(.black)
                }
                Spacer()
                
            }
            .padding()
            
            ZStack (alignment: .bottomTrailing) {
                GeometryReader{ geo in
                    Map(coordinateRegion: $manager.region, interactionModes: .all, showsUserLocation: true, userTrackingMode: $userTrackingMode, annotationItems: locations, annotationContent: { annotation in
                        MapAnnotation(coordinate: annotation.coordinate, anchorPoint: CGPoint(x: 0.5, y: 0.5), content: {
                            //Use this vs Circle because your map is a rectangle circumference is an oval
                            //Maybe a stretched Circle could be a little more accurate
                            RoundedRectangle(cornerRadius: 25)
                                .foregroundColor(.white)
                            
                                .overlay(
                                    Image(systemName: "mappin").foregroundColor(.red))
                            
                            // The screen vertical and horizontal multiplied by your radius divided Map vertial/horizontal span in meters
                                .frame(width: (geo.size.width/manager.regionSpanInLongitudeDeltaMeters.value) * radius, height: (geo.size.height/manager.regionSpanInLatitudeDeltaMeters.value) * radius, alignment: .center)
                            
                            
                        })
                    })
                    
                        .ignoresSafeArea()
                    
                }
                ReminderButton(locations: $locations).environmentObject(manager)
                    .padding()
            }
        }
    }
}

struct SingleLocationView_Previews: PreviewProvider {
    static var previews: some View {
        SingleLocationView()
    }
}

//You MKAnnotaion is a Protocol you need to create your own class
//MKPointAnnotation is a MKShape for use with MKMapView
class PinnedLocation: NSObject, MKAnnotation, Identifiable{
    var title: String?
    var subtitle: String?
    var coordinate: CLLocationCoordinate2D
    
    init(title: String? = nil, subtitle: String? = nil, coordinate: CLLocationCoordinate2D) {
        self.title = title
        self.subtitle = subtitle
        self.coordinate = coordinate
    }
    ///Get the CLCircularRegion with the given radius
    func getCLCircularRegion(radius: CGFloat) -> CLCircularRegion{
        CLCircularRegion(center: self.coordinate, radius: radius, identifier: "\(self.id)")
    }
}

extension UnitLength{
    //This is approx do research on degrees to meters
    static let degree = UnitLength(symbol: "degree", converter: UnitConverterLinear(coefficient: 111111))
}
class LocationManager: NSObject, CLLocationManagerDelegate, ObservableObject {
    @Published var region = MKCoordinateRegion()
    //If you do it the way you were doing it get the most current location from here to append to your array
    @Published var lastLocation: CLLocation = CLLocation()
    ///Region gives span in degrees. This is a rough conversion
    var regionSpanInLatitudeDeltaMeters: Measurement<UnitLength>{
        Measurement(value: region.span.latitudeDelta, unit: UnitLength.degree).converted(to: .meters)
    }
    ///Region gives span in degrees. This is a rough conversion
    var regionSpanInLongitudeDeltaMeters: Measurement<UnitLength>{
        Measurement(value: region.span.longitudeDelta, unit: UnitLength.degree).converted(to: .meters)
    }
    private let manager = CLLocationManager()
    override init() {
        super.init()
        manager.delegate = self
        manager.desiredAccuracy = kCLLocationAccuracyBest
        //Don't need it SwiftUI does this for you
        //manager.requestWhenInUseAuthorization()
        //manager.startUpdatingLocation()
    }
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        locations.last.map{
            region = MKCoordinateRegion(
                center: CLLocationCoordinate2D(latitude: $0.coordinate.latitude, longitude: $0.coordinate.longitude),
                span: MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5)
            )
        }
        lastLocation = locations.last!
        
    }
}

extension CLLocationCoordinate2D{
    var annotation: PinnedLocation{
        PinnedLocation(coordinate: CLLocationCoordinate2D(latitude: self.latitude, longitude: self.longitude))
    }
}
struct ReminderButton: View {
    //The button joins your location manager with the locations displayed. It needs access to both
    @EnvironmentObject var manager: LocationManager
    @Binding var locations: [PinnedLocation]
    
    var body: some View {
        VStack {
            Spacer()
            Button(action: {
                //Append the current center/location to your list of annotions
                locations.append(manager.region.center.annotation)
            }) {
                HStack {
                    Image(systemName: "plus.circle.fill")
                        .resizable()
                        .frame(width: 40, height: 40)
                    Text("Add a Reminder")
                }
                .padding()
                .background(Color.white)
                .cornerRadius(40)
                .shadow(color: .gray, radius: 0.2, x: 1, y: 1)
            }
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM