本文介绍了如何在wiftUI中添加移回用户位置按钮?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我是SWIFT和SwiftUI的新手,我想在地图视图的顶部添加一个用户跟踪按钮,以便用户的当前位置在点击时可以回到屏幕中心。我已经拥有地图视图和按钮,但无法使其工作。这里是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
的类中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中添加移回用户位置按钮?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!