SwiftUI滑块缩略图图像偏移

31moq8wy  于 2023-01-04  发布在  Swift
关注(0)|答案(1)|浏览(140)

我正在尝试制作一个带有刻度和自定义缩略图的自定义SwiftUI滑块。除了缩略图没有与刻度对齐之外,它工作得很好。我如何使它们对齐呢?

init() {
    let ticker: UIImage = UIImage(named: "ticker")?.withAlignmentRectInsets(UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 90)) ?? UIImage()
    UISlider.appearance().setThumbImage(ticker, for: .normal)
}

滑块:

ZStack {
      HStack { 
           ForEach(0...10, id: \.self) { _ in
               Text("I")
                   .frame(maxWidth: .infinity)
                   .foregroundColor(ColorStyle(colorAsset: .lightGrey).color)
            
      }
      Slider(value: $viewModel.sliderValue, in: minSlider...maxSlider, step: sliderStep)
           .tint(ColorStyle(colorAsset: .lightGrey).color)
}
zphenhs4

zphenhs41#

正在开发一个通用的滑块生成器,以减少重复的编码器,并针对iPad(iOS)进行了优化。诀窍是考虑到轨道长度减少拇指宽度的方式,因此全范围略小于帧宽度。所附代码不完整-需要为传入的变量设置@environment。粉红色边框只是为了突出显示帧。

import SwiftUI

fileprivate let panelFrameWidth: CGFloat = 500
fileprivate let sliderFrameWidth: CGFloat = 400
fileprivate let sliderFrameHeight: CGFloat = 70
fileprivate let sliderTitleWidth: CGFloat = panelFrameWidth - sliderFrameWidth
fileprivate let sliderValueYoffset: CGFloat = -30
fileprivate let sliderTickYoffset: CGFloat = 7.5
fileprivate let sliderCallupYoffset: CGFloat = 15
fileprivate let thumbWidth: CGFloat = 26 // 26 for iPad & iPhone; 6 for MacOS
fileprivate let tickMark = "I" // character for tick mark on slider
fileprivate let dp0 = "%.0f" // for formatting float in Text() to 0 decimal places
fileprivate let dp1 = "%.1f" // for formatting float in Text() to 1 decimal places
fileprivate let dp2 = "%.2f" // for formatting float in Text() to 2 decimal places

struct SliderBuilderData {
    var title: String = "Title"
    var rangeMin: Double = 0
    var rangeMax: Double = 100
    var rangeSteps: Double = 10
    var rangeCallups: [Double] = [0,25,50,75,100]
    var valueToPxl: Double {(sliderFrameWidth - thumbWidth)/(rangeMax - rangeMin)}
    var rangeCallupCentreOffsets: [CGFloat] {rangeCallups.map {CGFloat((($0) - (rangeMin + rangeMax)/2)*valueToPxl)}}
    var rangeCallupsToDisplay: [String] {rangeCallups.map {String(format: dp0, ($0))}}
}

struct SliderValueText: View {
    let text: String

    var body: some View {
        Text(text)
            .font(.body)
            .padding(2.0)
            .foregroundColor(.white)
            .background(.blue)
            .clipShape(Capsule())
    }
}

struct SliderViewBuilder: View {
    @State var value: Double
    let slider: SliderBuilderData

    var body: some View {
        ZStack {
            HStack (spacing: 0){
                Text(slider.title)
                    .frame(width: sliderTitleWidth, height: sliderFrameHeight, alignment: .leading)
                    .border(Color.pink)
            
                Slider(value: $value, in: slider.rangeMin...slider.rangeMax, step: slider.rangeSteps)
                    .frame(width: sliderFrameWidth, height: sliderFrameHeight)
                    .border(Color.pink)
            }
            SliderValueText(text: String(format: dp0, value))
                .frame(width: sliderFrameWidth - thumbWidth - 5, height: sliderFrameHeight/2, alignment: .center)
                .offset(x: sliderTitleWidth/2 + (value - (slider.rangeMin + slider.rangeMax)/2)*slider.valueToPxl, y: sliderValueYoffset)
            ForEach(slider.rangeCallups.indices, id: \.self) {index in
                VStack {
                    Text(tickMark) // this is for tick marks; omit for MacOS
                        .font(.caption)
                        .offset(x: sliderTitleWidth/2 + slider.rangeCallupCentreOffsets[index], y: sliderTickYoffset)
                    Text("\(slider.rangeCallupsToDisplay[index])")
                        .font(.caption)
                        .offset(x: sliderTitleWidth/2 + slider.rangeCallupCentreOffsets[index], y:sliderCallupYoffset)
                }
            }
        }
    }
}

struct ContentView: View {
    @State var testValue: Double = 25
    @State var cover: Double = 30

    let testBuilder: SliderBuilderData = SliderBuilderData()
    let coverSliderBuilder: SliderBuilderData = SliderBuilderData(title: "Cover\n(mm)", rangeMin: 20, rangeMax: 80, rangeSteps: 5, rangeCallups: [20,30,40,50,60,70,80])

    var body: some View {
        VStack {
            SliderViewBuilder(value: testValue, slider: testBuilder)
            Text("Hello, World! \(String(format: dp2, testValue))")
            SliderViewBuilder(value: cover, slider: coverSliderBuilder)
        }
        .padding()
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

相关问题