swift 自定义DatePacker

news2024/9/20 1:08:20

请添加图片描述

import Foundation

enum AppDatePickerStyle {
    
    case KDatePickerDate    //年月日
    case KDatePickerTime    //年月日时分
    case kDatePickerMonth // 年月
    case KDatePickerSecond  //秒

}

class AppDatePicker: UIView {

    private let jk_rootView = UIApplication.shared.keyWindow!
    private var jk_backgroundView: UIView!
    
    private var confirmHandler: (( _ year: Int, _ month: Int,_ day: Int) -> Void)?//选择的回调
    var cancelHandler: (() -> Void)?//取消的回调
    /// 选择器类型
    fileprivate var datePickerStyle: AppDatePickerStyle!
    /// 时间数据
    fileprivate var unitFlags:Set<Calendar.Component>!
    var pickerView = UIPickerView()
    
    //数据相关
    fileprivate var yearRange = 30 + 1000//年的范围
    
    fileprivate var dayRange = 0 //
    
    fileprivate var startYear = 0
    
    // 当前选中日期
    fileprivate var selectedYear = 0;
    fileprivate var selectedMonth = 0;
    fileprivate var selectedDay = 0;
    fileprivate var selectedHour = 0;
    fileprivate var selectedMinute = 0;
    fileprivate var selectedSecond = 0;

    override init(frame: CGRect) {
        super.init(frame: frame)
    }
    convenience init(title: String = "选择日期", type: AppDatePickerStyle, confirmHandler: @escaping (_ year:Int,_ month:Int,_ day:Int) -> Void) {
        self.init(frame: .zero)
        
        configUI()

        self.confirmHandler = confirmHandler
        
        jk_titleLabel.text = title
        initDatePickerWithType(type: type)
    }
    convenience init(title: String = "选择日期", year: Int, month: Int, day: Int, confirmHandler: @escaping (_ year:Int,_ month:Int,_ day:Int) -> Void) {
        self.init(frame: .zero)
        
        configUI()
        self.confirmHandler = confirmHandler
        
        jk_titleLabel.text = title
        initDatePickerWithType(type: .kDatePickerMonth, date: year == -1 ? nil:Date.dateFor("\(year)-\(month)-\(day)"))
    }
    
    private func getHeight() -> CGFloat {
        return CGFloat(56 + 4 * 50 + 56)
    }
    
    // MARK: - UIButtonAction
    @objc private func confimBtnAction() {
        
        if let holder = confirmHandler {
            holder(selectedYear, selectedMonth, selectedDay)
        }
        
        hide()
    }
    
    // MARK: - configUI
    func configUI() {
        
        
        // 防止多个 AlertView 重复显示
        if jk_rootView.subviews.filter({ $0.isKind(of: AppDatePicker.self) }).count > 0 { return }
                
        jk_backgroundView = UIView()
        jk_backgroundView.backgroundColor = UIColor.black.withAlphaComponent(0)
        
        jk_rootView.addSubview(jk_backgroundView)
        jk_rootView.addSubview(self)
        addSubview(jk_backView)
        jk_backView.addSubview(cornerBackView)
        cornerBackView.addSubview(jk_titleLabel)
        cornerBackView.addSubview(pickerView)
        cornerBackView.addSubview(jk_cancelBtn)
        cornerBackView.addSubview(conformBtn)
        cornerBackView.addSubview(verticalLineView)
        
        jk_backgroundView.snp.makeConstraints { (make) in
            make.edges.equalTo(jk_rootView)
        }
        
        let height = getHeight()
        snp.makeConstraints { make in
            make.left.right.equalToSuperview()
            make.height.equalTo(height + Size.safeAreaBottomGap)
            make.bottom.equalTo(height + Size.safeAreaBottomGap)
        }
        jk_backView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }
        cornerBackView.snp.makeConstraints { make in
            make.left.top.right.equalToSuperview()
            make.height.equalTo(height)
        }
        jk_titleLabel.snp.makeConstraints { make in
            make.height.equalTo(40)
            make.top.equalTo(16)
            make.left.right.equalToSuperview()
        }
        pickerView.snp.makeConstraints { make in
            make.top.equalTo(jk_titleLabel.snp.bottom)
            make.left.right.equalToSuperview()
            make.height.equalTo(50 * 4)
        }
        jk_cancelBtn.snp.makeConstraints { make in
            make.height.equalTo(56)
            make.top.equalTo(pickerView.snp.bottom)
            make.left.equalToSuperview()
            make.width.equalToSuperview().multipliedBy(0.5)
        }
        conformBtn.snp.makeConstraints { make in
            make.right.equalToSuperview()
            make.centerY.height.width.equalTo(jk_cancelBtn)
        }
        verticalLineView.snp.makeConstraints { make in
            make.height.equalTo(20)
            make.width.equalTo(1)
            make.centerY.equalTo(jk_cancelBtn)
            make.centerX.equalToSuperview()
        }
        
        self.jk_rootView.layoutIfNeeded()
        
        let tapGR = UITapGestureRecognizer.init(target: self, action: #selector(hideAction))
        jk_backgroundView.addGestureRecognizer(tapGR)
        
        jk_cancelBtn.addTarget(self, action: #selector(hideAction), for: .touchUpInside)
        conformBtn.addTarget(self, action: #selector(confimBtnAction), for: .touchUpInside)
        
        pickerView.delegate = self
        pickerView.dataSource = self
        
    }
    private lazy var jk_backView: UIView = {
        let jk_backView = UIView()
        jk_backView.backgroundColor = .white
        return jk_backView
    }()
    private lazy var cornerBackView: UIView = {
        let cornerBackView = UIView()
        cornerBackView.backgroundColor = .white
        return cornerBackView
    }()
    private lazy var jk_titleLabel: UILabel = {
        let jk_titleLabel = UILabel()
        jk_titleLabel.textAlignment = .center
        jk_titleLabel.font = kSetPingFangMedium(18)
        return jk_titleLabel
    }()
    private lazy var jk_cancelBtn: UIButton = {
        let jk_cancelBtn = UIButton()
        jk_cancelBtn.setTitle("取消", for: .normal)
        jk_cancelBtn.setTitleColor( .black, for: .normal)
        return jk_cancelBtn
    }()
    private lazy var verticalLineView: UIView = {
        let verticalLineView = UIView()
        verticalLineView.backgroundColor = .jky_viewBackgroundColor
        return verticalLineView
    }()
    private lazy var conformBtn: UIButton = {
        let conformBtn = UIButton()
        conformBtn.setTitle("确定", for: .normal)
        conformBtn.setTitleColor( .black, for: .normal)
        return conformBtn
    }()
    
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        fatalError("init(coder:) has not been implemented")
    }
}

//MARK:初始化数据
extension AppDatePicker {
    
    fileprivate func initDatePickerWithType(type: AppDatePickerStyle, date: Date? = nil)  {
        
        datePickerStyle = type
        let  calendar0 = Calendar.init(identifier: .gregorian)//公历
        
        var comps = DateComponents()//一个封装了具体年月日、时秒分、周、季度等的类
        
        unitFlags = [.year , .month , .day]
        
        switch  datePickerStyle {
        case .KDatePickerDate:
            break
        case .KDatePickerTime:
            unitFlags = [.year , .month , .day , .hour , .minute ]
        case .kDatePickerMonth:
            unitFlags = [.year , .month]
        case .KDatePickerSecond:
            unitFlags = [.year , .month , .day , .hour , .minute ,.second]
        default:
            break
        }
        
//        comps = calendar0.dateComponents(unitFlags, from: date != nil ? date! : Date())
        comps = calendar0.dateComponents(unitFlags, from: date != nil ? date!:Date())

        
        startYear = comps.year! - 100
        
        dayRange = self.isAllDay(year: startYear, month: 1)
        
        yearRange = 30 + 1000;
        selectedYear = comps.year!;
        selectedMonth = comps.month!;
        
        self.pickerView.selectRow(selectedYear - startYear, inComponent: 0, animated: true)
        self.pickerView.selectRow(selectedMonth - 1, inComponent: 1, animated: true)
        if datePickerStyle != .kDatePickerMonth {
            selectedDay = comps.day!;
            self.pickerView.selectRow(selectedDay - 1, inComponent: 2, animated: true)
        }
        
        switch  datePickerStyle {
        case .KDatePickerDate:
            break
        case .KDatePickerTime:
            selectedHour = comps.hour!;
            selectedMinute = comps.minute!;
            
            self.pickerView.selectRow(selectedHour , inComponent: 3, animated: true)
            self.pickerView.selectRow(selectedMinute , inComponent: 4, animated: true)
        case .KDatePickerSecond:
            selectedHour = comps.hour!;
            selectedMinute = comps.minute!;
            selectedSecond = comps.second!;
            self.pickerView.selectRow(selectedHour , inComponent: 3, animated: true)
            self.pickerView.selectRow(selectedMinute , inComponent: 4, animated: true)
            self.pickerView.selectRow(selectedSecond, inComponent: 5, animated: true)
        default:
            break
        }
        self.pickerView.reloadAllComponents()
    }
    
    //MARK:计算每个月有多少天
    fileprivate func isAllDay(year:Int, month:Int) -> Int {
        
        var   day:Int = 0
        switch(month)
        {
        case 1,3,5,7,8,10,12:
            day = 31
        case 4,6,9,11:
            day = 30
        case 2:
            
            if(((year%4==0)&&(year%100==0))||(year%400==0))
            {
                day=29
            }
            else
            {
                day=28;
            }
            
        default:
            break;
        }
        return day;
    }
    
}

extension AppDatePicker : UIPickerViewDelegate,UIPickerViewDataSource {
    
    //返回UIPickerView当前的列数
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return unitFlags == nil ? 0 : unitFlags.count
    }
    
    //确定每一列返回的东西
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        
        switch component {
        case 0:
            return yearRange
        case 1:
            return 12
        case 2:
            return dayRange
        case 3:
            return 24
        case 4:
            return 60
        case 5:
            return 60
        default:
            return 0
        }
    }
    
    func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat {
        return 45
    }
    
    //返回一个视图,用来设置pickerView的每行显示的内容。
    func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
        
        
        let label  = UILabel(frame: CGRect(x: screenWidth * CGFloat(component) / 6 , y: 0, width: screenWidth/6, height: 50))
        
        label.font = UIFont.boldSystemFont(ofSize: CGFloat(16))

        label.tag = component*100+row
        
        label.textAlignment = .center
        
        switch component {
        case 0:
            
            label.frame=CGRect(x:5, y:0,width:screenWidth/4.0, height:50);
            
            
            label.text="\(self.startYear + row)年";
            
        case 1:
            
            label.frame=CGRect(x:screenWidth/4.0, y:0,width:screenWidth/8.0, height:50);
            
            
            label.text="\(row + 1)月";
        case 2:
            
            label.frame=CGRect(x:screenWidth*3/8, y:0,width:screenWidth/8.0, height:50);
            
            
            label.text="\(row + 1)日";
        case 3:
            
            label.textAlignment = .right
            
            label.text="\(row )时";
        case 4:
            
            label.textAlignment = .right
            
            label.text="\(row )分";
        case 5:
            
            label.textAlignment = .right
            
            label.frame=CGRect(x:screenWidth/6, y:0,width:screenWidth/6.0 - 5, height:50);
            
            
            label.text="\(row )秒";
            
        default:
            label.text="\(row )秒";
        }
        
        return label
    }
    
    //当点击UIPickerView的某一列中某一行的时候,就会调用这个方法
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        switch component {
        case 0:
            self.selectedYear = self.startYear + row
            
            self.dayRange = self.isAllDay(year: self.startYear, month: self.selectedMonth)
            
            if datePickerStyle != .kDatePickerMonth {
                self.pickerView.reloadComponent(2)
            }
        case 1:
            self.selectedMonth =  row + 1
            
            self.dayRange = self.isAllDay(year: self.startYear, month: self.selectedMonth)
            
            if datePickerStyle != .kDatePickerMonth {
                self.pickerView.reloadComponent(2)
            }
        case 2:
            selectedDay = row + 1
        case 3:
            selectedHour = row
        case 4:
            selectedMinute = row
        case 5:
            selectedSecond = row
        default:
            selectedSecond = row
        }
    }
    
}

extension AppDatePicker: UIGestureRecognizerDelegate {
    
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
        
        if let view = touch.view, view.isDescendant(of: pickerView) {
            return false
        }
        
        return true
    }
    
    func show() {
        
        self.jk_backView.layerCornerRadius(16, [.topLeft,.topRight])
        UIView.animate(withDuration: 0.2, animations: {
            self.jk_backgroundView.backgroundColor = UIColor.black.withAlphaComponent(0.5)
            self.snp.updateConstraints { make in
                make.bottom.equalTo(0)
            }
            self.jk_rootView.layoutIfNeeded()
        })

    }
    
    @objc private func hideAction() {
        if let holder = cancelHandler {
            holder()
        }
        hide()
    }
    
    private func hide(completion: (() -> Void)? = nil) {
        
        UIView.animate(withDuration: 0.2, animations: {
            self.jk_backgroundView.backgroundColor = UIColor.black.withAlphaComponent(0)
            self.snp.updateConstraints { make in
                make.bottom.equalTo(self.getHeight() + Size.safeAreaBottomGap)
            }
            self.jk_rootView.layoutIfNeeded()
        }) { finished in
            guard finished else { return }
            self.removeFromSuperview()
            self.jk_backgroundView.removeFromSuperview()
        }
        
    }
        
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1985126.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

电池放电的速率对电池寿命有影响吗?

电池放电的速率对电池寿命确实有很大的影响&#xff0c;电池的寿命通常是指电池在正常使用条件下&#xff0c;能够保持其额定容量的时间。电池的容量会随着充放电次数的增加而逐渐减少&#xff0c;这个过程被称为电池的老化。电池的老化速度受到许多因素的影响&#xff0c;其中…

自闭症的孩子有哪些症状

在自闭症这个复杂而广阔的领域中&#xff0c;作为长期从事自闭症教育的工作者&#xff0c;我们深知每一位自闭症孩子都是独一无二的&#xff0c;他们面对的世界充满了挑战与不解。自闭症&#xff0c;也被称为孤独症谱系障碍&#xff0c;其核心症状往往体现在社交互动、沟通以及…

git安装图文

1.下载 通过百度网盘分享的文件&#xff1a;git安装图文 链接&#xff1a;https://pan.baidu.com/s/17ZMiWUIULtrGGba5n-WLeA 提取码&#xff1a;anjm --来自百度网盘超级会员V3的分享 2.安装

使用Go语言绘制水平柱状图教程

使用Go语言绘制水平柱状图教程 在本教程中&#xff0c;我们将学习如何使用Go语言及gg包绘制水平柱状图&#xff0c;并将图表保存为PNG格式的图片。水平柱状图适用于展示多个类别的数据&#xff0c;且便于标签的排列和阅读。 安装gg包 首先&#xff0c;确保你已经安装了gg包。…

远程抄表,构建智能水电管理

选自成都纵横智控官网-https://www.iotrouter.com/news/1320.html 众所周知&#xff0c;传统的人工抄表方式需要耗费大量人力资源&#xff0c;同时存在抄表难、监管难、收费难、缴费难等一系列问题。在万物互联时代下&#xff0c;物联网技术迅速发展&#xff0c;智能水电联控云…

Laya3.0 调用第三方js的方法

1.新建一个js文件&#xff0c;例如&#xff1a;SuanShi.js // 暴露类到全局作用域 ; window.SuanShi window.suan {}; (function (suan) {class JiSuan {constructor() {}static computeExpression(a, b) {return this.jia(a, b);}static jia(a, b) {return a b;}}suan.JiS…

TiDB v7.5.3 发版,听说升级后又可以躺平两年

众所周知 TiDB 运维很稳、升级丝滑&#xff0c;8 月 5 日&#xff0c;TiDB v7.5.3 发版&#xff0c;作为 TiDB v7 系列的最新长期支持版本&#xff0c;有升级需求的小伙伴可以安排起来了。 TiDB 7.5.3 发版说明 兼容性&#xff1a;新增系统表 INFORMATION_SCHEMA.KEYWORDS 用来…

打造成功的知识付费平台:从技术到内容的全面解析

在现代Web开发中&#xff0c;RESTful API是一种常用的接口设计风格。它使用HTTP协议&#xff0c;允许客户端与服务器之间进行数据交互。本文将通过一个简单的例子&#xff0c;介绍如何使用Python和Flask框架构建一个RESTful API。 一、准备工作 首先&#xff0c;我们需要安装…

Github 2024-08-06 Python开源项目日报 Top10

根据Github Trendings的统计,今日(2024-08-06统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目10JavaScript项目1系统设计指南 创建周期:2507 天开发语言:Python协议类型:OtherStar数量:241693 个Fork数量:42010 次关注人数…

代码随想录算法训练营day35:动态规划03:背包问题:0-1背包;416. 分割等和子集

背包问题理论 主要需要掌握&#xff1a; 物品个数上不同&#xff01;&#xff01;&#xff01; 0-1背包&#xff1a;n种物品 每种物品只有一个——只考虑每个物品放与不放 完全背包&#xff1a;n种物品 每种物品有无数个 多重背包&#xff1a;n种物品 每种物品个数各不相同…

Arch Linux-0-电脑安装Arch Linux系统-原Windows转Arch Linux

文章目录 一、使用U盘制作安装镜像1.1 下载并验证iso文件1.1.1 方案一&#xff1a;使用.torrent下载iso文件&#xff08;1&#xff09;下载.torrent文件&#xff08;2&#xff09;选取可以用的工具qbittorrent 1.1.2 方案二&#xff1a;国内镜像站下载&#xff08;推荐&#xf…

轻闪PDF v2.14.9 解锁版下载与安装教程 (全能PDF转换器)

前言 轻闪PDF(原傲软PDF编辑软件)是一款操作简单的全能PDF转换器,轻松实现PDF转换为Word,Excel或其他格式,以及PDF压缩,合并和图片文字识别OCR等功能.这款pdf编辑转换软件几乎支持所有常见文档格式,一键完成PDF与其他文档互相转换,并含有PDF合并,压缩,图片文字识别OCR等增值功…

Linux中的无人值守安装脚本Kickstart

目录 一.kickstart自动安装脚本的作用 在企业中安装多台操作系统时面临的问题 如何解决以上问题&#xff1f; 二.实验环境 三.kickstart自动安装脚本的制作 通过模板生成kickstart文件 1.安装图形化生成kickstart自动安装脚本的工具 2.图形化工具配置流程 3.配置文件详…

如何有效开展产业链招商?

产业链招商是一种以产业大数据为依托、以产业链图谱为基础、以产业链分析为核心、以完善产业链结构为目标的招商引资方式。相比于传统招商模式&#xff0c;产业链招商比拼的并不是土地、政策优惠&#xff0c;而是以产业链分析为核心&#xff0c;诊断区域产业链结构及长短板&…

springboot书店销售管理系统-计算机毕业设计源码09304

摘要 随着互联网的普及和发展&#xff0c;线上书店越来越受到人们的欢迎。为了更好地管理书店的销售活动&#xff0c;提高用户体验&#xff0c;开发一个基于Springboot的书店销售管理系统是至关重要的。这种系统可以帮助书店管理员更高效地管理书籍、订单和用户信息&#xff0c…

SpringBoot基础 第一天

SpringBoot配置的文件名是固定的&#xff1a;application.yml application.properties YAML:以数据为中心 比Json xml更适合做配置文件 YAML语法: 1 字面量:普通值(字符串 布尔值 数字) (1) k: v (2) " "不会转义 会转义 2 对象&#xff0c;map(属性和值) (1)…

kettle从入门到精通 第八十四课 ETL之kettle kettle中Get data from XML使用实战教程

场景&#xff1a;解析xml文件或者内容解析出其中某些字段。 本来想着这个步骤使用起来比较简单&#xff0c;就没有梳理成文&#xff0c;结果群里的小伙伴为了使用这个步骤折腾了一下午。故有了此文。 在开始学习之前我们一起来学习下xml命名空间的相关知识&#xff0c;为下文展…

rem适配与vw适配

rem适配与vw适配 1.rem适配1.1原理1.2步骤1.3.1技术方案一1.3.2技术方案二 2.vw适配2.1原理2.2计算 3.rem适配与vw适配的优缺点 1.rem适配 1.1原理 rem&#xff08;根em&#xff09;是基于根元素&#xff08;即HTML元素&#xff09;的字体大小的长度单位。当根元素的字体大小…

【数据结构与算法】链栈(恋战)

链栈 一.链栈的原理二.结构三.初始化四.是否为空或满1.空2.满 五.入栈六.遍历栈七.出栈八.获取栈顶元素 一.链栈的原理 我们上节课用的数组来实现,现在我们用链式存储来实现,其实跟链队列基本一样,只不过是出栈的位置不一样而已. 二.结构 用一个头来当栈,每个节点作为链子. …

独角数卡支付后显示待支付问题

我这边碰到的是因为上线前测试未修改&#xff0c;看图片&#xff1a; 希望对你有帮助