lgqfzz 2024-08-04 18:51 采纳率: 0%
浏览 7
已结题

swiftUI与UIkit日期选择器使用问题

SwiftUI和UIkit方面的问题
我是初学者,应该用法方面的问题,已精简了程序,放入xcode就可运行。程序是一个年月日时分选择器,但是在月份改变的时候,日期始终是31天,没有改变。比如4月6月等都是30天。
我发现它取的是默认值,就是我初始化的值。
也做了调试,在此处打了断点(return parent.myDate.GetDays(yy: parent.myDate.year, mm: parent.myDate.month 这里是返回行数的),前三次是对的,后面三次就变成初始值了,也就是8月,8月就是31天,这是为什么?
还有点阴阳历切换的时候,选中的显示选中的都是数字,阴历应该输出“阴历”。
代码如下:

import SwiftUI
import UIKit
 
// `SimplePicker` 是一个 SwiftUI 视图,它使用 `UIViewRepresentable` 协议将 `UIPickerView` 包装成 SwiftUI 视图。
struct SimplePicker2: UIViewRepresentable {
    @Binding var myDate: MyDateStruct2
 
    // 创建并返回 `UIPickerView` 实例
    func makeUIView(context: Context) -> UIPickerView {
        let pickerView = UIPickerView()
        pickerView.delegate = context.coordinator // 设置代理
        pickerView.dataSource = context.coordinator // 设置数据源
 
        // 初始化 selectedMonth
        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 {
        print("hello coordinator111")
        return 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.myDate.maxYear - parent.myDate.minYear + 1
            case 1: // 月
                return 12
            case 2: // 日
                // 使用 selectedMonth 计算天数
                // let month = selectedMonth
                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.myDate.minYear)"
            case 1: // 月
                return parent.myDate.iflunar ? "阴历" : "\(row + 1)月"
            case 2: // 日
                return parent.myDate.iflunar ? "阴历" : "\(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:
                // 更新 selectedMonth
                parent.myDate.month = row + 1
                let newDay = parent.myDate.GetDays(yy: parent.myDate.year, mm: parent.myDate.month)
                if parent.myDate.day > newDay {
                    parent.myDate.day = newDay
                }
                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 iflunar: Bool = false
    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("年月日时分-\(myDate.iflunar ? "阴历":"阳历")")
            Text("\(String(myDate.year))\(myDate.month)\(myDate.day)\(myDate.hour)\(myDate.minute)分")
            Button(action: {
                myDate.year -= 1
                myDate.iflunar.toggle()
            }, label: {
                Text("阴阳历")
            })
            SimplePicker2(myDate: $myDate)
                .frame(height: 200) // 设置选择器的高度
        }
    }
}
 
// 预览 `TestView`
#Preview {
    TestView2()
    // SimplePicker()
}


我学习不久,求告知,多谢。

  • 写回答

8条回答 默认 最新

  • 专家-司宇[在线] 2024-08-04 18:51
    关注

    引自免费微信小程序:皆我百晓生

    针对你提到的月份改变时日期始终为31天的问题,是因为你在更新月份后,虽然你尝试重新加载了日期的组件,但没有更新月份对应的最大天数。这导致了在月份改变后,日期仍然按照旧月份的最大天数来显示,而不是根据新月份的实际天数来更新。下面是一些针对这个问题的修复建议。

    首先,确保在更新月份后重新计算并设置日期的最大值。在CoordinatordidSelectRow方法中,当月份改变时,你需要重新计算该月的天数并设置给日期选择器。以下是修改后的代码片段:

    // ... 其他代码不变 ...
    
    // 在Coordinator类中
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        switch component {
        case 0: // 年份改变时处理逻辑不变 ...
        case 1: // 月份改变时的处理逻辑
            parent.myDate.month = row + 1 // 更新月份
            let newDayCount = parent.myDate.GetDays(yy: parent.myDate.year, mm: parent.myDate.month) // 获取新月份的天数
            parent.myDate.day = newDayCount // 设置日期的最大值为新月份的天数
            pickerView.selectRow(newDayCount - 1, inComponent: 2, animated: false) // 选择新月份的第一天(注意减一,因为索引是从0开始的)
            print("月份改变:\(row + 1)-\(parent.myDate.month)") // 打印日志确认月份已更新
            break // 其他情况处理逻辑不变 ...
        // 其他组件的处理逻辑不变 ...
        }
    }
    

    关于阴阳历切换时显示的问题,你可以在数据源方法中根据iflunar的值返回不同的标题。如果iflunartrue,则返回“阴历”,否则返回实际的日期值。修改后的代码如下:

    // 在Coordinator类的titleForRow方法中
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        switch component {
            // 其他组件的处理逻辑不变 ...
        case 2: // 日的标题处理逻辑增加判断iflunar的值
            return parent.myDate.iflunar ? "阴历" : "\(row + 1)日" // 根据iflunar值返回不同的标题
        default: // 错误或未处理情况的处理逻辑不变 ...
        }
    }
    

    以上是针对你提出的问题的修复建议。希望对你有所帮助!如果有其他问题或需要进一步的帮助,请随时提问。

    评论 编辑记录

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 8月5日
  • 创建了问题 8月4日

悬赏问题

  • ¥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局部变量对蓝图不可见