Browse Source

add annotation textView

Groot 6 tháng trước cách đây
mục cha
commit
df793667b6

+ 0 - 77
plugins/map_mapkit_ios/example/ios/.symlinks/plugins/map_mapkit_ios/ios/Classes/MapView/Model/MarkerType.swift

@@ -1,77 +0,0 @@
-//
-//  MarkerType.swift
-//  Pods
-//
-//  Created by Groot on 2025/5/14.
-//
-
-import Foundation
-
-protocol MapMarkerSupportType: Codable {
-    var rawValue: Int { get }
-
-    var supportSelected: Bool { get }
-
-    func imageName(selected: Bool) -> String
-
-    var size: CGSize { get }
-}
-
-// 创建一个全局辅助类来处理解码/编码
-struct MarkerTypeFactory {
-    static func markerType(from rawValue: Int) -> any MapMarkerSupportType {
-        // 根据应用包类型选择正确的枚举类型
-        switch currentPackage {
-        case .traceLocation1:
-            return MarkerType(rawValue: rawValue) ?? MarkerType.mine
-        // 如果有更多包类型,可以在这里添加
-        }
-    }
-}
-
-// 为MapMarkerSupportType添加Codable实现
-extension MapMarkerSupportType {
-    // 编码为整数
-    func encode(to encoder: Encoder) throws {
-        var container = encoder.singleValueContainer()
-        try container.encode(rawValue)
-    }
-}
-
-// 第一个包的标记类型
-enum MarkerType: Int, MapMarkerSupportType {
-    case mine = 1
-    case friend = 2
-    case traceStart = 3
-    case traceEndFriend = 4
-    case traceEndMine = 5
-    
-    var supportSelected: Bool {
-        return self == .mine || self == .friend
-    }
-    func imageName(selected: Bool) -> String {
-        let prefixName: String = currentPackage.rawValue
-        let imageBaseName: String = switch self {
-            case .mine:
-                "mine"
-            case .friend:
-                "friend"
-            case .traceStart:
-                "traceStart"
-            case .traceEndFriend:
-                "traceEndFriend"
-            case .traceEndMine:
-                "traceEndMine"
-        }
-        return "\(prefixName)_\(imageBaseName)" + ((selected && supportSelected) ? "_selected" : "")
-    }
-
-    var size: CGSize {
-        switch self {
-            case .traceStart:
-                return CGSize(width: 22, height: 36)
-            default:
-                return CGSize(width: 44, height: 52)
-        }
-    }
-}

+ 1 - 1
plugins/map_mapkit_ios/example/lib/main.dart

@@ -102,7 +102,7 @@ class _MyHomePageState extends State<MyHomePage> {
                       "id": "marker_${Random().nextInt(1000000)}",
                       "latitude": points[0]["latitude"],
                       "longitude": points[0]["longitude"],
-                      "markerName": "Marker ${Random().nextInt(1000000)}",
+                      "markerName": "",
                       "markerType": 3,
                       "isSelected": false
                     });

+ 3 - 2
plugins/map_mapkit_ios/ios/Classes/MapView/MapViewController.swift

@@ -99,8 +99,9 @@ extension MapViewController: MKMapViewDelegate {
 
     func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
         let renderer = MKPolylineRenderer(overlay: overlay)
-        renderer.lineWidth = 3
-        renderer.strokeColor = UIColor(red: 0.123, green: 0.125, blue: 0.255, alpha: 1.0)
+        renderer.lineWidth = 6
+        //rgba(123, 125, 255, 1)
+        renderer.strokeColor = UIColor(red: 123 / 255, green: 125 / 255, blue: 255 / 255, alpha: 1)
         renderer.lineCap = .round
         renderer.lineJoin = .round
         return renderer

+ 0 - 77
plugins/map_mapkit_ios/ios/Classes/MapView/Model/MarkerType.swift

@@ -1,77 +0,0 @@
-//
-//  MarkerType.swift
-//  Pods
-//
-//  Created by Groot on 2025/5/14.
-//
-
-import Foundation
-
-protocol MapMarkerSupportType: Codable {
-    var rawValue: Int { get }
-
-    var supportSelected: Bool { get }
-
-    func imageName(selected: Bool) -> String
-
-    var size: CGSize { get }
-}
-
-// 创建一个全局辅助类来处理解码/编码
-struct MarkerTypeFactory {
-    static func markerType(from rawValue: Int) -> any MapMarkerSupportType {
-        // 根据应用包类型选择正确的枚举类型
-        switch currentPackage {
-        case .traceLocation1:
-            return MarkerType(rawValue: rawValue) ?? MarkerType.mine
-        // 如果有更多包类型,可以在这里添加
-        }
-    }
-}
-
-// 为MapMarkerSupportType添加Codable实现
-extension MapMarkerSupportType {
-    // 编码为整数
-    func encode(to encoder: Encoder) throws {
-        var container = encoder.singleValueContainer()
-        try container.encode(rawValue)
-    }
-}
-
-// 第一个包的标记类型
-enum MarkerType: Int, MapMarkerSupportType {
-    case mine = 1
-    case friend = 2
-    case traceStart = 3
-    case traceEndFriend = 4
-    case traceEndMine = 5
-    
-    var supportSelected: Bool {
-        return self == .mine || self == .friend
-    }
-    func imageName(selected: Bool) -> String {
-        let prefixName: String = currentPackage.rawValue
-        let imageBaseName: String = switch self {
-            case .mine:
-                "mine"
-            case .friend:
-                "friend"
-            case .traceStart:
-                "traceStart"
-            case .traceEndFriend:
-                "traceEndFriend"
-            case .traceEndMine:
-                "traceEndMine"
-        }
-        return "\(prefixName)_\(imageBaseName)" + ((selected && supportSelected) ? "_selected" : "")
-    }
-
-    var size: CGSize {
-        switch self {
-            case .traceStart:
-                return CGSize(width: 22, height: 36)
-            default:
-                return CGSize(width: 44, height: 52)
-        }
-    }
-}

+ 52 - 0
plugins/map_mapkit_ios/ios/Classes/MapView/Views/MapAnnotationMarkerImageView.swift

@@ -0,0 +1,52 @@
+//
+//  MapAnnotationMarkerImageView.swift
+//  Pods
+//
+//  Created by Groot on 2025/5/14.
+//
+
+import UIKit
+
+class MapAnnotationMarkerImageView: UIView {
+    let markerType: any MapMarkerSupportType
+    var isSelected: Bool = false {
+        didSet {
+            imageView.image = uiImage
+        }
+    }
+
+    private let imageView = UIImageView()
+
+    init(markerType: any MapMarkerSupportType) {
+        self.markerType = markerType
+        super.init(frame: .zero)
+        setupImageView()
+    }
+
+    required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+
+    private func setupImageView() {
+        imageView.image = uiImage
+        imageView.contentMode = .scaleAspectFit
+        imageView.frame = CGRect(origin: .init(), size: markerType.size)
+        addSubview(imageView)
+    }
+
+    private var uiImage: UIImage? {
+        let imageName = markerType.imageName(selected: isSelected)
+        
+        if let image = UIImage(named: imageName) {
+            return image
+        }
+        
+        // 尝试从插件资源束加载
+        let bundleURL = Bundle(for: MapAnnotationView.self).url(forResource: "map_mapkit_ios_resources", withExtension: "bundle")
+        if let bundleURL = bundleURL, let resourceBundle = Bundle(url: bundleURL) {
+            return UIImage(named: imageName, in: resourceBundle, compatibleWith: nil)
+        }
+        
+        return nil
+    }
+}

+ 119 - 0
plugins/map_mapkit_ios/ios/Classes/MapView/Views/MapAnnotationMarkerTextView.swift

@@ -0,0 +1,119 @@
+//
+//  MapAnnotationMarkerTextView.swift
+//  Pods
+//
+//  Created by Groot on 2025/5/14.
+//
+
+import UIKit
+
+class MapAnnotationMarkerTextView: UIView {
+    // 常量定义
+    private static let bubbleHeight: CGFloat = 24
+    private static let triangleHeight: CGFloat = 6
+    private static let minWidth: CGFloat = 60
+    
+    static var height: CGFloat {
+        return bubbleHeight + triangleHeight
+    }
+
+    let text: String
+    private var labelView: UILabel!
+    private var backgroundView: UIView!
+    private var triangleLayer: CAShapeLayer!
+
+    init(text: String) {
+        self.text = text
+        super.init(frame: .zero)
+        setupViews()
+    }
+
+    required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+    
+    private func setupViews() {
+        createSubviews()
+        setupConstraints()
+    }
+    
+    private func createSubviews() {
+        // 创建胶囊形状背景视图
+        backgroundView = UIView()
+        backgroundView.backgroundColor = .white
+        backgroundView.layer.cornerRadius = 12  // 较大的圆角,实现胶囊形状
+        backgroundView.layer.masksToBounds = false
+        backgroundView.layer.shadowColor = UIColor.black.cgColor
+        backgroundView.layer.shadowOpacity = 0.2
+        backgroundView.layer.shadowOffset = CGSize(width: 0, height: 1)
+        backgroundView.layer.shadowRadius = 2
+        addSubview(backgroundView)
+        
+        // 创建标签视图(单行文本)
+        labelView = UILabel()
+        labelView.text = text
+        labelView.font = UIFont.systemFont(ofSize: 12, weight: .regular)
+        labelView.textColor = .black
+        labelView.backgroundColor = .clear
+        labelView.textAlignment = .center
+        labelView.lineBreakMode = .byTruncatingTail
+        labelView.numberOfLines = 1  // 限制为单行
+        backgroundView.addSubview(labelView)
+        
+        // 创建气泡三角形
+        triangleLayer = CAShapeLayer()
+        triangleLayer.fillColor = UIColor.white.cgColor
+        
+        let trianglePath = UIBezierPath()
+        trianglePath.move(to: CGPoint(x: 0, y: 0))    // 左点
+        trianglePath.addLine(to: CGPoint(x: 5, y: 6)) // 底点
+        trianglePath.addLine(to: CGPoint(x: 10, y: 0)) // 右点
+        trianglePath.close()
+        
+        triangleLayer.path = trianglePath.cgPath
+        layer.addSublayer(triangleLayer)
+    }
+    
+    private func setupConstraints() {
+        // 启用AutoLayout
+        translatesAutoresizingMaskIntoConstraints = false
+        backgroundView.translatesAutoresizingMaskIntoConstraints = false
+        labelView.translatesAutoresizingMaskIntoConstraints = false
+        
+        // 背景视图约束
+        NSLayoutConstraint.activate([
+            backgroundView.topAnchor.constraint(equalTo: topAnchor),
+            backgroundView.leadingAnchor.constraint(equalTo: leadingAnchor),
+            backgroundView.trailingAnchor.constraint(equalTo: trailingAnchor),
+            backgroundView.heightAnchor.constraint(equalToConstant: Self.bubbleHeight)
+        ])
+        
+        // 标签约束
+        NSLayoutConstraint.activate([
+            labelView.topAnchor.constraint(equalTo: backgroundView.topAnchor),
+            labelView.leadingAnchor.constraint(equalTo: backgroundView.leadingAnchor, constant: 8),
+            labelView.trailingAnchor.constraint(equalTo: backgroundView.trailingAnchor, constant: -8),
+            labelView.bottomAnchor.constraint(equalTo: backgroundView.bottomAnchor)
+        ])
+        
+        // 设置整个视图的高度(包含三角形)和最小宽度
+        NSLayoutConstraint.activate([
+            heightAnchor.constraint(equalToConstant: Self.height),
+            widthAnchor.constraint(greaterThanOrEqualToConstant: Self.minWidth)
+        ])
+        
+        layoutIfNeeded()
+        updateTrianglePosition()
+    }
+    
+    override func layoutSubviews() {
+        super.layoutSubviews()
+        updateTrianglePosition()
+    }
+    
+    private func updateTrianglePosition() {
+        // 更新三角形位置到底部中心
+        let width = bounds.width
+        triangleLayer.frame = CGRect(x: (width - 10) / 2, y: Self.bubbleHeight, width: 10, height: Self.triangleHeight)
+    }
+}

+ 87 - 50
plugins/map_mapkit_ios/ios/Classes/MapView/Views/MapAnnotationView.swift

@@ -13,88 +13,125 @@ class MapAnnotationView: MKAnnotationView {
     static let identifier: String = "MapAnnotationView"
 
     var marker: ATMapMarker?
+    var markerImageView: MapAnnotationMarkerImageView!
+    var textView: MapAnnotationMarkerTextView?
+    
+    // spacing between text and image
+    let spacing: CGFloat = 6
     
     var annotationSelected: Bool {
         return (marker?.isSelected ?? false) || self.isSelected
     }
     
-    private let imageView = UIImageView()
-    private var uiImage: UIImage? {
-        // 先尝试从主资源束加载
-        let imageName = marker?.markerType.imageName(selected: annotationSelected) ?? ""
-        print(imageName)
-        if let image = UIImage(named: imageName) {
-            return image
-        }
-        
-        // 尝试从插件资源束加载
-        let bundleURL = Bundle(for: MapAnnotationView.self).url(forResource: "map_mapkit_ios_resources", withExtension: "bundle")
-        if let bundleURL = bundleURL, let resourceBundle = Bundle(url: bundleURL) {
-            return UIImage(named: imageName, in: resourceBundle, compatibleWith: nil)
-        }
-        
-        return nil
-    }
-    
     override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
         self.marker = annotation as? ATMapMarker
         super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
         
         self.isEnabled = marker?.markerType.supportSelected ?? false
         self.isHidden = false
-        // 添加图片显示
-        setupImageView()
+        setupViews()
     }
 
     required init?(coder aDecoder: NSCoder) {
         fatalError("init(coder:) has not been implemented")
     }
     
-    private func setupImageView() {
-        // 设置默认图像
-        imageView.image = uiImage
-        imageView.contentMode = .scaleAspectFit
+    // MARK: - 设置视图
+    
+    private func setupViews() {
+        // 创建并添加图像视图
+        markerImageView = MapAnnotationMarkerImageView(markerType: marker?.markerType ?? MarkerType.mine)
+        markerImageView.isSelected = annotationSelected
+        addSubview(markerImageView)
+        
+        // 如果有标题,添加文本视图
+        if let markerName = marker?.markerName, !markerName.isEmpty {
+            textView = MapAnnotationMarkerTextView(text: markerName)
+            if let textView = textView {
+                addSubview(textView)
+            }
+        }
+        
+        // 设置AutoLayout
+        setupConstraints()
+    }
+    
+    // MARK: - 布局
+    
+    private func setupConstraints() {
+        // 禁用自动约束转换
+        translatesAutoresizingMaskIntoConstraints = false
+        markerImageView.translatesAutoresizingMaskIntoConstraints = false
         
-        // 添加图像视图到注释视图
-        addSubview(imageView)
+        let markerSize = marker?.markerType.size ?? CGSize(width: 30, height: 30)
         
-        // 设置图像视图的大小和位置
-        let size = marker?.markerType.size ?? .init()
-        imageView.frame = CGRect(origin: .init(), size: size)
+        // 设置图像视图约束 - 居中显示在标记视图中
+        NSLayoutConstraint.activate([
+            markerImageView.centerXAnchor.constraint(equalTo: centerXAnchor),
+            markerImageView.centerYAnchor.constraint(equalTo: centerYAnchor),
+            markerImageView.widthAnchor.constraint(equalToConstant: markerSize.width),
+            markerImageView.heightAnchor.constraint(equalToConstant: markerSize.height)
+        ])
+        
+        // 设置文本视图约束 - 位于图像上方,居中对齐
+        if let textView = textView {
+            textView.translatesAutoresizingMaskIntoConstraints = false
+            NSLayoutConstraint.activate([
+                textView.centerXAnchor.constraint(equalTo: centerXAnchor),
+                textView.bottomAnchor.constraint(equalTo: markerImageView.topAnchor, constant: -spacing)
+            ])
+        }
         
-        // 设置注释视图的大小
-        self.frame = imageView.frame
+        // 设置标记视图整体尺寸
+        let textHeight = textView?.intrinsicContentSize.height ?? 0
+        let totalHeight = textView != nil ? 
+            markerSize.height + textHeight + spacing : 
+            markerSize.height
         
-        // 设置注释视图的中心点偏移
-        self.centerOffset = CGPoint(x: 0, y: -imageView.frame.height / 2)
+        // 宽度至少和markerImageView一样宽,高度根据是否有文本决定
+        NSLayoutConstraint.activate([
+            widthAnchor.constraint(greaterThanOrEqualTo: markerImageView.widthAnchor),
+            heightAnchor.constraint(equalToConstant: totalHeight)
+        ])
+        
+        // 更新偏移量
+        updateCenterOffset()
+    }
+    
+    // MARK: - 更新视图
+    
+    override func layoutSubviews() {
+        super.layoutSubviews()
+        updateCenterOffset()
+    }
+    
+    private func updateCenterOffset() {
+        let markerSize = marker?.markerType.size ?? CGSize(width: 30, height: 30)
+        
+        if let textView = textView {
+            let textHeight = textView.frame.height
+            let totalHeight = markerSize.height + textHeight + spacing
+            
+            // 有文本时,调整偏移让图片底部对准坐标点
+            centerOffset = CGPoint(x: 0, y: -(totalHeight - markerSize.height)/2)
+        } else {
+            // 没有文本时,仅需要将图片底部对准坐标点
+            centerOffset = CGPoint(x: 0, y: -markerSize.height/2)
+        }
     }
     
     override func prepareForDisplay() {
         super.prepareForDisplay()
-        
-        // 确保图像是最新的
         updateImage()
     }
     
     private func updateImage() {
-        let oldImage = imageView.image
-        imageView.image = uiImage
-        
-        // 如果图像发生变化或为空,重新设置图像视图
-        if imageView.image == nil || oldImage != imageView.image {
-            setupImageView()
-        }
+        markerImageView.isSelected = annotationSelected
     }
 
     override func setSelected(_ selected: Bool, animated: Bool) {
         super.setSelected(selected, animated: animated)
-        if selected {
-            self.marker?.isSelected = true
-        } else {
-            self.marker?.isSelected = false
-        }
-        
-        // 更新图像以反映选中状态
+        marker?.isSelected = selected
         updateImage()
     }
-} 
+}