在 iOS 上通过 Mapbox 中的按钮在当前位置添加制造商
Add Maker at current location via Button in Mapbox on iOS
我正在尝试构建一个应用程序,我可以通过按一个按钮向地图添加标记。我已经可以通过按下按钮将当前位置和默认标题写入类型为 MGLPointAnnotation 的数组中。但我对新注释的 可视化 感到困惑。我总是收到错误
Type of expression is ambiguous without more context
到目前为止,这是我的代码:
func makeEntry(){
guard let locValue: CLLocationCoordinate2D = locationManager.location?.coordinate else { return }
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
let point = Annotation()
point.coordinate = CLLocationCoordinate2D(latitude: (locValue.latitude), longitude: (locValue.longitude))
point.title = "Entry"
pointAnnotations.append(point)
mapView.addAnnotations(pointAnnotations) <-- triggers the error waring
}
我是 Swift 的新手,希望您能帮助我。
编辑:
以下是该应用程序的其余核心功能:
func addButton(){
entryButton = UIButton(frame: CGRect(x: (view.frame.width/2)-100 , y: (view.frame.height)-75, width: 200, height: 50))
entryButton.setTitle("Neuer Eintrag", for: .normal)
entryButton.setTitleColor(UIColor(red: 100/255, green: 180/255, blue: 40/255, alpha: 1), for: .normal)
entryButton.backgroundColor=(UIColor(red: 255/255, green: 255/255, blue: 255/255, alpha: 1))
entryButton.layer.cornerRadius = 20
entryButton.addTarget(self, action: #selector(entryButtonWasPressed(_sender:)), for: .touchUpInside)
view.addSubview(entryButton)
}
@objc func entryButtonWasPressed(_sender: UIButton){
makeEntry()
print(pointAnnotations)
}
编辑编辑:这是完整的代码:
import UIKit
import Mapbox
class ViewController: UIViewController, MGLMapViewDelegate {
let point = MGLPointAnnotation()
var entryButton: UIButton!
let locationManager = CLLocationManager()
var annotation = MGLPointAnnotation()
var pointAnnotations = [MGLPointAnnotation]()
override func viewDidLoad() {
super.viewDidLoad()
let mapView = MGLMapView(frame: view.bounds)
mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
mapView.delegate = self
// Enable heading tracking mode so that the arrow will appear.
mapView.userTrackingMode = .followWithHeading
// Enable the permanent heading indicator, which will appear when the tracking mode is not `.followWithHeading`.
mapView.showsUserHeadingIndicator = true
view.addSubview(mapView)
// Set the map view's delegate
mapView.delegate = self
// Allow the map view to display the user's location
mapView.showsUserLocation = true
addButton()
}
func addButton(){
entryButton = UIButton(frame: CGRect(x: (view.frame.width/2)-100 , y: (view.frame.height)-75, width: 200, height: 50))
entryButton.setTitle("New Entry", for: .normal)
entryButton.setTitleColor(UIColor(red: 100/255, green: 180/255, blue: 40/255, alpha: 1), for: .normal)
entryButton.backgroundColor=(UIColor(red: 255/255, green: 255/255, blue: 255/255, alpha: 1))
entryButton.layer.cornerRadius = 20
entryButton.addTarget(self, action: #selector(entryButtonWasPressed(_sender:)), for: .touchUpInside)
view.addSubview(entryButton)
}
@objc func entryButtonWasPressed(_sender: UIButton){
makeEntry()
print(pointAnnotations)
}
func makeEntry(){
guard let locValue: CLLocationCoordinate2D = locationManager.location?.coordinate else { return }
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
let point = MGLPointAnnotation()
point.coordinate = CLLocationCoordinate2D(latitude: (locValue.latitude), longitude: (locValue.longitude))
point.title = "Entry"
pointAnnotations.append(point)
// mapView.addAnnotations(pointAnnotations)
}
func mapView(_ mapView: MGLMapView, annotationCanShowCallout annotation: MGLAnnotation) -> Bool {
// Always allow callouts to popup when annotations are tapped.
return true
}
func mapView(_ mapView: MGLMapView, didSelect annotation: MGLAnnotation) {
let camera = MGLMapCamera(lookingAtCenter: annotation.coordinate, fromDistance: 4500, pitch: 15, heading: 0)
mapView.fly(to: camera, withDuration: 2,
peakAltitude: 3000, completionHandler: nil)
}
}
func mapView(_ mapView: MGLMapView, viewFor annotation: MGLAnnotation) -> MGLAnnotationView? {
// Substitute our custom view for the user location annotation. This custom view is defined below.
if annotation is MGLUserLocation && mapView.userLocation != nil {
return CustomUserLocationAnnotationView()
}
return nil
}
// Optional: tap the user location annotation to toggle heading tracking mode.
func mapView(_ mapView: MGLMapView, didSelect annotation: MGLAnnotation) {
if mapView.userTrackingMode != .followWithHeading {
mapView.userTrackingMode = .followWithHeading
} else {
mapView.resetNorth()
}
// We're borrowing this method as a gesture recognizer, so reset selection state.
mapView.deselectAnnotation(annotation, animated: false)
}
// Create a subclass of MGLUserLocationAnnotationView.
class CustomUserLocationAnnotationView: MGLUserLocationAnnotationView {
let size: CGFloat = 48
var dot: CALayer!
var arrow: CAShapeLayer!
// -update is a method inherited from MGLUserLocationAnnotationView. It updates the appearance of the user location annotation when needed. This can be called many times a second, so be careful to keep it lightweight.
override func update() {
if frame.isNull {
frame = CGRect(x: 0, y: 0, width: size, height: size)
return setNeedsLayout()
}
// Check whether we have the user’s location yet.
if CLLocationCoordinate2DIsValid(userLocation!.coordinate) {
setupLayers()
updateHeading()
}
}
private func updateHeading() {
// Show the heading arrow, if the heading of the user is available.
if let heading = userLocation!.heading?.trueHeading {
arrow.isHidden = false
// Get the difference between the map’s current direction and the user’s heading, then convert it from degrees to radians.
let rotation: CGFloat = -MGLRadiansFromDegrees(mapView!.direction - heading)
// If the difference would be perceptible, rotate the arrow.
if abs(rotation) > 0.01 {
// Disable implicit animations of this rotation, which reduces lag between changes.
CATransaction.begin()
CATransaction.setDisableActions(true)
arrow.setAffineTransform(CGAffineTransform.identity.rotated(by: rotation))
CATransaction.commit()
}
} else {
arrow.isHidden = true
}
}
private func setupLayers() {
// This dot forms the base of the annotation.
if dot == nil {
dot = CALayer()
dot.bounds = CGRect(x: 0, y: 0, width: size, height: size)
// Use CALayer’s corner radius to turn this layer into a circle.
dot.cornerRadius = size / 2
dot.backgroundColor = super.tintColor.cgColor
dot.borderWidth = 4
dot.borderColor = UIColor.white.cgColor
layer.addSublayer(dot)
}
// This arrow overlays the dot and is rotated with the user’s heading.
if arrow == nil {
arrow = CAShapeLayer()
arrow.path = arrowPath()
arrow.frame = CGRect(x: 0, y: 0, width: size / 2, height: size / 2)
arrow.position = CGPoint(x: dot.frame.midX, y: dot.frame.midY)
arrow.fillColor = dot.borderColor
layer.addSublayer(arrow)
}
}
// Calculate the vector path for an arrow, for use in a shape layer.
private func arrowPath() -> CGPath {
let max: CGFloat = size / 2
let pad: CGFloat = 3
let top = CGPoint(x: max * 0.5, y: 0)
let left = CGPoint(x: 0 + pad, y: max - pad)
let right = CGPoint(x: max - pad, y: max - pad)
let center = CGPoint(x: max * 0.5, y: max * 0.6)
let bezierPath = UIBezierPath()
bezierPath.move(to: top)
bezierPath.addLine(to: left)
bezierPath.addLine(to: center)
bezierPath.addLine(to: right)
bezierPath.addLine(to: top)
bezierPath.close()
return bezierPath.cgPath
}
}
编辑 ***************************************编辑
我 copy/pasted 将您的整个代码放入一个新的 Mapbox 项目中,并 运行 它在模拟器上。它在我的模拟位置编译并显示了通常的(小)蓝点。按下按钮没有任何反应 - 没有新注释,也没有错误消息。
查看您的代码,您可以看到 ViewController
class 之外有两个方法。他们只是漂浮在无人区。其中之一是委托方法:
func mapView(_ mapView: MGLMapView, viewFor annotation: MGLAnnotation) -> MGLAnnotationView?
如果您将此方法移回到 ViewController
class 中,它将在需要时调用,并为您想要的用户位置提供自定义外观,即。大蓝点。
class 之外的另一种方法是:
func mapView(_ mapView: MGLMapView, didSelect annotation: MGLAnnotation)
但是,您在 class 中已经有此方法的另一个版本,因此您可能希望将两者的功能合并到 中的 class 然后摆脱外部的。
您遇到 'ambiguous' 错误消息的原因是您在 ViewDidLoad
中声明了 mapView
,因此它在 [=39= 中的任何其他方法中不可用].相反,在方法外部声明 mapView
以及其他 class 属性,然后像这样在 ViewDidLoad
内部正常使用它:
var annotation = MGLPointAnnotation()
var pointAnnotations = [MGLPointAnnotation]()
var mapView: MGLMapView! // Declared here
override func viewDidLoad() {
super.viewDidLoad()
mapView = MGLMapView(frame: view.bounds) // Instantiated here. (No `let`)
mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
mapView.delegate = self
现在您的按钮将在用户位置放置标准注释。你可以在你的大蓝点后面看到它。如果有任何不清楚的地方,请告诉我。
我正在尝试构建一个应用程序,我可以通过按一个按钮向地图添加标记。我已经可以通过按下按钮将当前位置和默认标题写入类型为 MGLPointAnnotation 的数组中。但我对新注释的 可视化 感到困惑。我总是收到错误
Type of expression is ambiguous without more context
到目前为止,这是我的代码:
func makeEntry(){
guard let locValue: CLLocationCoordinate2D = locationManager.location?.coordinate else { return }
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
let point = Annotation()
point.coordinate = CLLocationCoordinate2D(latitude: (locValue.latitude), longitude: (locValue.longitude))
point.title = "Entry"
pointAnnotations.append(point)
mapView.addAnnotations(pointAnnotations) <-- triggers the error waring
}
我是 Swift 的新手,希望您能帮助我。
编辑:
以下是该应用程序的其余核心功能:
func addButton(){
entryButton = UIButton(frame: CGRect(x: (view.frame.width/2)-100 , y: (view.frame.height)-75, width: 200, height: 50))
entryButton.setTitle("Neuer Eintrag", for: .normal)
entryButton.setTitleColor(UIColor(red: 100/255, green: 180/255, blue: 40/255, alpha: 1), for: .normal)
entryButton.backgroundColor=(UIColor(red: 255/255, green: 255/255, blue: 255/255, alpha: 1))
entryButton.layer.cornerRadius = 20
entryButton.addTarget(self, action: #selector(entryButtonWasPressed(_sender:)), for: .touchUpInside)
view.addSubview(entryButton)
}
@objc func entryButtonWasPressed(_sender: UIButton){
makeEntry()
print(pointAnnotations)
}
编辑编辑:这是完整的代码:
import UIKit
import Mapbox
class ViewController: UIViewController, MGLMapViewDelegate {
let point = MGLPointAnnotation()
var entryButton: UIButton!
let locationManager = CLLocationManager()
var annotation = MGLPointAnnotation()
var pointAnnotations = [MGLPointAnnotation]()
override func viewDidLoad() {
super.viewDidLoad()
let mapView = MGLMapView(frame: view.bounds)
mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
mapView.delegate = self
// Enable heading tracking mode so that the arrow will appear.
mapView.userTrackingMode = .followWithHeading
// Enable the permanent heading indicator, which will appear when the tracking mode is not `.followWithHeading`.
mapView.showsUserHeadingIndicator = true
view.addSubview(mapView)
// Set the map view's delegate
mapView.delegate = self
// Allow the map view to display the user's location
mapView.showsUserLocation = true
addButton()
}
func addButton(){
entryButton = UIButton(frame: CGRect(x: (view.frame.width/2)-100 , y: (view.frame.height)-75, width: 200, height: 50))
entryButton.setTitle("New Entry", for: .normal)
entryButton.setTitleColor(UIColor(red: 100/255, green: 180/255, blue: 40/255, alpha: 1), for: .normal)
entryButton.backgroundColor=(UIColor(red: 255/255, green: 255/255, blue: 255/255, alpha: 1))
entryButton.layer.cornerRadius = 20
entryButton.addTarget(self, action: #selector(entryButtonWasPressed(_sender:)), for: .touchUpInside)
view.addSubview(entryButton)
}
@objc func entryButtonWasPressed(_sender: UIButton){
makeEntry()
print(pointAnnotations)
}
func makeEntry(){
guard let locValue: CLLocationCoordinate2D = locationManager.location?.coordinate else { return }
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
let point = MGLPointAnnotation()
point.coordinate = CLLocationCoordinate2D(latitude: (locValue.latitude), longitude: (locValue.longitude))
point.title = "Entry"
pointAnnotations.append(point)
// mapView.addAnnotations(pointAnnotations)
}
func mapView(_ mapView: MGLMapView, annotationCanShowCallout annotation: MGLAnnotation) -> Bool {
// Always allow callouts to popup when annotations are tapped.
return true
}
func mapView(_ mapView: MGLMapView, didSelect annotation: MGLAnnotation) {
let camera = MGLMapCamera(lookingAtCenter: annotation.coordinate, fromDistance: 4500, pitch: 15, heading: 0)
mapView.fly(to: camera, withDuration: 2,
peakAltitude: 3000, completionHandler: nil)
}
}
func mapView(_ mapView: MGLMapView, viewFor annotation: MGLAnnotation) -> MGLAnnotationView? {
// Substitute our custom view for the user location annotation. This custom view is defined below.
if annotation is MGLUserLocation && mapView.userLocation != nil {
return CustomUserLocationAnnotationView()
}
return nil
}
// Optional: tap the user location annotation to toggle heading tracking mode.
func mapView(_ mapView: MGLMapView, didSelect annotation: MGLAnnotation) {
if mapView.userTrackingMode != .followWithHeading {
mapView.userTrackingMode = .followWithHeading
} else {
mapView.resetNorth()
}
// We're borrowing this method as a gesture recognizer, so reset selection state.
mapView.deselectAnnotation(annotation, animated: false)
}
// Create a subclass of MGLUserLocationAnnotationView.
class CustomUserLocationAnnotationView: MGLUserLocationAnnotationView {
let size: CGFloat = 48
var dot: CALayer!
var arrow: CAShapeLayer!
// -update is a method inherited from MGLUserLocationAnnotationView. It updates the appearance of the user location annotation when needed. This can be called many times a second, so be careful to keep it lightweight.
override func update() {
if frame.isNull {
frame = CGRect(x: 0, y: 0, width: size, height: size)
return setNeedsLayout()
}
// Check whether we have the user’s location yet.
if CLLocationCoordinate2DIsValid(userLocation!.coordinate) {
setupLayers()
updateHeading()
}
}
private func updateHeading() {
// Show the heading arrow, if the heading of the user is available.
if let heading = userLocation!.heading?.trueHeading {
arrow.isHidden = false
// Get the difference between the map’s current direction and the user’s heading, then convert it from degrees to radians.
let rotation: CGFloat = -MGLRadiansFromDegrees(mapView!.direction - heading)
// If the difference would be perceptible, rotate the arrow.
if abs(rotation) > 0.01 {
// Disable implicit animations of this rotation, which reduces lag between changes.
CATransaction.begin()
CATransaction.setDisableActions(true)
arrow.setAffineTransform(CGAffineTransform.identity.rotated(by: rotation))
CATransaction.commit()
}
} else {
arrow.isHidden = true
}
}
private func setupLayers() {
// This dot forms the base of the annotation.
if dot == nil {
dot = CALayer()
dot.bounds = CGRect(x: 0, y: 0, width: size, height: size)
// Use CALayer’s corner radius to turn this layer into a circle.
dot.cornerRadius = size / 2
dot.backgroundColor = super.tintColor.cgColor
dot.borderWidth = 4
dot.borderColor = UIColor.white.cgColor
layer.addSublayer(dot)
}
// This arrow overlays the dot and is rotated with the user’s heading.
if arrow == nil {
arrow = CAShapeLayer()
arrow.path = arrowPath()
arrow.frame = CGRect(x: 0, y: 0, width: size / 2, height: size / 2)
arrow.position = CGPoint(x: dot.frame.midX, y: dot.frame.midY)
arrow.fillColor = dot.borderColor
layer.addSublayer(arrow)
}
}
// Calculate the vector path for an arrow, for use in a shape layer.
private func arrowPath() -> CGPath {
let max: CGFloat = size / 2
let pad: CGFloat = 3
let top = CGPoint(x: max * 0.5, y: 0)
let left = CGPoint(x: 0 + pad, y: max - pad)
let right = CGPoint(x: max - pad, y: max - pad)
let center = CGPoint(x: max * 0.5, y: max * 0.6)
let bezierPath = UIBezierPath()
bezierPath.move(to: top)
bezierPath.addLine(to: left)
bezierPath.addLine(to: center)
bezierPath.addLine(to: right)
bezierPath.addLine(to: top)
bezierPath.close()
return bezierPath.cgPath
}
}
编辑 ***************************************编辑
我 copy/pasted 将您的整个代码放入一个新的 Mapbox 项目中,并 运行 它在模拟器上。它在我的模拟位置编译并显示了通常的(小)蓝点。按下按钮没有任何反应 - 没有新注释,也没有错误消息。
查看您的代码,您可以看到 ViewController
class 之外有两个方法。他们只是漂浮在无人区。其中之一是委托方法:
func mapView(_ mapView: MGLMapView, viewFor annotation: MGLAnnotation) -> MGLAnnotationView?
如果您将此方法移回到 ViewController
class 中,它将在需要时调用,并为您想要的用户位置提供自定义外观,即。大蓝点。
class 之外的另一种方法是:
func mapView(_ mapView: MGLMapView, didSelect annotation: MGLAnnotation)
但是,您在 class 中已经有此方法的另一个版本,因此您可能希望将两者的功能合并到 中的 class 然后摆脱外部的。
您遇到 'ambiguous' 错误消息的原因是您在 ViewDidLoad
中声明了 mapView
,因此它在 [=39= 中的任何其他方法中不可用].相反,在方法外部声明 mapView
以及其他 class 属性,然后像这样在 ViewDidLoad
内部正常使用它:
var annotation = MGLPointAnnotation()
var pointAnnotations = [MGLPointAnnotation]()
var mapView: MGLMapView! // Declared here
override func viewDidLoad() {
super.viewDidLoad()
mapView = MGLMapView(frame: view.bounds) // Instantiated here. (No `let`)
mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
mapView.delegate = self
现在您的按钮将在用户位置放置标准注释。你可以在你的大蓝点后面看到它。如果有任何不清楚的地方,请告诉我。