使用内置 iOS 日历以编程方式快速创建日历/访问

Posted

技术标签:

【中文标题】使用内置 iOS 日历以编程方式快速创建日历/访问【英文标题】:Create calendar programmatically in swift/accessing with built-in iOS calendar 【发布时间】:2018-09-01 10:25:02 【问题描述】:

我正在尝试在我的应用程序中创建一个自定义日历,并找到了一个关于构建自定义日历 (https://github.com/patchthecode/JTAppleCalendar) 的教程,我在一个新项目中遵循了该教程并且它有效。但是,本教程使用情节提要,而我的应用程序没有。因此,我尝试使用子视图将故事板 UI 设置迁移到代码中,但没有成功。

该功能的目的是将商务会议存储在日历中,我愿意放弃自定义日历功能并访问 ios 日历,但我不确定如何执行此操作。

我尝试运行时遇到的错误是线程 1:致命错误:在 view.addSubview(calendarView) 处展开可选值时意外发现 nil

该应用程序使用 TabBarController 进行导航,Organizer 是我的选项卡之一。

任何有关使自定义日历工作的帮助,或者我可以使用什么代码来访问 iOS 日历,我们将不胜感激。

代码如下。

import UIKit
import JTAppleCalendar
import EventKit
class Organiser: UIViewController 

var calendarView: JTAppleCalendarView!
var year: UILabel!
var month: UILabel!

let outsideMonthColour = UIColor.white
let monthColour = UIColor.black
let selectedMonthColour = UIColor.red
let currentDateSelectedColour = UIColor.blue


let formatter = DateFormatter()

override func viewDidLoad() 
    super.viewDidLoad()

    view.addSubview(calendarView)
    view.addSubview(year)
    view.addSubview(month)


    calendarView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive=true
    calendarView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive=true
    calendarView.heightAnchor.constraint(equalToConstant: 200)
    calendarView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: -30)

    month.bottomAnchor.constraint(equalTo: calendarView.topAnchor, constant: 25)
    month.leftAnchor.constraint(equalTo: calendarView.leftAnchor, constant: 0)


    year.bottomAnchor.constraint(equalTo: month.topAnchor, constant: 25)
    year.leftAnchor.constraint(equalTo: month.leftAnchor, constant: 25)

    calendarView.translatesAutoresizingMaskIntoConstraints = false
    month.translatesAutoresizingMaskIntoConstraints = false
    year.translatesAutoresizingMaskIntoConstraints = false

    // Do any additional setup after loading the view, typically from a nib.



//setup calendar cells
func setupCalendarView()
    calendarView.minimumLineSpacing = 0
    calendarView.minimumInteritemSpacing = 0

    calendarView.visibleDates  visibleDates in
        self.setupViewsOfCalendar(from: visibleDates)
    


//setup selected cell text colour function
func handleCellTextColour(view: JTAppleCell?, cellState: CellState)
    guard let validCell = view as? CustomCell else  return 

    if cellState.isSelected 
        validCell.dateLabel?.textColor = currentDateSelectedColour
     else 
        if cellState.dateBelongsTo == .thisMonth 
            validCell.dateLabel?.textColor = monthColour
         else 
            validCell.dateLabel?.textColor = outsideMonthColour
        
    



//setup selected cell highlight function
func handleCellSelected(view: JTAppleCell?, cellState: CellState)
    guard let validCell = view as? CustomCell else  return 

    if cellState.isSelected 
        validCell.selectedView?.isHidden = false
     else 
        validCell.selectedView?.isHidden = true
    



override func didReceiveMemoryWarning() 
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.






extension Organiser: JTAppleCalendarViewDataSource
func configureCalendar(_ calendar: JTAppleCalendarView) -> ConfigurationParameters 
    formatter.dateFormat = "yyyy mm dd"
    formatter.timeZone = Calendar.current.timeZone
    formatter.locale = Calendar.current.locale

    let startDate = formatter.date(from: "2017 01 01")
    let endDate = formatter.date(from: "2018 12 31")

    let parameters = ConfigurationParameters(startDate: startDate!, endDate: endDate!)
    return parameters





extension Organiser: JTAppleCalendarViewDelegate

func calendar(_ calendar: JTAppleCalendarView, willDisplay cell: JTAppleCell, forItemAt date: Date, cellState: CellState, indexPath: IndexPath) 
    let myCustomCell = calendar.dequeueReusableJTAppleCell(withReuseIdentifier: "CustomCell", for: indexPath) as! CustomCell
    myCustomCell.dateLabel?.text = cellState.text

    handleCellSelected(view: cell, cellState: cellState)
    handleCellTextColour(view: cell, cellState: cellState)
    return ()


func calendar(_ calendar: JTAppleCalendarView, cellForItemAt date: Date, cellState: CellState, indexPath: IndexPath) -> JTAppleCell 
    let myCustomCell = calendar.dequeueReusableJTAppleCell(withReuseIdentifier: "CustomCell", for: indexPath) as! CustomCell
    self.calendar(calendar, willDisplay: myCustomCell, forItemAt: date, cellState: cellState, indexPath: indexPath)
    myCustomCell.dateLabel?.text = cellState.text
    return myCustomCell

//function for handling interface changes when cell selected
func calendar(_ calendar: JTAppleCalendarView, didSelectDate date: Date, cell: JTAppleCell?, cellState: CellState) 
    handleCellSelected(view: cell, cellState: cellState)
    handleCellTextColour(view: cell, cellState: cellState)

//function for handling interface changes when cell deselected selected
func calendar(_ calendar: JTAppleCalendarView, didDeselectDate date: Date, cell: JTAppleCell?, cellState: CellState) 
    handleCellSelected(view: cell, cellState: cellState)
    handleCellTextColour(view: cell, cellState: cellState)

//function so that month and year show when calendar loads
func setupViewsOfCalendar(from visibleDates: DateSegmentInfo)
    let date = visibleDates.monthDates.first!.date

    self.formatter.dateFormat = "yyyy"
    self.year.text = self.formatter.string(from: date)

    self.formatter.dateFormat = "MMMM"
    self.month.text = self.formatter.string(from: date)


//function to change month when calendar scrolled
func calendar(_ calendar: JTAppleCalendarView, didScrollToDateSegmentWith visibleDates: DateSegmentInfo) 
    let date = visibleDates.monthDates.first!.date

    formatter.dateFormat = "yyyy"
    year.text = formatter.string(from: date)

    formatter.dateFormat = "MMMM"
    month.text = formatter.string(from: date)



【问题讨论】:

在您的 xib 中,您是否连接了 FTAppleCalendarView 和 UILabel?如果您已连接,则不会发生崩溃。 感谢您的帮助,但我正在尝试仅使用代码来构建我的应用程序 - 而不是故事板或 xib 文件 【参考方案1】:

您遇到的崩溃是因为您没有初始化 JTAppleCalendarView,因此当您尝试将其添加为子视图时,它是 nil。编译器不会抱怨,因为您在声明中强制解包。

替换

var calendarView: JTAppleCalendarView!

let calendarView = JTAppleCalendarView()

请注意,当您尝试将年份和月份标签添加为子视图时,您在接下来的两行中也会因同样的原因而崩溃。

您可以将它们的声明替换为:

let year = UILabel()
let month = UILabel()

【讨论】:

谢谢!这是有道理的,我现在可以构建和运行有任何错误的应用程序,但是当我的应用程序运行时,视图控制器“组织者”仍然是空白的。我还缺少什么让日历可见吗? 我已经编辑了我的约束以包括 translatesAutoresizingMaskIntoConstraints 并添加 calendarView 约束,但它仍然没有显示 约束代码有问题。 .isActive=true 只设置在前两个。乘数设置为 -30 表示宽度计算为 view.width * -30。因此,如果视图宽度为 100pt,则日历宽度将为 -3000。您也没有月份和年份标签的宽度/高度限制【参考方案2】:

您正在使用“!”强制解开 JTAppleCalendar 的实例。因此,如果值为 nil,则在强制展开时,应用程序将崩溃。为避免同样的情况,您需要按照以下步骤操作。

第 1 步:您可以将对象库中的 UIView 添加到 xib 或情节提要中。

第 2 步:然后您需要在 Identity Inspector 中设置 JTAppleCalenderView,如下图所示。

然后您可以使用与您使用过的代码相同的代码,并且它不应该崩溃。

注意:您还需要在 UILabel 中添加相同的内容以避免 UILabel 崩溃。

【讨论】:

以上是关于使用内置 iOS 日历以编程方式快速创建日历/访问的主要内容,如果未能解决你的问题,请参考以下文章

使用 PhoneGap/jQuery Mobile 以编程方式在 iPhone/Android 日历中添加事件?

以编程方式在 iPhone 日历中添加自定义事件

iOS - 以编程方式将我们应用程序的自定义 URI 添加到存储在日历中的事件中

在 android 中以编程方式使用谷歌日历添加同步事件

iOS 内置日历应用程序如何与各种日历源同步?

如何以编程方式设置 iPhone 闹钟?