CircularSliderView.swift 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. //
  2. // CircularSliderView.swift
  3. // fiveConstant
  4. //
  5. // Created by 李建 on 2023/2/6.
  6. //
  7. // 弧形温度调节组件
  8. import SwiftUI
  9. struct CircularSliderView: View {
  10. @State var roomInfo: RoomInfo
  11. @State var temperatureValue: CGFloat
  12. @State var angleValue: CGFloat
  13. var onSetValue: ((Int)->Void)?
  14. let config = Config(minimumValue: 0,
  15. maximumValue: 14,
  16. totalValue: 14.0,
  17. knobRadius: 18.0,
  18. radius: 105.0)
  19. init(roomInfo: RoomInfo) {
  20. self.roomInfo = roomInfo
  21. let value = CGFloat(roomInfo.set_temp!)
  22. self.temperatureValue = value
  23. let fixAngle = (value - 16) / config.totalValue * (270 * .pi / 180)
  24. self.angleValue = fixAngle * 180 / .pi
  25. }
  26. var body: some View {
  27. ZStack {
  28. Circle()
  29. .trim(from: 0.125, to: 0.875)
  30. .stroke(roomInfo.power! ? Color("MainColor") : Color(hex: 0xF0F5F6, alpha: 1), lineWidth: 20)
  31. .frame(width: config.radius * 2, height: config.radius * 2)
  32. .rotationEffect(.degrees(90))
  33. ZStack {
  34. Circle()
  35. .fill(Color.white)
  36. .frame(width: config.knobRadius * 2, height: config.knobRadius * 2)
  37. .padding(10)
  38. .shadow(radius: 11, y: 5)
  39. .offset(y: -config.radius)
  40. .rotationEffect(Angle.degrees(angleValue))
  41. .zIndex(5)
  42. .gesture(DragGesture(minimumDistance: 0.0)
  43. .onChanged({ value in
  44. change(location: value.location)
  45. })
  46. .onEnded({ _ in
  47. self.onSetValue!(Int(temperatureValue))
  48. })
  49. )
  50. Circle()
  51. .fill(Color("MainColor"))
  52. .frame(width: 12, height: 12)
  53. .offset(y: -config.radius)
  54. .zIndex(6)
  55. .rotationEffect(Angle.degrees(angleValue))
  56. // 两头的小圆点
  57. Circle()
  58. .fill(roomInfo.power! ? Color("MainColor") : Color(hex: 0xF0F5F6, alpha: 1))
  59. .frame(width: 19, height: 19)
  60. .offset(y: -config.radius)
  61. Circle()
  62. .fill(roomInfo.power! ? Color("MainColor") : Color(hex: 0xF0F5F6, alpha: 1))
  63. .frame(width: 19, height: 19)
  64. .offset(y: -config.radius)
  65. .rotationEffect(Angle.degrees(270))
  66. }
  67. .rotationEffect(.degrees(225)) //
  68. HStack(spacing:0) {
  69. Text("\(String.init(format: "%.f", temperatureValue))")
  70. .font(.system(size: 60))
  71. .foregroundColor(Color("SecondColor"))
  72. .bold()
  73. Text("℃").font(.system(size: 20)).padding(.bottom, 30)
  74. }
  75. }
  76. }
  77. private func change(location: CGPoint) {
  78. let vector = CGVector(dx: location.x, dy: location.y)
  79. let angle = atan2(vector.dy - (config.knobRadius + 10), vector.dx - (config.knobRadius + 10)) + .pi/2.0
  80. let fixedAngle = angle < 0.0 ? angle + 2.0 * .pi : angle
  81. let value = fixedAngle / (270 * .pi / 180) * config.totalValue
  82. if value >= config.minimumValue && value <= config.maximumValue {
  83. temperatureValue = value + 16
  84. angleValue = fixedAngle * 180 / .pi
  85. }
  86. }
  87. }
  88. extension CircularSliderView {
  89. func onDragEnd(perform action: @escaping (Int)->Void) ->Self {
  90. var copy = self
  91. copy.onSetValue = action
  92. return copy
  93. }
  94. }
  95. struct Config {
  96. let minimumValue: CGFloat
  97. let maximumValue: CGFloat
  98. let totalValue: CGFloat
  99. let knobRadius: CGFloat
  100. let radius: CGFloat
  101. }
  102. struct CircularSliderView_Previews: PreviewProvider {
  103. static let json = """
  104. {"record_id":"1t7svi03170copjp9iimtd3z005isbfj","name":"样板间","home_id":"1t7svi01jj7copaplj7q47n170kd6hw6","home_name":"李建的家","is_master":true,"control_number":"1","user_id":"","power":true,"set_temp":21,"air_quality":0,"co2":0,"temperature":7,"humidity":0,"mode":2,"fan_speed":4,"fan_value":1,"timer_status":false,"duration":0}
  105. """.data(using: .utf8)!
  106. static var previews: some View {
  107. let decoder = JSONDecoder()
  108. let product = try? decoder.decode(RoomInfo.self, from: json)
  109. CircularSliderView(roomInfo: product!)
  110. }
  111. }