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

SwiftUI中如何将Wheel Picker放入上下文菜单弹窗?

实现两列Wheel Picker弹窗(类似Apple DatePicker样式)

Menu 和 .contextMenu 属于菜单类容器,本身不支持放置 WheelPicker 这类需要交互的控件,所以得改用 Sheet 承载自定义双列选择器,实现和系统 DatePicker 一致的弹窗效果。

步骤1:封装UIKit的UIPickerView(适配SwiftUI)

通过 UIViewRepresentable 将UIKit的UIPickerView封装为SwiftUI可用组件,支持双列选择逻辑:

import SwiftUI

struct DoubleColumnPicker: UIViewRepresentable {
    let firstColumnOptions: [String]
    let secondColumnOptions: [String]
    @Binding var selectedFirst: String
    @Binding var selectedSecond: String
    
    func makeUIView(context: Context) -> UIPickerView {
        let picker = UIPickerView()
        picker.delegate = context.coordinator
        picker.dataSource = context.coordinator
        
        // 设置默认选中项
        if let firstIndex = firstColumnOptions.firstIndex(of: selectedFirst) {
            picker.selectRow(firstIndex, inComponent: 0, animated: false)
        }
        if let secondIndex = secondColumnOptions.firstIndex(of: selectedSecond) {
            picker.selectRow(secondIndex, inComponent: 1, animated: false)
        }
        
        return picker
    }
    
    func updateUIView(_ uiView: UIPickerView, context: Context) {}
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    class Coordinator: NSObject, UIPickerViewDelegate, UIPickerViewDataSource {
        let parent: DoubleColumnPicker
        
        init(_ parent: DoubleColumnPicker) {
            self.parent = parent
        }
        
        // 返回列数
        func numberOfComponents(in pickerView: UIPickerView) -> Int {
            2
        }
        
        // 返回每列的选项数量
        func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
            component == 0 ? parent.firstColumnOptions.count : parent.secondColumnOptions.count
        }
        
        // 返回每行显示的内容
        func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
            component == 0 ? parent.firstColumnOptions[row] : parent.secondColumnOptions[row]
        }
        
        // 处理选中事件
        func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
            if component == 0 {
                parent.selectedFirst = parent.firstColumnOptions[row]
            } else {
                parent.selectedSecond = parent.secondColumnOptions[row]
            }
        }
    }
}

步骤2:主视图实现弹窗逻辑

用Sheet弹出Picker,搭配取消/确认按钮,还原系统DatePicker的弹窗布局:

struct ContentView: View {
    // 模拟两列选项数据
    let firstOptions = ["选项1-1", "选项1-2", "选项1-3", "选项1-4"]
    let secondOptions = ["选项2-1", "选项2-2", "选项2-3"]
    
    // 选中值绑定
    @State private var selectedFirst = "选项1-1"
    @State private var selectedSecond = "选项2-1"
    @State private var showPickerSheet = false
    
    var body: some View {
        Button("打开选择器") {
            showPickerSheet.toggle()
        }
        .sheet(isPresented: $showPickerSheet) {
            VStack(spacing: 0) {
                // 顶部操作栏
                HStack {
                    Button("取消") {
                        showPickerSheet.toggle()
                    }
                    Spacer()
                    Button("确定") {
                        showPickerSheet.toggle()
                        // 这里可添加选中后的业务逻辑
                        print("最终选中:\(selectedFirst) - \(selectedSecond)")
                    }
                }
                .padding()
                .background(Color(UIColor.systemBackground))
                
                // 双列选择器
                DoubleColumnPicker(
                    firstColumnOptions: firstOptions,
                    secondColumnOptions: secondOptions,
                    selectedFirst: $selectedFirst,
                    selectedSecond: $selectedSecond
                )
                .frame(height: 200)
                .background(Color(UIColor.systemBackground))
            }
            .background(Color(UIColor.systemGray6))
            .presentationDetents([.height(260)]) // 固定弹窗高度,和系统DatePicker对齐
        }
    }
}

核心说明

  • 用Sheet替代Menu/contextMenu:Sheet支持承载交互式控件,能满足Picker的交互需求;
  • 原生Picker效果:通过封装UIKit的UIPickerView,实现和系统控件一致的滚轮体验;
  • 还原系统交互:顶部操作栏+固定高度的弹窗布局,和系统DatePicker的使用逻辑完全匹配。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 19:23:11