MapAnnotationView.swift 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. //
  2. // MapAnnotationView.swift
  3. // Runner
  4. //
  5. // Created by Groot on 2025/5/9.
  6. //
  7. import UIKit
  8. import MapKit
  9. class MapAnnotationView: MKAnnotationView {
  10. static let identifier: String = "MapAnnotationView"
  11. var marker: ATMapMarker? {
  12. didSet {
  13. updateView()
  14. }
  15. }
  16. var markerImageView: MapAnnotationMarkerImageView?
  17. var textView: MapAnnotationMarkerTextView?
  18. // spacing between text and image
  19. let spacing: CGFloat = 6
  20. var annotationSelected: Bool {
  21. return (marker?.isSelected ?? false) || self.isSelected
  22. }
  23. override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
  24. super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
  25. self.marker = annotation as? ATMapMarker
  26. self.isEnabled = marker?.markerType.supportSelected ?? false
  27. self.isHidden = false
  28. }
  29. required init?(coder aDecoder: NSCoder) {
  30. fatalError("init(coder:) has not been implemented")
  31. }
  32. // MARK: - 视图更新与重用
  33. override func prepareForReuse() {
  34. super.prepareForReuse()
  35. // 清除当前所有子视图
  36. for subview in subviews {
  37. subview.removeFromSuperview()
  38. }
  39. markerImageView = nil
  40. textView = nil
  41. }
  42. private func updateView() {
  43. // 确保在更新视图前移除所有子视图
  44. for subview in subviews {
  45. subview.removeFromSuperview()
  46. }
  47. guard let marker = marker else { return }
  48. // 创建并添加图像视图
  49. markerImageView = MapAnnotationMarkerImageView(markerType: marker.markerType)
  50. if let markerImageView = markerImageView {
  51. markerImageView.isSelected = annotationSelected
  52. addSubview(markerImageView)
  53. }
  54. // 如果有标题,添加文本视图
  55. if let markerName = marker.markerName, !markerName.isEmpty {
  56. textView = MapAnnotationMarkerTextView(text: markerName)
  57. if let textView = textView {
  58. addSubview(textView)
  59. }
  60. }
  61. // 设置AutoLayout
  62. setupConstraints()
  63. }
  64. // MARK: - 布局
  65. private func setupConstraints() {
  66. // 禁用自动约束转换
  67. translatesAutoresizingMaskIntoConstraints = false
  68. guard let markerImageView = markerImageView else { return }
  69. markerImageView.translatesAutoresizingMaskIntoConstraints = false
  70. let markerSize = marker?.markerType.size ?? CGSize(width: 30, height: 30)
  71. // 设置图像视图约束 - 居中显示在标记视图中
  72. NSLayoutConstraint.activate([
  73. markerImageView.centerXAnchor.constraint(equalTo: centerXAnchor),
  74. markerImageView.centerYAnchor.constraint(equalTo: centerYAnchor),
  75. markerImageView.widthAnchor.constraint(equalToConstant: markerSize.width),
  76. markerImageView.heightAnchor.constraint(equalToConstant: markerSize.height)
  77. ])
  78. // 设置文本视图约束 - 位于图像上方,居中对齐
  79. if let textView = textView {
  80. textView.translatesAutoresizingMaskIntoConstraints = false
  81. NSLayoutConstraint.activate([
  82. textView.centerXAnchor.constraint(equalTo: centerXAnchor),
  83. textView.bottomAnchor.constraint(equalTo: markerImageView.topAnchor, constant: -spacing)
  84. ])
  85. }
  86. // 设置标记视图整体尺寸
  87. let textHeight = textView?.intrinsicContentSize.height ?? 0
  88. let totalHeight = textView != nil ?
  89. markerSize.height + textHeight + spacing :
  90. markerSize.height
  91. // 宽度至少和markerImageView一样宽,高度根据是否有文本决定
  92. NSLayoutConstraint.activate([
  93. widthAnchor.constraint(greaterThanOrEqualTo: markerImageView.widthAnchor),
  94. heightAnchor.constraint(equalToConstant: totalHeight)
  95. ])
  96. // 更新偏移量
  97. updateCenterOffset()
  98. }
  99. // MARK: - 更新视图
  100. override func layoutSubviews() {
  101. super.layoutSubviews()
  102. updateCenterOffset()
  103. }
  104. private func updateCenterOffset() {
  105. let markerSize = marker?.markerType.size ?? CGSize(width: 30, height: 30)
  106. if let textView = textView {
  107. let textHeight = textView.frame.height
  108. let totalHeight = markerSize.height + textHeight + spacing
  109. // 有文本时,调整偏移让图片底部对准坐标点
  110. centerOffset = CGPoint(x: 0, y: -(totalHeight - markerSize.height)/2)
  111. } else {
  112. // 没有文本时,仅需要将图片底部对准坐标点
  113. centerOffset = CGPoint(x: 0, y: -markerSize.height/2)
  114. }
  115. }
  116. override func prepareForDisplay() {
  117. super.prepareForDisplay()
  118. // 确保视图已经设置好
  119. if markerImageView == nil {
  120. updateView()
  121. }
  122. // 更新选中状态
  123. markerImageView?.isSelected = annotationSelected
  124. }
  125. override func setSelected(_ selected: Bool, animated: Bool) {
  126. super.setSelected(selected, animated: animated)
  127. marker?.isSelected = selected
  128. markerImageView?.isSelected = annotationSelected
  129. }
  130. }