如何在"当前位置"上设置一个pin,将pin用作Geofence,在Enter上提醒用户,然后重置所



我是一名产品设计师,试图构建一个基于位置的提醒概念,以验证早期的想法。我可以在Figma中创建所有这些屏幕的原型,但实时定位和上下文警报是我假设的基础,所以我在这里竭尽全力,试图在SwiftUI 中实现这一点

https://www.figma.com/proto/jxYwPbqe4oqsXBbf6CZDDi/Location-Reminder-Spec?page-id=0%3A1&节点id=1%3A189&视口=161%2C384%2C0.12701110541820526&缩放=缩小

我一直在从各种教程(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
}
}

ContentView.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()
}
}

提醒按钮.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)
}
}
}
}

最新更新