Yandex.Maps:我去了卡控制器-我立即获得了用户的位置(好吧,现在认真了)

再次问候!

最近,我发表了一篇对Yandex.Maps的热爱。 这首诗。 颂 实际上,她在这里habr.com/en/post/479102

在确保程序员中很少有诗歌爱好者之后,我还是决定以一种更加“ HABRovsky”的方式阐明这种情况。 捕获大量代码,想法和屏幕截图。 走吧

图片

让我们重新开始。

任务很简单: 当您带着卡片进入控制器时,您需要立即“缩小”到用户的位置(注意:您还需要以可读的形式获取地址以及所有可用的命令)。

我们裁掉分析师:“分而治之”。

为了实现此目标,有必要解决许多技术和业务问题,即:

0.转到带有潜在模块的控制器,以使用地理定位(MRSG),回调等。

1.工作组
1.1实施工作组
1.2启动IWG
1.2.1获取用户坐标
1.2.2看他
2 *。 以可读格式获取职位地址。

切换到控制器(VIPER + Configurator)

extension AddPresenter: AddPresentationLogic { // ... func openMap(_ delegate: YandexMapSetPointViewControllerProtocol?) { router.routeTo(target: .addPlace(delegate)) } // ... } 

委托只有一个功能,因此当您指定所需的点时,可以通过协议将其返回给使用卡调用控制器的控制器:

 protocol YandexMapSetPointViewControllerProtocol { func didSelectPoint(_ place: Place) } 

给委托,我们发送调用代码的控制部分。 这里的一切似乎都很清楚。

这就是我们去控制器的朴实无华...

图片

中心的十字准线恰好位于控制器的中心和UIView地图的中心。 默认情况下,放大地图内部的假设将在窗口中心起作用。 原来如此。

十字线的左侧和正下方-UILabel。 计划在那里显示一个可读的地址。 带有UIActivityIndi​​cator的右键。 关键是,在用户坐标到达之前,他会“旋转”并且按钮变暗并被禁用。 通过单击带有用户坐标的按钮,我们将十字准线返回给他。 这是从用户的位置开始的位置指示。

底部是“选择点”按钮。 通过单击,发生了业务逻辑的魔力:

 @IBAction func selectButtonWasPressed(_ sender: Any) { let place = Place() place.name = " " place.point.latitude = "\(String(describing: selectedPoint!.latitude))" place.point.longitude = "\(String(describing: selectedPoint!.longitude))" place.addressText = selectedPointGeocoderedAddress delegate?.didSelectPoint(place) navigationController?.popViewController(animated: true) } 

万岁! 我们讨论了准备阶段!

我们进入MRSG。

以下是表格格式的文字,可以个人反映我对最著名的内置地图模块(当时我还不了解www.openstreetmap.org ,谢谢, daglob )的评估 (带有模糊元素)。



“由于任务很简单,所以我使用Yandex.Maps。 他们是美丽,敏捷的……”-我想。

如果您对如何配置它感兴趣,请编写一个小型项目,但是如果您太懒了-tech.yandex.ru/maps/mapkit/?from=mapsapi ,请走上我的路。 入门很容易。

事实是,文档以以下形式显示:



请注意微不足道的描述和左侧的大量对象。 该死的腿。
“测试项目可能会回答我的问题。” 好吧好吧

这是野兽。 github.com/yandex/mapkit-ios-demo
我在那里没有看到我的琐碎任务的解决方案。
-好的-我想-如果我不是开发人员,我有足够的经验。



我组装了一个测试项目,并研究了长时间定制用户标记的功能。

重点:
有一个对象:

 @IBOutlet weak var mapView: YMKMapView! //  YMKUserLocationObjectListener - ,   

您说:“一切似乎都是合乎逻辑的。” 但是没有 替代方法:

  func onObjectAdded(with view: YMKUserLocationView) {} func onObjectRemoved(with view: YMKUserLocationView) {} func onObjectUpdated(with view: YMKUserLocationView, event: YMKObjectEvent) {} 

我们有机会以极其困难的方式到达point.lat和point.long。
例如,像这样:

 userLocation = YMKPoint(latitude: view.pin.geometry.latitude, longitude: view.pin.geometry.longitude) 

加载坐标的等待时间在2到50秒之间变化。

我告诉自己:“你错了,必须有一个专注的LocationManager。” 后来证明-实际上,文档中有这样的“朋友”……但他在哪里有例子?!?
在示例项目中,没有使用这种管理器的示例:



-好吧,文件,只剩下你和我。
-是的,没有问题的“创新者”,享受:



我们向UIViewController订阅了该协议(我希望没有必要在这里进一步解释任何内容,真的,伙计们):

 // MARK: - // Params var userLocation: YMKPoint? { didSet { guard userLocation != nil && userLocation?.latitude != 0 && userLocation?.longitude != 0 else { return } if isItFirstSelection { isItFirstSelection = false selectedPoint = userLocation mapView.mapWindow.map.move( with: YMKCameraPosition.init(target: userLocation!, zoom: 16, azimuth: 0, tilt: 0), animationType: YMKAnimation(type: YMKAnimationType.smooth, duration: 1), cameraCallback: nil) } activityIndicator.stopAnimating() } } // MARK: - // Some like didLoad setupLocationManager() // MARK: - // Setup private func setupLocationManager() { locationManager = YMKMapKit.sharedInstance()!.createLocationManager() locationManager.subscribeForLocationUpdates(withDesiredAccuracy: 0, minTime: 10, minDistance: 0, allowUseInBackground: true, filteringMode: .on, locationListener: self) } // MARK: - // MARK: YMKLocationDelegate extension YandexMapSetPointViewController: YMKLocationDelegate { func onLocationUpdated(with location: YMKLocation) { userLocation = YMKPoint(latitude: location.position.latitude, longitude: location.position.longitude) } func onLocationStatusUpdated(with status: YMKLocationStatus) {} } 

还有...



1-15秒,卡尔! 15! 有时,它可以更快地解决上一个选项! 怎么??
Yandex,什么玩笑? 花这么多时间花所有的时间去尝试并获得这样的结果-好吧,这通常很可悲。

我以为,以为...好吧,不是完全一样。 给一个持卡人的控制器,并使其切换到木凳上超过4秒钟-这对于该应用程序来说是自杀的。 没有人会完全有理由相信这会舒适超过5秒(如果您不相信我,请听Vitaliy Fridman关于UI / UX的报告)。

我想了更多……下面的情感是这样的:


谁想要声音-www.youtube.com/watch?v=pTZaNHZGsQo

成功的秘诀是这样的:
花一公斤... CLLocationManager和YMKLocationManager并...使它们一起工作。



这个联合...“工作”看起来像这样:

 // Params private var locationManager: YMKLocationManager! private var nativeLocationManager = CLLocationManager() // MARK: - // Some like didLoad setupNativeLocationManager() // MARK: - // Setup private func setupNativeLocationManager() { if CLLocationManager.locationServicesEnabled() { nativeLocationManager.delegate = self nativeLocationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters nativeLocationManager.startUpdatingLocation() } } // MARK: - // CLLocationManagerDelegate extension YandexMapSetPointViewController: CLLocationManagerDelegate { func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { userLocation = YMKPoint(latitude: locations.last!.coordinate.latitude, longitude: locations.last!.coordinate.longitude) } } 


...抓饭准备好了

快速获得用户分数的结果是:多于0秒。

在我看来,当解决一个琐碎的问题时,本机和嵌入式部分的对立看起来像这样:



地理编码器*
另外,我将展示地理编码器的实现。
二手的Yandex Geocoder tech.yandex.ru/maps/geocoder

 // Params private let geocoderManager = GeocoderManager.shared //      .     import Foundation import Alamofire import Alamofire_SwiftyJSON import SwiftyJSON import PromiseKit import UIKit // MARK: - // MARK: GeocoderManager class GeocoderManager { static let shared = GeocoderManager() private init() {} func getAddressBy(latitude: String, longitude: String, completion: @escaping (Bool, String?, Error?)->()) { GeocoderAPI().request(latitude: latitude, longitude: longitude).done { (response) in completion(true, response.getAddress(), nil) print("success") }.catch { (error) in completion(false, nil, error) } } } // import Foundation import Alamofire import PromiseKit // MARK: - // MARK: Request enum GeocoderRequest { case addressRequest(String, String) } // MARK: - // MARK: GeocoderRequest extension GeocoderRequest: DefaultRequest { var path: String { switch self { case .addressRequest: return "1.x/" } } var method: HTTPMethod { switch self { case .addressRequest: return .get } } var headers: HTTPHeaders { return [:] } var parameters: [String: Any]? { switch self { case .addressRequest(let latitude, let longitude): return [ "apikey" : Consts.APIKeys.yandexGeocoderKey, "format" : "json", "results" : 1, "spn" : "3.552069,2.400552", "geocode" : "\(longitude),\(latitude)" ] } } func asURLRequest() throws -> URLRequest { let url = try GlobalConsts.Links.geocoderBaseURL.asURL()// not good, need new idea for this var urlRequest = URLRequest(url: url.appendingPathComponent(path)) urlRequest.httpMethod = method.rawValue urlRequest.allHTTPHeaderFields = headers switch method { case .get: urlRequest = try URLEncoding.default.encode(urlRequest, with: parameters) case .post: urlRequest = try JSONEncoding.default.encode(urlRequest, with: parameters) case .put: urlRequest = try JSONEncoding.default.encode(urlRequest, with: parameters) case .patch: urlRequest = try JSONEncoding.default.encode(urlRequest, with: parameters) case .delete: urlRequest = try JSONEncoding.default.encode(urlRequest, with: parameters) default: break } return urlRequest } } 

此资源对将服务器的响应转换为模型有很大帮助: app.quicktype.io

视觉上的工作结果如下:



总结以上内容:
同事们,写这篇文章是为了使您在解决此类问题时所花的时间不会比我花费的时间多,而是选择一条不同的路径或快速走这条路。

我希望看到建设性的批评和/或其他正确的解决方案。

如果发现这篇文章对您有用,请用Lois评分纠正我,最好以新的方式查看此故事原始版本

所有创造性的成功和积极的心情!

Source: https://habr.com/ru/post/zh-CN479432/


All Articles