请帮帮我。
第一次参与项目,涉及iBeacon,在商店内部创建虚拟地图。
我知道如何使用MapKit删除引脚,但是如果我在View上只有CGPoints,我怎么能这样做呢? 我设法如何在视图上滴下UIImage(带图像)。但是当我旋转或捏时,它不会停留在我丢弃的那个坐标上。 这是一个代码:
import UIKit
class MapViewController: UIViewController{
private var scaleView: CGFloat = 1
private var rotateView: CGFloat = 0
private var anchorPoint = CGPoint(x: 0.5, y: 0.5)
private let gestureRecognizerDelegate = GestureRecognizerDelegate()
@IBOutlet weak var mapView: MapView!
@IBOutlet var pinchGestureRecognizer: UIPinchGestureRecognizer!
@IBOutlet var panGestureRecognizer: UIPanGestureRecognizer!
@IBOutlet var rotateGestureRecognizer: UIRotationGestureRecognizer!
@IBOutlet weak var pin: UIImageView!
override func viewDidAppear(_ animated: Bool) {
if !cartIsEmpty {
cartBtn.setImage(UIImage(named: "haveitem"), for: .normal)
} else {
cartBtn.setImage(UIImage(named: "2772"), for: .normal)
}
cartBtn.addTarget(self, action: #selector(openCart), for: .touchUpInside)
let item1 = UIBarButtonItem(customView: cartBtn)
self.navigationItem.rightBarButtonItem = item1
}
override func viewDidDisappear(_ animated: Bool) {
cartBtn.removeTarget(self, action: #selector(openCart), for: .touchUpInside)
}
override func viewDidLoad() {
super.viewDidLoad()
ApplicationManager.sharedInstance.onApplicationStart()
NotificationCenter.default.addObserver(self, selector: #selector(self.onOrientationChanged), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
self.panGestureRecognizer.delegate = gestureRecognizerDelegate
self.pinchGestureRecognizer.delegate = gestureRecognizerDelegate
self.rotateGestureRecognizer.delegate = gestureRecognizerDelegate
ApplicationManager.sharedInstance.gotFloorData = drawFloor
ApplicationManager.sharedInstance.currentUserPoint = drawCurrentUserPoint
}
func drawFloor (floor: Floor) {
mapView.setFloor(currentFloor: floor)
mapView.setNeedsDisplay()
}
func drawCurrentUserPoint(currentUserPoint: CurrentUserLocation, beaconRangingData: [BeaconRangingPoint]) {
mapView.setUserPoint(currentUserPoint: currentUserPoint, beaconRangingData: beaconRangingData)
mapView.setNeedsDisplay()
}
@IBAction func handlePan(recognizer:UIPanGestureRecognizer) {
let translation = recognizer.translation(in: mapView)
if recognizer.view != nil {
let offsetX = translation.x * CGFloat(cosf(Float(rotateView))) - translation.y * CGFloat(sinf(Float(rotateView)))
let offsetY = translation.x * CGFloat(sinf(Float(rotateView))) + translation.y * CGFloat(cosf(Float(rotateView)))
mapView.center = CGPoint(x:mapView.center.x + offsetX * scaleView,
y:mapView.center.y + offsetY * scaleView)
}
recognizer.setTranslation(CGPoint(x: 0, y: 0), in: mapView)
}
@IBAction func handlePinch(recognizer : UIPinchGestureRecognizer) {
if recognizer.view != nil {
setAnchor(point: recognizer.location(in: mapView))
mapView.transform = mapView.transform.scaledBy(x: recognizer.scale, y: recognizer.scale)
scaleView = recognizer.scale * scaleView
recognizer.scale = 1
}
}
@IBAction func handleRotate(recognizer : UIRotationGestureRecognizer) {
if recognizer.view != nil {
setAnchor(point: recognizer.location(in: mapView))
mapView.transform = mapView.transform.rotated(by: recognizer.rotation)
rotateView = rotateView + recognizer.rotation
recognizer.rotation = 0
}
}
private func setAnchor(point : CGPoint) {
let anchor = CGPoint(x: point.x / mapView.bounds.width, y: point.y / mapView.bounds.height)
mapView.layer.anchorPoint = CGPoint(x: anchor.x, y: anchor.y)
let translationX = (mapView.bounds.width * (anchor.x - anchorPoint.x)) * scaleView
let translationY = (mapView.bounds.height * (anchor.y - anchorPoint.y)) * scaleView
let offsetX = translationX * CGFloat(cosf(Float(rotateView))) - translationY * CGFloat(sinf(Float(rotateView)))
let offsetY = translationX * CGFloat(sinf(Float(rotateView))) + translationY * CGFloat(cosf(Float(rotateView)))
mapView.layer.position = CGPoint(x: mapView.layer.position.x + offsetX,
y: mapView.layer.position.y + offsetY)
anchorPoint = anchor
}
private func showAlert(title: String, message: String?, style: UIAlertControllerStyle = .alert) {
let alertController = UIAlertController(title: title, message: message, preferredStyle: style)
let tryAgainAction = UIAlertAction(title: "Try again", style: .default) {
alertAction in
ApplicationManager.sharedInstance.onApplicationStart()
}
let cancelAction = UIAlertAction(title: "Cancel", style: .default, handler: nil)
alertController.addAction(tryAgainAction)
alertController.addAction(cancelAction)
present(alertController, animated: true, completion: nil)
}
func onOrientationChanged() {
self.mapView.setNeedsDisplay()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
也是mapView的代码:
import UIKit
类MapView:UIView {
private var floor = Floor(walls: [], doors: [], beacons: [])
private let wallColor = UIColor.black
private let doorColor = UIColor.red
private let triangleColor = UIColor.red
private let perpendicularColor = UIColor.darkGray
private let doorLength = 3.0
private let beaconColor = UIColor.green
private let beaconNoActiveColor = UIColor(red: 20/255.0, green: 154.0/255.0, blue: 53.0/255.0, alpha: 1.0)
private let beaconFrameColor = UIColor.brown
private let lineWidthBeaconFrame:CGFloat = 0.25
private let beaconRadius: CGFloat = 5.0
private let userColor = UIColor.blue
private let userFrameColor = UIColor.brown
private let lineWidthUserFrame:CGFloat = 0.25
private let userRadius: CGFloat = 5.0
private let distanceBeaconColor = UIColor.clear
private let distanceBeaconFrameColor = UIColor.green
private let lineWidthOfDistanceFrame: CGFloat = 0.5
private let userRawRadius: CGFloat = 3.0
private let userRawColor = UIColor.darkGray
private let userRawFrameColor = UIColor.lightGray
private let lineWidthOfuserRawFrame: CGFloat = 0.8
private var beaconText: NSString = ""
private let textColor: UIColor = UIColor.red
private let textFont: UIFont = UIFont(name: "Helvetica Neue", size: 5)!
private var currentUserLocation = CurrentUserLocation()
private var beaconRangingData: [BeaconRangingPoint] = []
func setFloor (currentFloor: Floor) {
floor = currentFloor
}
func setUserPoint(currentUserPoint: CurrentUserLocation, beaconRangingData: [BeaconRangingPoint]) {
self.currentUserLocation = currentUserPoint
self.beaconRangingData = beaconRangingData
}
func dropPin(location: CGPoint) {
}
override func draw(_ rect: CGRect) {
let frameToDraw = CoordinatesConverter(boundsWidth: bounds.width, boundsHeight: bounds.height, paddingX: 5, paddingY: 5)
let mapWithScaleCoordinaates = frameToDraw.getSuitableCoordinates(floor: floor, currentUserLocation: currentUserLocation, beaconRangingData: beaconRangingData)
let lines = mapWithScaleCoordinaates.lines
let circles = mapWithScaleCoordinaates.circles
drawLines(lines: lines)
drawCircles(circles: circles)
}
private func drawLines(lines :[Line]) {
let wallPath = UIBezierPath()
let doorPath = UIBezierPath()
let trianglePath = UIBezierPath()
let perpendicularPath = UIBezierPath()
for line in lines {
if line.type == .wall {
wallPath.move(to: CGPoint(x: line.x1, y: line.y1))
wallPath.addLine(to: CGPoint(x: line.x2, y: line.y2))
wallColor.setStroke()
wallPath.stroke()
}
if line.type == .door {
doorPath.move(to: CGPoint(x: line.x1, y: line.y1))
doorPath.addLine(to: CGPoint(x: line.x2, y: line.y2))
doorPath.lineWidth = CGFloat(doorLength)
doorColor.setStroke()
doorPath.stroke()
}
if line.type == .triangle {
trianglePath.move(to: CGPoint(x: line.x1, y: line.y1))
trianglePath.addLine(to: CGPoint(x: line.x2, y: line.y2))
triangleColor.setStroke()
trianglePath.stroke()
}
if line.type == .perpendicular {
perpendicularPath.move(to: CGPoint(x: line.x1, y: line.y1))
perpendicularPath.addLine(to: CGPoint(x: line.x2, y: line.y2))
perpendicularColor.setStroke()
perpendicularPath.stroke()
}
}
}
private func drawCircles(circles: [Circle]) {
let layerViews = layer.sublayers
if layerViews != nil {
for view in layerViews! {
if type(of: view) === CAShapeLayer.self {
view.removeFromSuperlayer()
}
}
}
for circle in circles {
if type(of: circle) === BeaconCircle.self {
if (circle as! BeaconCircle).correctedDistance == 0 {
infoToDrawCircle(circle: circle, radius: beaconRadius, color: beaconNoActiveColor.cgColor, frameColor: beaconFrameColor.cgColor, frameWidth: lineWidthBeaconFrame)
drawBeaconText(circle: circle as! BeaconCircle)
} else {
infoToDrawCircle(circle: circle, radius: beaconRadius, color: beaconColor.cgColor, frameColor: beaconFrameColor.cgColor, frameWidth: lineWidthBeaconFrame)
drawBeaconText(circle: circle as! BeaconCircle)
}
if type(of: circle) === BeaconCircle.self && (circle as! BeaconCircle).correctedDistance != 0 {
infoToDrawCircle(circle: circle, radius: CGFloat((circle as! BeaconCircle).correctedDistance), color: distanceBeaconColor.cgColor, frameColor: distanceBeaconFrameColor.cgColor, frameWidth: lineWidthOfDistanceFrame)
// infoToDrawCircle(circle: circle, radius: CGFloat((circle as! BeaconCircle).notCorrectedDistance), color: UIColor.gray.cgColor, frameColor: distanceBeaconFrameColor.cgColor, frameWidth: lineWidthOfDistanceFrame)
}
} else if type(of: circle) === UserCircle.self {
infoToDrawCircle(circle: circle, radius: userRadius, color: userColor.cgColor, frameColor: userFrameColor.cgColor, frameWidth: lineWidthUserFrame)
} else if type (of: circle) === UserRawCircle.self {
infoToDrawCircle(circle: circle, radius: userRawRadius, color: userRawColor.cgColor, frameColor: userRawFrameColor.cgColor, frameWidth: lineWidthOfuserRawFrame)
} else {
Logger.logMessage(message: "incorrect circle type", level: .error)
break
}
}
}
private func drawBeaconText (circle: BeaconCircle) {
let attributes: NSDictionary = [
NSForegroundColorAttributeName: textColor,
NSFontAttributeName: textFont
]
let minor = circle.minor
let correctDistance = Int(round(100 * circle.correctDistanceForText) / 100)
let notCorrectDistance = Int(round(100 * circle.notCorrectDistanceForText) / 100)
beaconText = "m: \(minor), cd: \(correctDistance), nd: \(notCorrectDistance)" as NSString
if circle.x > Int((bounds.width - 50)) {
beaconText.draw(at: CGPoint(x: circle.x - 70, y: circle.y + 5), withAttributes: attributes as? [String : Any])
} else if circle.x < 20 {
beaconText.draw(at: CGPoint(x: circle.x + 5, y: circle.y + 5), withAttributes: attributes as? [String : Any])
} else {
beaconText.draw(at: CGPoint(x: circle.x + 6, y: circle.y + 5), withAttributes: attributes as? [String : Any])
}
}
private func infoToDrawCircle (circle: Circle, radius: CGFloat, color: CGColor, frameColor: CGColor, frameWidth: CGFloat) {
let center = CGPoint(x: circle.x, y: circle.y)
let path = UIBezierPath(arcCenter: center, radius: radius, startAngle: 0, endAngle: 360, clockwise: true)
let shapeLayer = CAShapeLayer()
shapeLayer.path = path.cgPath
shapeLayer.fillColor = color
shapeLayer.lineWidth = frameWidth
shapeLayer.strokeColor = frameColor
layer.addSublayer(shapeLayer)
}
}
答案 0 :(得分:0)
我建议您将MapViewController
与MKMapViewDelegate
相符。通过这种方式,您可以向地图添加注释(也是动画),您不必再担心它们,因为它们都由地图委托处理。
您可以使用:
self.map.showAnnotations(pins, animated: true)
其中pins
是MKAnnotation
的数组。 Here is the link到方法的文档。
干杯