You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI自定义Picker问题:如何设置默认起始位置为0,00

解决SwiftUI自定义Picker默认显示0,00的问题

你的基于UIScrollView的方案完全可以实现默认显示0,00的需求,只需要调整偏移量的初始化和绑定逻辑即可,具体修改步骤如下:

  1. 拆分偏移量绑定:原代码中两个滑块共用一个offset变量导致滚动同步,现在为整数和小数滑块分别设置独立的偏移量变量。
  2. 计算整数部分初始偏移:找到0在整数数组中的索引,将初始偏移量设置为索引 × 单个元素高度(90),确保0显示在中间位置。
  3. 同步偏移量到ScrollView:在CustomSlider的updateUIView方法中,将绑定的偏移量同步到UIScrollView的contentOffset,保证初始位置生效。
  4. 小数部分初始偏移:小数部分默认显示第一个元素"00",对应初始偏移量为0。

修改后的完整代码

import SwiftUI

struct CustomPicker: View {
    @State var integerOffset: CGFloat
    @State var doubleOffset: CGFloat = 0

    let integers: [Int]
    let doubles: [String]

    init(integers: [Int], doubles: [String]) {
        self.integers = integers
        self.doubles = doubles
        // 计算0在整数数组中的索引,设置初始偏移
        if let startIndex = integers.firstIndex(of: 0) {
            self._integerOffset = State(initialValue: CGFloat(startIndex) * 90)
        } else {
            self._integerOffset = State(initialValue: 0)
        }
    }

    var body: some View {
        VStack {
            HStack(spacing: 0) {
                CustomSlider(sliderItems: integers.count, offset: $integerOffset, content: {
                    VStack(spacing: 0){
                        ForEach(integers, id: \.self ){ index in
                            VStack {
                                Text("\(index)")
                                    .font(.custom("Calibre", size: 65))
                                    .foregroundColor(.black)
                                    .frame(maxWidth: 90, maxHeight: 90)
                            }.onTapGesture {
                                print("DEBUG: \(index)")
                            }
                        }
                    }
                })
                .frame(maxWidth: 90 , maxHeight: 270)

                Text(",")
                    .font(.custom("Calibre", size: 65))

                CustomSlider(sliderItems: doubles.count, offset: $doubleOffset, content: {
                    VStack(spacing: 0){
                        ForEach(doubles, id: \.self ){ index in
                            VStack {
                                Text("\(index)")
                                    .font(.custom("Calibre", size: 65))
                                    .foregroundColor(.black)
                                    .frame(maxWidth: 90, maxHeight: 90)
                            }.onTapGesture {
                                print("DEBUG: \(index)")
                            }
                        }
                    }
                })
                .frame(maxWidth: 90 , maxHeight: 270)
            }
        }
    }
}

func getRect()-> CGRect{
    return UIScreen.main.bounds
}

struct CustomSlider<Content: View> : UIViewRepresentable {
    var content: Content
    @Binding var offset : CGFloat
    var sliderItems: Int

    init(sliderItems: Int, offset: Binding<CGFloat>,@ViewBuilder content: @escaping ()->Content){
        self.content = content()
        self._offset = offset
        self.sliderItems = sliderItems
    }

    func makeCoordinator() -> Coordinator {
        return CustomSlider.Coordinator(parent: self)
    }

    func makeUIView(context: Context) ->  UIScrollView {
        let scrollView = UIScrollView()
        let swiftUIView = UIHostingController(rootView: content).view!

        let height =  CGFloat(sliderItems * 90) + 180
        swiftUIView.frame = CGRect(x: 0, y: 0, width: 90, height: height)

        scrollView.contentSize = swiftUIView.frame.size
        scrollView.addSubview(swiftUIView)
        scrollView.bounces = false
        scrollView.showsVerticalScrollIndicator = false
        scrollView.showsHorizontalScrollIndicator = false
        scrollView.delegate = context.coordinator

        // 设置初始偏移
        scrollView.contentOffset.y = offset
        return scrollView
    }

    func updateUIView(_ uiView: UIScrollView, context: Context) {
        // 避免循环更新,仅当偏移不一致时设置
        if abs(uiView.contentOffset.y - offset) > 1 {
            uiView.setContentOffset(CGPoint(x: 0, y: offset), animated: false)
        }
    }

    class Coordinator: NSObject, UIScrollViewDelegate{
        var parent: CustomSlider

        init(parent: CustomSlider){
            self.parent = parent
        }

        func scrollViewDidScroll(_ scrollView: UIScrollView ){
            parent.offset = scrollView.contentOffset.y
        }

        func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
            let offset  = scrollView.contentOffset.y
            let value = (offset / 90).rounded(.toNearestOrAwayFromZero)
            scrollView.setContentOffset(CGPoint(x: 0, y: value * 90), animated: false)
        }

        func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
            if !decelerate {
                let offset  = scrollView.contentOffset.y
                let value = (offset / 90).rounded(.toNearestOrAwayFromZero)
                scrollView.setContentOffset(CGPoint(x: 0, y: value * 90), animated: false)
            }
        }
    }
}

struct CustomPicker_Previews: PreviewProvider {
    static var previews: some View {
        CustomPicker(integers: Array(-5...20), doubles: ["00", "25", "50", "75"])
    }
}

关键修改说明

  • 在CustomPicker的初始化方法中,通过firstIndex(of: 0)找到0在整数数组中的位置,计算出对应的初始偏移量,确保0默认显示在中间。
  • 为整数和小数滑块分别设置独立的偏移量变量integerOffset和doubleOffset,避免滚动同步干扰。
  • 在CustomSlider的makeUIView和updateUIView中,确保初始偏移量正确应用到UIScrollView,并且在偏移量变化时同步更新。

内容的提问来源于stack exchange,提问作者Alex Anghel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 06:32:24