MapAmapMarkerBatteryView.swift 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. //
  2. // MapAmapMarkerBatteryView.swift
  3. // map_amap_ios
  4. //
  5. // Created by 诺诺诺的言 on 2025/7/22.
  6. //
  7. import Foundation
  8. import UIKit
  9. class MapAmapMarkerBatteryView: UIView {
  10. // 电池百分比 (0-100)
  11. var percentage: Int = 100 {
  12. didSet {
  13. percentage = min(100, max(0, percentage))
  14. setNeedsDisplay()
  15. }
  16. }
  17. // 电池颜色
  18. var batteryColor: UIColor = {
  19. if #available(iOS 13.0, *) {
  20. return .systemGreen
  21. } else {
  22. return UIColor(red: 0.20, green: 0.78, blue: 0.35, alpha: 1.00)
  23. }
  24. }() {
  25. didSet {
  26. setNeedsDisplay()
  27. }
  28. }
  29. // 低电量颜色 (默认低于20%显示红色)
  30. var lowBatteryColor: UIColor = {
  31. if #available(iOS 13.0, *) {
  32. return .systemRed
  33. } else {
  34. return UIColor(red: 1.00, green: 0.23, blue: 0.19, alpha: 1.00)
  35. }
  36. }()
  37. var lowBatteryThreshold: Int = 20
  38. // 边框颜色
  39. var borderColor: UIColor = {
  40. if #available(iOS 13.0, *) {
  41. return .label
  42. } else {
  43. return .black
  44. }
  45. }() {
  46. didSet {
  47. setNeedsDisplay()
  48. }
  49. }
  50. // 边框宽度
  51. var borderWidth: CGFloat = 1.0 {
  52. didSet {
  53. setNeedsDisplay()
  54. }
  55. }
  56. // 内容与边框的间距
  57. var contentPadding: CGFloat = 1.0 {
  58. didSet {
  59. setNeedsDisplay()
  60. }
  61. }
  62. // 电池头与电池身体的间距
  63. var headSpacing: CGFloat = 1.0 {
  64. didSet {
  65. setNeedsDisplay()
  66. }
  67. }
  68. // 是否显示百分比文本
  69. var showPercentageText: Bool = true {
  70. didSet {
  71. setNeedsDisplay()
  72. }
  73. }
  74. // 文本颜色
  75. var textColor: UIColor = {
  76. if #available(iOS 13.0, *) {
  77. return .label
  78. } else {
  79. return .black
  80. }
  81. }() {
  82. didSet {
  83. setNeedsDisplay()
  84. }
  85. }
  86. // 文本字体
  87. var textFont: UIFont = UIFont.systemFont(ofSize: 10) {
  88. didSet {
  89. setNeedsDisplay()
  90. }
  91. }
  92. // 文本与电池的间距
  93. var textSpacing: CGFloat = 2 {
  94. didSet {
  95. setNeedsDisplay()
  96. }
  97. }
  98. // 边距设置
  99. var horizontalPadding: CGFloat = 6 {
  100. didSet {
  101. setNeedsDisplay()
  102. }
  103. }
  104. var verticalPadding: CGFloat = 4 {
  105. didSet {
  106. setNeedsDisplay()
  107. }
  108. }
  109. // 电池尺寸
  110. var batteryWidth: CGFloat = 10 {
  111. didSet {
  112. setNeedsDisplay()
  113. }
  114. }
  115. var batteryHeight: CGFloat = 7 {
  116. didSet {
  117. setNeedsDisplay()
  118. }
  119. }
  120. private let batteryCornerRadius: CGFloat = 1.0
  121. private let batteryKnobWidth: CGFloat = 2.0
  122. private let batteryKnobHeight: CGFloat = 3.0
  123. private let batteryKnobCornerRadius: CGFloat = 0
  124. override init(frame: CGRect) {
  125. super.init(frame: frame)
  126. backgroundColor = .clear
  127. }
  128. required init?(coder: NSCoder) {
  129. super.init(coder: coder)
  130. backgroundColor = .clear
  131. }
  132. override func draw(_ rect: CGRect) {
  133. super.draw(rect)
  134. // 先计算文本尺寸(如果需要显示文本)
  135. var textSize = CGSize.zero
  136. if showPercentageText {
  137. let text = "\(percentage)%"
  138. let textAttributes: [NSAttributedString.Key: Any] = [
  139. .font: textFont,
  140. .foregroundColor: textColor
  141. ]
  142. textSize = text.size(withAttributes: textAttributes)
  143. }
  144. // 计算总内容宽度
  145. let totalContentWidth = batteryWidth + batteryKnobWidth + headSpacing + (showPercentageText ? (textSpacing + textSize.width) : 0)
  146. // 计算起始X坐标(居中)
  147. let startX = (rect.width - totalContentWidth) / 2
  148. // 电池主体区域
  149. let batteryBodyRect = CGRect(
  150. x: startX,
  151. y: (rect.height - batteryHeight) / 2,
  152. width: batteryWidth,
  153. height: batteryHeight
  154. )
  155. // 电池头区域
  156. let batteryKnobRect = CGRect(
  157. x: batteryBodyRect.maxX + headSpacing,
  158. y: batteryBodyRect.midY - batteryKnobHeight / 2,
  159. width: batteryKnobWidth,
  160. height: batteryKnobHeight
  161. )
  162. // 绘制电池主体
  163. let batteryPath = UIBezierPath(
  164. roundedRect: batteryBodyRect,
  165. cornerRadius: batteryCornerRadius
  166. )
  167. batteryPath.lineWidth = borderWidth
  168. // 根据电量选择颜色
  169. let fillColor = percentage <= lowBatteryThreshold ? lowBatteryColor : batteryColor
  170. fillColor.setStroke()
  171. batteryPath.stroke()
  172. // 绘制电池头
  173. let knobPath = UIBezierPath(
  174. roundedRect: batteryKnobRect,
  175. cornerRadius: batteryKnobCornerRadius
  176. )
  177. fillColor.setFill()
  178. knobPath.fill()
  179. // 计算电量填充区域(考虑内容间距)
  180. let fillWidth = (batteryWidth - borderWidth - contentPadding * 2) * CGFloat(percentage) / 100
  181. let fillRect = CGRect(
  182. x: batteryBodyRect.origin.x + borderWidth / 2 + contentPadding,
  183. y: batteryBodyRect.origin.y + borderWidth / 2 + contentPadding,
  184. width: fillWidth,
  185. height: batteryHeight - borderWidth - contentPadding * 2
  186. )
  187. fillColor.setFill()
  188. UIBezierPath(rect: fillRect).fill()
  189. // 绘制百分比文本(在电池右侧)
  190. if showPercentageText {
  191. let text = "\(percentage)%"
  192. let textAttributes: [NSAttributedString.Key: Any] = [
  193. .font: textFont,
  194. .foregroundColor: fillColor
  195. ]
  196. let textRect = CGRect(
  197. x: batteryKnobRect.maxX + textSpacing,
  198. y: rect.midY - textSize.height / 2,
  199. width: textSize.width,
  200. height: textSize.height
  201. )
  202. text.draw(in: textRect, withAttributes: textAttributes)
  203. }
  204. }
  205. override var intrinsicContentSize: CGSize {
  206. var textWidth: CGFloat = 0
  207. if showPercentageText {
  208. textWidth = "100%".size(withAttributes: [.font: textFont]).width + textSpacing
  209. }
  210. let totalWidth = batteryWidth + batteryKnobWidth + headSpacing + textWidth
  211. let totalHeight = max(batteryHeight, batteryKnobHeight)
  212. let sumHeight = totalHeight + verticalPadding * 2
  213. self.layer.cornerRadius = sumHeight / 2.0
  214. self.layer.masksToBounds = true
  215. print("totalheigdfdfji---\(totalHeight + verticalPadding * 2)");
  216. return CGSize(
  217. width: totalWidth + horizontalPadding * 2,
  218. height: totalHeight + verticalPadding * 2
  219. )
  220. }
  221. }