PlayerCustomSlider.swift
1 // 2 // CustomSlider.swift 3 // flo 4 // 5 // Created by rizaldy on 05/06/24. 6 // 7 8 import SwiftUI 9 10 struct PlayerCustomSlider: View { 11 var isMediaLoading: Bool = false 12 13 @Binding var isSeeking: Bool 14 @Binding var value: Double 15 16 @State private var tempValue: Double = 0.0 17 18 var range: ClosedRange<Double> 19 var onEnded: (Double) -> Void 20 21 var body: some View { 22 GeometryReader { geometry in 23 ZStack(alignment: .leading) { 24 Rectangle() 25 .foregroundColor(Color.gray.opacity(0.8)) 26 .frame(height: 5) 27 .cornerRadius(5) 28 29 Rectangle() 30 .foregroundColor(Color.white) 31 .frame( 32 width: CGFloat( 33 (self.value - self.range.lowerBound) / (self.range.upperBound - self.range.lowerBound) 34 ) * geometry.size.width, height: 4 35 ) 36 .opacity(isMediaLoading ? 0 : 1) 37 .cornerRadius(2) 38 39 if self.isSeeking { 40 Circle() 41 .fill(Color.white) 42 .frame(width: 12, height: 12) 43 .opacity(0.8) 44 .offset( 45 x: CGFloat( 46 (self.tempValue - self.range.lowerBound) 47 / (self.range.upperBound - self.range.lowerBound)) * geometry.size.width - 6) 48 } 49 50 Circle() 51 .fill(Color.white) 52 .frame(width: 12, height: 12) 53 .offset( 54 x: CGFloat( 55 (self.value - self.range.lowerBound) / (self.range.upperBound - self.range.lowerBound) 56 ) * geometry.size.width - 6 57 ) 58 .opacity(isMediaLoading ? 0 : 1) 59 .animation(.easeInOut(duration: 0.3), value: self.value) 60 .gesture( 61 DragGesture() 62 .onChanged { gesture in 63 self.isSeeking = true 64 65 let newValue = 66 self.range.lowerBound + Double(gesture.location.x / geometry.size.width) 67 * (self.range.upperBound - self.range.lowerBound) 68 69 self.tempValue = newValue 70 }.onEnded { gesture in 71 let newValue = 72 self.range.lowerBound + Double(gesture.location.x / geometry.size.width) 73 * (self.range.upperBound - self.range.lowerBound) 74 75 onEnded(newValue) 76 77 self.isSeeking = false 78 } 79 ) 80 } 81 } 82 .frame(height: 20) 83 } 84 } 85 86 struct CustomSliders_Previews: PreviewProvider { 87 static var previews: some View { 88 PreviewWrapper() 89 } 90 91 struct PreviewWrapper: View { 92 @State private var value: Double = 0.30 93 @State private var isSeeking: Bool = false 94 95 var body: some View { 96 ZStack { 97 Color.accent 98 HStack { 99 PlayerCustomSlider(isSeeking: $isSeeking, value: $value, range: 0...1) { value in 100 self.value = value 101 } 102 }.padding() 103 }.ignoresSafeArea() 104 } 105 } 106 }