見出し画像

SwiftUIのSliderが全然カスタマイズができないので自作のカスタムSlider作成してみた!

こんにちは!リーさんです🐳
とある案件でSliderを使うことになり、あまり実装したことなかったので
調べてみると全然カスタマイズできないやないか。。。。。

デザインが結構おしゃれなスライダーになるので、Apple提供のものでは作れないと思い、カスタマイズSliderを作成してみました!

今回はメモ用なのでデザイン部分は適当にやってます。
とりあえず動くものとしてのコードになるのでご了承ください☠️

import SwiftUI

struct ContentView: View {
    @State private var sliderValue: Double = 0
    let maxValue: Double = 100
    
    var body: some View {
            CustomSlider(value: $sliderValue, range: 0...maxValue) {
                print("スライダーが終わった後の処理")
            }
            .frame(width: .infinity, height: 50)
            .padding(.horizontal, 20)
    }
}

struct CustomSlider: View {
    @Binding var value: Double
    @State private var isSliding = false
    var range: ClosedRange<Double>
    var onEnded: () -> Void
    
    var body: some View {
        GeometryReader { geometry in
            let dragGesture = DragGesture(minimumDistance: 0)
                .onChanged { gesture in
                    let newValue = value + Double(gesture.translation.width) * (range.upperBound - range.lowerBound) / Double(geometry.size.width)
                    value = min(max(range.lowerBound, newValue), range.upperBound)
                    
                    self.isSliding = true
                }
                .onEnded { _ in
                    onEnded()
                    self.isSliding = false
                }
            
            ZStack {
                Capsule()
                    .foregroundColor(.gray)
                    .frame(height: 20)
                
                Capsule()
                    .fill(Color.blue)
                    .frame(width: CGFloat(self.value - self.range.lowerBound) / CGFloat(self.range.upperBound - self.range.lowerBound) * geometry.size.width, height: 20)
                    .offset(x: -geometry.size.width / 2 + CGFloat(self.value - self.range.lowerBound) / CGFloat(self.range.upperBound - self.range.lowerBound) * geometry.size.width / 2, y: 0)
                
                handleButton
                    .foregroundColor(.blue)
                    .frame(width: 30, height: 30)
                    .gesture(dragGesture)
                    .offset(x: CGFloat((value - range.lowerBound) / (range.upperBound - range.lowerBound)) * geometry.size.width - geometry.size.width / 2)
                
                if isSliding {
                    Text("\(value)")
                        .font(.system(size:50).bold())
                        .padding(.bottom, 100)
                }
            }
        }
    }
    // MEMO: つまみ部分のカスタマイズ
    var handleButton: some View {
        ZStack {
            Rectangle()
                .fill(Color.blue)
                .frame(width: 30, height: 30)
                .cornerRadius(8)
            
            HStack(spacing: 2) {
                Rectangle()
                    .fill(Color.white)
                    .frame(width: 3, height: 10)
                
                Rectangle()
                    .fill(Color.white)
                    .frame(width: 3, height: 10)
            }
        }
    }
}

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

こちらは動作動画になります!!

いいなと思ったら応援しよう!