|
|
@@ -0,0 +1,260 @@
|
|
|
+//
|
|
|
+// MapAnnotationBatteryView.swift
|
|
|
+// map_mapkit_ios
|
|
|
+//
|
|
|
+// Created by 诺诺诺的言 on 2025/7/18.
|
|
|
+//
|
|
|
+
|
|
|
+import Foundation
|
|
|
+import UIKit
|
|
|
+
|
|
|
+class MapAnnotationBatteryView: UIView {
|
|
|
+ // 电池百分比 (0-100)
|
|
|
+ var percentage: Int = 100 {
|
|
|
+ didSet {
|
|
|
+ percentage = min(100, max(0, percentage))
|
|
|
+ setNeedsDisplay()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 电池颜色
|
|
|
+ var batteryColor: UIColor = {
|
|
|
+ if #available(iOS 13.0, *) {
|
|
|
+ return .systemGreen
|
|
|
+ } else {
|
|
|
+ return UIColor(red: 0.20, green: 0.78, blue: 0.35, alpha: 1.00)
|
|
|
+ }
|
|
|
+ }() {
|
|
|
+ didSet {
|
|
|
+ setNeedsDisplay()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 低电量颜色 (默认低于20%显示红色)
|
|
|
+ var lowBatteryColor: UIColor = {
|
|
|
+ if #available(iOS 13.0, *) {
|
|
|
+ return .systemRed
|
|
|
+ } else {
|
|
|
+ return UIColor(red: 1.00, green: 0.23, blue: 0.19, alpha: 1.00)
|
|
|
+ }
|
|
|
+ }()
|
|
|
+ var lowBatteryThreshold: Int = 20
|
|
|
+
|
|
|
+ // 边框颜色
|
|
|
+ var borderColor: UIColor = {
|
|
|
+ if #available(iOS 13.0, *) {
|
|
|
+ return .label
|
|
|
+ } else {
|
|
|
+ return .black
|
|
|
+ }
|
|
|
+ }() {
|
|
|
+ didSet {
|
|
|
+ setNeedsDisplay()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 边框宽度
|
|
|
+ var borderWidth: CGFloat = 1.0 {
|
|
|
+ didSet {
|
|
|
+ setNeedsDisplay()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 内容与边框的间距
|
|
|
+ var contentPadding: CGFloat = 1.0 {
|
|
|
+ didSet {
|
|
|
+ setNeedsDisplay()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 电池头与电池身体的间距
|
|
|
+ var headSpacing: CGFloat = 1.0 {
|
|
|
+ didSet {
|
|
|
+ setNeedsDisplay()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 是否显示百分比文本
|
|
|
+ var showPercentageText: Bool = true {
|
|
|
+ didSet {
|
|
|
+ setNeedsDisplay()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 文本颜色
|
|
|
+ var textColor: UIColor = {
|
|
|
+ if #available(iOS 13.0, *) {
|
|
|
+ return .label
|
|
|
+ } else {
|
|
|
+ return .black
|
|
|
+ }
|
|
|
+ }() {
|
|
|
+ didSet {
|
|
|
+ setNeedsDisplay()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 文本字体
|
|
|
+ var textFont: UIFont = UIFont.systemFont(ofSize: 10) {
|
|
|
+ didSet {
|
|
|
+ setNeedsDisplay()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 文本与电池的间距
|
|
|
+ var textSpacing: CGFloat = 2 {
|
|
|
+ didSet {
|
|
|
+ setNeedsDisplay()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 边距设置
|
|
|
+ var horizontalPadding: CGFloat = 6 {
|
|
|
+ didSet {
|
|
|
+ setNeedsDisplay()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ var verticalPadding: CGFloat = 4 {
|
|
|
+ didSet {
|
|
|
+ setNeedsDisplay()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 电池尺寸
|
|
|
+ var batteryWidth: CGFloat = 10 {
|
|
|
+ didSet {
|
|
|
+ setNeedsDisplay()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ var batteryHeight: CGFloat = 7 {
|
|
|
+ didSet {
|
|
|
+ setNeedsDisplay()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private let batteryCornerRadius: CGFloat = 1.0
|
|
|
+ private let batteryKnobWidth: CGFloat = 2.0
|
|
|
+ private let batteryKnobHeight: CGFloat = 3.0
|
|
|
+ private let batteryKnobCornerRadius: CGFloat = 0
|
|
|
+
|
|
|
+ override init(frame: CGRect) {
|
|
|
+ super.init(frame: frame)
|
|
|
+ backgroundColor = .clear
|
|
|
+ }
|
|
|
+
|
|
|
+ required init?(coder: NSCoder) {
|
|
|
+ super.init(coder: coder)
|
|
|
+ backgroundColor = .clear
|
|
|
+ }
|
|
|
+
|
|
|
+ override func draw(_ rect: CGRect) {
|
|
|
+ super.draw(rect)
|
|
|
+
|
|
|
+ // 先计算文本尺寸(如果需要显示文本)
|
|
|
+ var textSize = CGSize.zero
|
|
|
+ if showPercentageText {
|
|
|
+ let text = "\(percentage)%"
|
|
|
+ let textAttributes: [NSAttributedString.Key: Any] = [
|
|
|
+ .font: textFont,
|
|
|
+ .foregroundColor: textColor
|
|
|
+ ]
|
|
|
+ textSize = text.size(withAttributes: textAttributes)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算总内容宽度
|
|
|
+ let totalContentWidth = batteryWidth + batteryKnobWidth + headSpacing + (showPercentageText ? (textSpacing + textSize.width) : 0)
|
|
|
+
|
|
|
+ // 计算起始X坐标(居中)
|
|
|
+ let startX = (rect.width - totalContentWidth) / 2
|
|
|
+
|
|
|
+ // 电池主体区域
|
|
|
+ let batteryBodyRect = CGRect(
|
|
|
+ x: startX,
|
|
|
+ y: (rect.height - batteryHeight) / 2,
|
|
|
+ width: batteryWidth,
|
|
|
+ height: batteryHeight
|
|
|
+ )
|
|
|
+
|
|
|
+ // 电池头区域
|
|
|
+ let batteryKnobRect = CGRect(
|
|
|
+ x: batteryBodyRect.maxX + headSpacing,
|
|
|
+ y: batteryBodyRect.midY - batteryKnobHeight / 2,
|
|
|
+ width: batteryKnobWidth,
|
|
|
+ height: batteryKnobHeight
|
|
|
+ )
|
|
|
+
|
|
|
+ // 绘制电池主体
|
|
|
+ let batteryPath = UIBezierPath(
|
|
|
+ roundedRect: batteryBodyRect,
|
|
|
+ cornerRadius: batteryCornerRadius
|
|
|
+ )
|
|
|
+ batteryPath.lineWidth = borderWidth
|
|
|
+
|
|
|
+ // 根据电量选择颜色
|
|
|
+ let fillColor = percentage <= lowBatteryThreshold ? lowBatteryColor : batteryColor
|
|
|
+ fillColor.setStroke()
|
|
|
+ batteryPath.stroke()
|
|
|
+
|
|
|
+
|
|
|
+ // 绘制电池头
|
|
|
+ let knobPath = UIBezierPath(
|
|
|
+ roundedRect: batteryKnobRect,
|
|
|
+ cornerRadius: batteryKnobCornerRadius
|
|
|
+ )
|
|
|
+ fillColor.setFill()
|
|
|
+ knobPath.fill()
|
|
|
+
|
|
|
+ // 计算电量填充区域(考虑内容间距)
|
|
|
+ let fillWidth = (batteryWidth - borderWidth - contentPadding * 2) * CGFloat(percentage) / 100
|
|
|
+ let fillRect = CGRect(
|
|
|
+ x: batteryBodyRect.origin.x + borderWidth / 2 + contentPadding,
|
|
|
+ y: batteryBodyRect.origin.y + borderWidth / 2 + contentPadding,
|
|
|
+ width: fillWidth,
|
|
|
+ height: batteryHeight - borderWidth - contentPadding * 2
|
|
|
+ )
|
|
|
+
|
|
|
+
|
|
|
+ fillColor.setFill()
|
|
|
+ UIBezierPath(rect: fillRect).fill()
|
|
|
+
|
|
|
+ // 绘制百分比文本(在电池右侧)
|
|
|
+ if showPercentageText {
|
|
|
+ let text = "\(percentage)%"
|
|
|
+ let textAttributes: [NSAttributedString.Key: Any] = [
|
|
|
+ .font: textFont,
|
|
|
+ .foregroundColor: fillColor
|
|
|
+ ]
|
|
|
+
|
|
|
+ let textRect = CGRect(
|
|
|
+ x: batteryKnobRect.maxX + textSpacing,
|
|
|
+ y: rect.midY - textSize.height / 2,
|
|
|
+ width: textSize.width,
|
|
|
+ height: textSize.height
|
|
|
+ )
|
|
|
+
|
|
|
+ text.draw(in: textRect, withAttributes: textAttributes)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ override var intrinsicContentSize: CGSize {
|
|
|
+ var textWidth: CGFloat = 0
|
|
|
+ if showPercentageText {
|
|
|
+ textWidth = "100%".size(withAttributes: [.font: textFont]).width + textSpacing
|
|
|
+ }
|
|
|
+
|
|
|
+ let totalWidth = batteryWidth + batteryKnobWidth + headSpacing + textWidth
|
|
|
+ let totalHeight = max(batteryHeight, batteryKnobHeight)
|
|
|
+
|
|
|
+ let sumHeight = totalHeight + verticalPadding * 2
|
|
|
+ self.layer.cornerRadius = sumHeight / 2.0
|
|
|
+ self.layer.masksToBounds = true
|
|
|
+ print("totalheigdfdfji---\(totalHeight + verticalPadding * 2)");
|
|
|
+ return CGSize(
|
|
|
+ width: totalWidth + horizontalPadding * 2,
|
|
|
+ height: totalHeight + verticalPadding * 2
|
|
|
+ )
|
|
|
+ }
|
|
|
+}
|
|
|
+
|