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

SwiftUI中使用GitHub NumberPicker库报错,求解决方法

解决SwiftUI中使用UIKit NumberPicker库的报错问题

问题根源

你用的这个NumberPicker库是基于UIKit(Storyboard)开发的,SwiftUI的视图体系和UIKit完全不同:

  • SwiftUI视图不是UIViewController实例,没法直接调用present方法
  • 原库的代理模式在SwiftUI值类型视图里无法直接适配

解决办法:用UIViewControllerRepresentable封装UIKit组件

通过SwiftUI提供的UIViewControllerRepresentable协议,把这个UIKit的NumberPicker包装成SwiftUI可直接使用的视图,同时处理代理回调逻辑。

1. 封装NumberPicker组件

创建一个符合协议的结构体,完成UIKit到SwiftUI的适配:

import SwiftUI
import NumberPicker

struct NumberPickerView: UIViewControllerRepresentable {
    // 传递配置参数
    let maxNumber: Int
    let heading: String
    let defaultNumber: Int
    let bgGradients: [UIColor]
    let tintColor: UIColor
    // 绑定选中结果和显示状态
    @Binding var selectedNumber: Int
    @Binding var isPresented: Bool
    
    func makeUIViewController(context: Context) -> UIViewController {
        // 用一个空的UIViewController作为容器来present选择器
        UIViewController()
    }
    
    func updateUIViewController(_ containerVC: UIViewController, context: Context) {
        // 根据isPresented状态控制picker的显示/隐藏
        if isPresented, containerVC.presentedViewController == nil {
            let numberPicker = NumberPicker(delegate: context.coordinator, maxNumber: maxNumber)
            numberPicker.bgGradients = bgGradients
            numberPicker.tintColor = tintColor
            numberPicker.heading = heading
            numberPicker.defaultSelectedNumber = defaultNumber
            
            containerVC.present(numberPicker, animated: true)
        } else if !isPresented, let presentedVC = containerVC.presentedViewController {
            presentedVC.dismiss(animated: true)
        }
    }
    
    // 创建协调器处理UIKit代理回调
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    class Coordinator: NSObject, NumberPickerDelegate {
        private let parent: NumberPickerView
        
        init(_ parent: NumberPickerView) {
            self.parent = parent
        }
        
        // 实现库的代理方法,把选中结果传回SwiftUI
        func numberPicker(_ numberPicker: NumberPicker, didSelectNumber number: Int) {
            parent.selectedNumber = number
            parent.isPresented = false
        }
    }
}

2. 在SwiftUI视图中使用封装后的组件

用@State变量控制选择器的显示状态,以及接收选中的数值:

struct ContentView: View {
    @State private var showNumberPicker = false
    @State private var selectedWeight = 150
    
    var body: some View {
        VStack(spacing: 20) {
            Text("选中体重: \(selectedWeight)")
                .font(.title)
            
            Button("打开体重选择器") {
                showNumberPicker = true
            }
        }
        // 用sheet弹出封装好的选择器
        .sheet(isPresented: $showNumberPicker) {
            NumberPickerView(
                maxNumber: 300,
                heading: "Weight",
                defaultNumber: 150,
                bgGradients: [.red, .yellow],
                tintColor: .white,
                selectedNumber: $selectedWeight,
                isPresented: $showNumberPicker
            )
        }
    }
}

核心要点

  • UIViewControllerRepresentable:作为SwiftUI和UIKit的桥梁,负责管理UIKit组件的生命周期
  • Coordinator:解决SwiftUI值类型无法作为UIKit代理的问题,处理回调逻辑
  • @Binding:实现父视图和封装组件之间的状态双向传递

这样就能在SwiftUI项目中正常使用这个UIKit的NumberPicker库,不会再出现原有代码的报错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 02:10:35