lgqfzz 2024-08-01 23:38 采纳率: 0%
浏览 9

swift UI 日期选择器的问题

这是swift UI方面的问题
这是实现年月日时分的选择器,问题是不论月份如何改变,日期始终是31天。调试的时候我发现日期会变成默认值也就是当前的时间8月1号,8月可不是31吗?
贴代码:

import SwiftUI
import UIKit

// `SimplePicker` 是一个 SwiftUI 视图,它使用 `UIViewRepresentable` 协议将 `UIPickerView` 包装成 SwiftUI 视图。
struct SimplePicker2: UIViewRepresentable {
    @Binding var myDate: MyDateStruct2
    let minYear: Int = 1900
    let maxYear: Int = 2100

    // 创建并返回 `UIPickerView` 实例
    func makeUIView(context: Context) -> UIPickerView {
        let pickerView = UIPickerView()
        pickerView.delegate = context.coordinator // 设置代理
        pickerView.dataSource = context.coordinator // 设置数据源
        pickerView.selectRow(myDate.year - myDate.minYear, inComponent: 0, animated: false)
        pickerView.selectRow(myDate.month - 1, inComponent: 1, animated: false)
        pickerView.selectRow(myDate.day - 1, inComponent: 2, animated: false)
        pickerView.selectRow(myDate.hour - 1, inComponent: 3, animated: false)
        pickerView.selectRow(myDate.minute - 1, inComponent: 4, animated: false)
        return pickerView
    }

    // 当 SwiftUI 需要更新视图时调用,这里不需要更新视图,所以为空实现
    func updateUIView(_ uiView: UIPickerView, context: Context) {
        uiView.reloadAllComponents()
        uiView.selectRow(myDate.year - myDate.minYear, inComponent: 0, animated: false)
        uiView.selectRow(myDate.month - 1, inComponent: 1, animated: false)
        uiView.selectRow(myDate.day - 1, inComponent: 2, animated: false)
        uiView.selectRow(myDate.hour - 1, inComponent: 3, animated: false)
        uiView.selectRow(myDate.minute - 1, inComponent: 4, animated: false)
    }

    // 创建并返回 `Coordinator` 实例
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    // `Coordinator` 类负责处理 `UIPickerView` 的委托和数据源方法
    class Coordinator: NSObject, UIPickerViewDelegate, UIPickerViewDataSource {
        var parent: SimplePicker2
        // 初始化 `Coordinator` 实例,保存对 `SimplePicker` 的引用
        init(_ pickerView: SimplePicker2) {
            self.parent = pickerView
        }

        // 返回选择器的列数 年月日时分 所有五列
        func numberOfComponents(in pickerView: UIPickerView) -> Int {
            return 5 // parent.data.count
        }

        // 返回某列的行数
        func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
            switch component {
            case 0: // 年
                return parent.maxYear - parent.minYear + 1
            case 1: // 月
                return 12
            case 2: // 日
                return parent.myDate.GetDays(yy: parent.myDate.year, mm: parent.myDate.month)
            case 3: // 时
                return 24
            case 4: // 分
                return 60
            default: // 秒或者错误 其实没有秒的
                return 60
            }
        }

        // 返回某列某行的标题
        func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
            switch component {
            case 0: // 年
                return "\(row + parent.minYear)"
            case 1: // 月
                return "\(row + 1)月"
            case 2: // 日
                return "\(row + 1)日"
            case 3: // 时
                return "\(row)"
            case 4: // 分
                return "\(row)"
            default: // 秒或者错误 其实没有秒的
                return "\(row)"
            }
        }

        // 处理选择事件,打印选择的值
        func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
            switch component {
            case 0:
                parent.myDate.year = row + parent.myDate.minYear
            case 1:
                parent.myDate.month = row + 1
                pickerView.reloadComponent(2)
                print("月份改变:\(row + 1)-\(parent.myDate.month)")
            case 2:
                parent.myDate.day = row + 1
            case 3:
                parent.myDate.hour = row
            case 4:
                parent.myDate.minute = row
            default:
                break
            }
        }

        // 设置宽度
        public func pickerView(_ pickerView: UIPickerView, widthForComponent component: Int) -> CGFloat {
            let totalWidth = pickerView.bounds.width
            switch component {
            case 0:
                return totalWidth * 0.24 // 第一列宽度为100
            case 1:
                return totalWidth * 0.21 // 第二列宽度为150
            case 2:
                return totalWidth * 0.23 // 第三列宽度为200
            case 3:
                return totalWidth * 0.15
            default:
                return totalWidth * 0.15
            }
        }
    }
}

struct MyDateStruct2 {
    var minYear = 1900
    var maxYear = 2100
    var year: Int = 2000 // 阳历
    var month: Int = 1
    var day: Int = 1
    var hour: Int = 0
    var minute: Int = 0
    func GetDays(yy: Int, mm: Int) -> Int {
        if mm < 1 || mm > 12 {
            return 0
        }

        if yy == 1582 && mm == 10 {
            return 21
        }

        // 计算是否是闰年
        let isLeapYear = (yy % 4 == 0 && yy % 100 != 0) || (yy % 400 == 0)
        // 每月的天数
        let daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
        // 计算该月的天数
        var dom = daysInMonth[mm - 1]
        if mm == 2 && isLeapYear {
            dom = 29
        }

        return dom
    }
}

// `TestView` 是一个包含 `SimplePicker` 的 SwiftUI 视图
struct TestView2: View {
    @State private var myDate: MyDateStruct2
    init() {
        let calendar = Calendar.current
        let now = Date()
        let components = calendar.dateComponents([.year, .month, .day, .hour, .minute], from: now)
        _myDate = State(initialValue: MyDateStruct2(
            year: components.year!,
            month: components.month!,
            day: components.day!,
            hour: components.hour!,
            minute: components.minute!))
    }

    var body: some View {
        VStack {
            Text("年月日时分")
            Text("\(String(myDate.year))\(myDate.month)\(myDate.day)\(myDate.hour)\(myDate.minute)分")
            Button(action: {
                myDate.year -= 1
            }, label: {
                Text("阴阳历")
            })
            SimplePicker2(myDate: $myDate)
                .frame(height: 200) // 设置选择器的高度
        }
    }
}

// 预览 `TestView`
#Preview {
    TestView2()
    // SimplePicker()
}

我在

```swift
return parent.myDate.GetDays(yy: parent.myDate.year, mm: parent.myDate.month)

```加了断点,选择日期后,我发现它执行了6次,前三次时间都是对的,后面日期不对了,变成了默认值也就是2024.8.1号。
问题出在哪里?请求帮助,谢谢您!

  • 写回答

1条回答 默认 最新

  • 猿来如此yyy 2024-08-02 10:21
    关注

    根据你提供的代码,问题可能出在didSelectRow方法中。当选择月份后,你调用了pickerView.reloadComponent(2)来刷新日期组件,但是你没有更新day属性的值。因此,当updateUIView方法被调用时,它将使用默认值1来设置日期组件,并不会根据你之前的选择来更新。

    要解决这个问题,你可以在didSelectRow方法中添加以下代码来更新day属性的值:

    case 1:
        parent.myDate.month = row + 1
        let newDay = parent.myDate.GetDays(yy: parent.myDate.year, mm: parent.myDate.month)
        parent.myDate.day = min(parent.myDate.day, newDay)
        pickerView.reloadComponent(2)
        print("月份改变:\(row + 1)-\(parent.myDate.month)")
    

    这样,当你选择不同的月份时,日期组件将根据新的月份和之前选择的日期来刷新,并使用正确的天数限制。

    评论

报告相同问题?

问题事件

  • 创建了问题 8月1日

悬赏问题

  • ¥15 35114 SVAC视频验签的问题
  • ¥15 impedancepy
  • ¥15 在虚拟机环境下完成以下,要求截图!
  • ¥15 求往届大挑得奖作品(ppt…)
  • ¥15 如何在vue.config.js中读取到public文件夹下window.APP_CONFIG.API_BASE_URL的值
  • ¥50 浦育平台scratch图形化编程
  • ¥20 求这个的原理图 只要原理图
  • ¥15 vue2项目中,如何配置环境,可以在打完包之后修改请求的服务器地址
  • ¥20 微信的店铺小程序如何修改背景图
  • ¥15 UE5.1局部变量对蓝图不可见