如何在wiftUI中添加移回用户位置按钮? [英] How to add a move back to user location button in swiftUI?
本文介绍了如何在wiftUI中添加移回用户位置按钮?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
这里是ContentView.swft文件,我被*:
卡住了import SwiftUI
import MapKit
struct ContentView: View {
var body: some View {
ZStack {
MapView(locationManager: $locationManager)
.edgesIgnoringSafeArea(.bottom)
HStack {
Spacer()
VStack {
Spacer()
Button(action: {
******
}) {
Image(systemName: "location")
.imageScale(.small)
.accessibility(label: Text("Locate Me"))
.padding()
}
.background(Color.white)
.cornerRadius(10)
.padding()
}
}
}
}
这里是MapView.swft:
import SwiftUI
import MapKit
import CoreLocation
import ECMapNavigationAble
struct MapView: UIViewRepresentable, ECMapNavigationAble{
var locationManager = CLLocationManager()
func makeUIView(context: UIViewRepresentableContext<MapView>) -> MKMapView {
MKMapView()
}
func updateUIView(_ view: MKMapView, context: UIViewRepresentableContext<MapView>){
view.showsUserLocation = true
view.isPitchEnabled = false
self.locationManager.requestAlwaysAuthorization()
self.locationManager.requestWhenInUseAuthorization()
if CLLocationManager.locationServicesEnabled() {
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
}
if let userLocation = locationManager.location?.coordinate {
let userLocationEC = ECLocation(coordinate : userLocation, type: .wgs84)
let viewRegion = MKCoordinateRegion(center: userLocationEC.gcj02Coordinate, latitudinalMeters: 200, longitudinalMeters: 200)
view.userTrackingMode = .follow
view.setRegion(viewRegion, animated: true)
}
DispatchQueue.main.async{
self.locationManager.startUpdatingLocation()
}
}
}
推荐答案
我遇到了同样的问题,几个小时后,我设法使某些东西按要求工作
- 启动时,如果用户授权,它会显示用户位置,但会等待他轻触按钮以激活以下按钮。
- 如果他授权并点击该按钮,它将跟随他。
- 如果应用程序由于某种原因无法访问他的位置(拒绝访问,限制…),它会告诉他在"设置"中进行更改,然后将他重定向到那里。
- 如果他在运行应用时更改授权,它将自动更改。
- 如果地图跟随他,该按钮将消失。
- 如果他拖动地图(停止跟踪),该按钮将再次出现。
- (该按钮支持黑暗模式)
我真的希望它能帮助你,我想有一天我会把它放到GitHub上。如果我这样做,我会在此处添加链接。
首先,我不想每次都重新创建MKMapView,所以我将其放在名为MapViewContainer
的类中
我认为这不是一个好做法,尽管🤷🏻♂️
如果不想使用,只需在
MKMapViewRepresentable
中将@EnvironmentObject private var mapViewContainer: MapViewContainer
替换为let mapView = MKMapView(frame: .zero)
(并将mapViewContainer.mapView
更改为mapView
)
import MapKit
class MapViewContainer: ObservableObject {
@Published public private(set) var mapView = MKMapView(frame: .zero)
}
然后,我可以创建我的MapViewRepresentable
import SwiftUI
import MapKit
// MARK: - MKMapViewRepresentable
struct MKMapViewRepresentable: UIViewRepresentable {
var userTrackingMode: Binding<MKUserTrackingMode>
@EnvironmentObject private var mapViewContainer: MapViewContainer
func makeUIView(context: UIViewRepresentableContext<MKMapViewRepresentable>) -> MKMapView {
mapViewContainer.mapView.delegate = context.coordinator
context.coordinator.followUserIfPossible()
return mapViewContainer.mapView
}
func updateUIView(_ mapView: MKMapView, context: UIViewRepresentableContext<MKMapViewRepresentable>) {
if mapView.userTrackingMode != userTrackingMode.wrappedValue {
mapView.setUserTrackingMode(userTrackingMode.wrappedValue, animated: true)
}
}
func makeCoordinator() -> MapViewCoordinator {
let coordinator = MapViewCoordinator(self)
return coordinator
}
// MARK: - Coordinator
class MapViewCoordinator: NSObject, MKMapViewDelegate, CLLocationManagerDelegate {
var control: MKMapViewRepresentable
let locationManager = CLLocationManager()
init(_ control: MKMapViewRepresentable) {
self.control = control
super.init()
setupLocationManager()
}
func setupLocationManager() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.pausesLocationUpdatesAutomatically = true
}
func followUserIfPossible() {
switch CLLocationManager.authorizationStatus() {
case .authorizedAlways, .authorizedWhenInUse:
control.userTrackingMode.wrappedValue = .follow
default:
break
}
}
private func present(_ alert: UIAlertController, animated: Bool = true, completion: (() -> Void)? = nil) {
// UIApplication.shared.keyWindow has been deprecated in iOS 13,
// so you need a little workaround to avoid the compiler warning
// https://stackoverflow.com/a/58031897/10967642
let keyWindow = UIApplication.shared.windows.first { $0.isKeyWindow }
keyWindow?.rootViewController?.present(alert, animated: animated, completion: completion)
}
// MARK: MKMapViewDelegate
func mapView(_ mapView: MKMapView, didChange mode: MKUserTrackingMode, animated: Bool) {
#if DEBUG
print("(type(of: self)).(#function): userTrackingMode=", terminator: "")
switch mode {
case .follow: print(".follow")
case .followWithHeading: print(".followWithHeading")
case .none: print(".none")
@unknown default: print("@unknown")
}
#endif
if CLLocationManager.locationServicesEnabled() {
switch mode {
case .follow, .followWithHeading:
switch CLLocationManager.authorizationStatus() {
case .notDetermined:
locationManager.requestWhenInUseAuthorization()
case .restricted:
// Possibly due to active restrictions such as parental controls being in place
let alert = UIAlertController(title: "Location Permission Restricted", message: "The app cannot access your location. This is possibly due to active restrictions such as parental controls being in place. Please disable or remove them and enable location permissions in settings.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Settings", style: .default) { _ in
// Redirect to Settings app
UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!)
})
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
present(alert)
DispatchQueue.main.async {
self.control.userTrackingMode.wrappedValue = .none
}
case .denied:
let alert = UIAlertController(title: "Location Permission Denied", message: "Please enable location permissions in settings.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Settings", style: .default) { _ in
// Redirect to Settings app
UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!)
})
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
present(alert)
DispatchQueue.main.async {
self.control.userTrackingMode.wrappedValue = .none
}
default:
DispatchQueue.main.async {
self.control.userTrackingMode.wrappedValue = mode
}
}
default:
DispatchQueue.main.async {
self.control.userTrackingMode.wrappedValue = mode
}
}
} else {
let alert = UIAlertController(title: "Location Services Disabled", message: "Please enable location services in settings.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Settings", style: .default) { _ in
// Redirect to Settings app
UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!)
})
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
present(alert)
DispatchQueue.main.async {
self.control.userTrackingMode.wrappedValue = mode
}
}
}
// MARK: CLLocationManagerDelegate
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
#if DEBUG
print("(type(of: self)).(#function): status=", terminator: "")
switch status {
case .notDetermined: print(".notDetermined")
case .restricted: print(".restricted")
case .denied: print(".denied")
case .authorizedAlways: print(".authorizedAlways")
case .authorizedWhenInUse: print(".authorizedWhenInUse")
@unknown default: print("@unknown")
}
#endif
switch status {
case .authorizedAlways, .authorizedWhenInUse:
locationManager.startUpdatingLocation()
control.mapViewContainer.mapView.setUserTrackingMode(control.userTrackingMode.wrappedValue, animated: true)
default:
control.mapViewContainer.mapView.setUserTrackingMode(.none, animated: true)
}
}
}
}
最后,将其放入SwiftUIView
import SwiftUI
import CoreLocation.CLLocation
import MapKit.MKAnnotationView
import MapKit.MKUserLocation
struct MapView: View {
@State private var userTrackingMode: MKUserTrackingMode = .none
var body: some View {
ZStack {
MKMapViewRepresentable(userTrackingMode: $userTrackingMode)
.environmentObject(MapViewContainer())
.edgesIgnoringSafeArea(.all)
VStack {
if !(userTrackingMode == .follow || userTrackingMode == .followWithHeading) {
HStack {
Spacer()
Button(action: { self.followUser() }) {
Image(systemName: "location.fill")
.modifier(MapButton(backgroundColor: .primary))
}
.padding(.trailing)
}
.padding(.top)
}
Spacer()
}
}
}
private func followUser() {
userTrackingMode = .follow
}
}
fileprivate struct MapButton: ViewModifier {
let backgroundColor: Color
var fontColor: Color = Color(UIColor.systemBackground)
func body(content: Content) -> some View {
content
.padding()
.background(self.backgroundColor.opacity(0.9))
.foregroundColor(self.fontColor)
.font(.title)
.clipShape(Circle())
}
}
这篇关于如何在wiftUI中添加移回用户位置按钮?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文