如何使用Swift 5在iOS中实现内联日期选择器

我们已经了解了iOS默认的日历应用及其外观。 让我们看看如何像日历应用一样从头开始实现内联日期选择器。 这是典型日历应用程序中的添加事件屏幕的外观。

我希望阅读此博客的开发人员具备使用Xcode创建新项目的能力。 因此,让我们深入研究实际的实现。

我创建了一个分组表视图,并使用setupTableView()方法设置了它的数据源和委托,如下所示。

  func setupTableView(){ta​​bleView = UITableView(frame:CGRect(x:0,y:0,width:view.bounds.size.width,height:view.bounds.size.height),style:.grouped) 
view.addSubview(tableView)tableView.register(UINib(nibName:DateTableViewCell.nibName(),bundle:nil),forCellReuseIdentifier:DateTableViewCell.reuseIdentifier())tableView.register(UINib(nibName:DatePickerTableViewCell.nibName(),bundle:nil ),forCellReuseIdentifier:DatePickerTableViewCell.reuseIdentifier())tableView.dataSource = selftableView.delegate = self}

我们已经声明了两个主要变量。 一个,我们声明了一个字符串数组,其中包含要添加的日期选择器标题文本的数量。 我们有datePickerIndexPath,它包含表视图中当前显示的日期选择器的indexPath。

  var inputTexts:[String] = [“开始日期”,“结束日期”,“另一个日期”] 
var datePickerIndexPath:IndexPath?

现在我们来看主体部分,数据源和委托方法。 在行数方法中,当未显示日期选择器时,我们返回inputTexts数组的计数。 如果日期选择器当前可见,我们为此添加一个额外的单元格。

  func tableView(_ tableView:UITableView,numberOfRowsInSection部分:Int)-> Int {//如果datePicker已经存在,如果datePickerIndexPath!= nil {return inputTexts.count + 1}否则,我们为此添加一个额外的单元格。{返回inputTexts。 count}} func tableView(_ tableView:UITableView,cellForRowAt indexPath:IndexPath)-> UITableViewCell {if datePickerIndexPath == indexPath {让datePickerCell = tableView.dequeueReusableCell(withIdentifier:DatePickerTableViewCell.reuseIdentifier())为!  DatePickerTableViewCell datePickerCell.updateCell(date:inputDates [indexPath.row-1],indexPath:indexPath)datePickerCell.delegate =自返回datePickerCell}否则{让dateCell = tableView.dequeueReusableCell(withIdentifier:DateTableViewCell.reuseIdentifier())为!  DateTableViewCell dateCell.updateText(文本:inputTexts [indexPath.row],日期:inputDates [indexPath.row])返回dateCell}} 

在cellForRow方法中,我们将返回两种类型的单元格,一个日期选择器单元格和一个日期文本单元格,该单元格显示日期值以及标题文本。 我们首先检查当前indexPath是否等于显示datepicker的datePickerIndexPath。 在这种情况下,我们返回日期选择器单元格,在其他情况下,我们返回日期单元格以显示日期及其标题。

  func tableView(_ tableView:UITableView,didSelectRowAt indexPath:IndexPath){tableView.beginUpdates()//如果让datePickerIndexPath = datePickerIndexPath,datePickerIndexPath.row-1 == indexPath.row {tableView.deleteRows(at:[datePickerIndexPath], :.fade)self.datePickerIndexPath = nil}其他{ 
// 2 if let datePickerIndexPath = datePickerIndexPath {tableView.deleteRows(at:[datePickerIndexPath],with:.fade)} datePickerIndexPath = indexPathToInsertDatePicker(indexPath:indexPath)tableView.insertRows(at:[datePickerIndexPath!],带有.fade)tableView .deselectRow(at:indexPath,animation:true)} tableView.endUpdates()}

首先,我们需要在tableView的begin和end更新方法中进行所有行的插入和删除操作。

  1. 在第一种情况下,如果datePickerIndexPath不为nil(当前显示日期选择器),并且如果所选索引路径等于当前日期选择器单元格之前的第一行,那么我们需要隐藏显示的日期选择器单元格。 因此,我们删除datePicker indexPath处的行,并将datePickerIndexPath变量设置为nil。
  2. 我们首先删除现有的显示日期选择器。 然后我们计算下一个datePicker应该显示在哪里。 然后使用计算出的indexPath重新插入datePicker单元格。 方法indexPathToInsertDatePicker(indexPath:IndexPath)如下所示。
  func indexPathToInsertDatePicker(indexPath:IndexPath)-> IndexPath {如果让datePickerIndexPath = datePickerIndexPath,datePickerIndexPath.row <indexPath.row {return indexPath}否则{return IndexPath(row:indexPath.row + 1,section:indexPath.section)}} 

在这里,我们获取用户选择的索引路径,如果当前显示的日期选择器位于用户选择的索引路径上方,则必须在用户选择的索引路径中插入datePicker。

在其他情况下,我们将增加索引路径的行数并返回它。

最终,当我们运行该应用程序时,它看起来如下所示。 您可以在https://github.com/rajtharan-g/InlineDatePicker获取完整的源代码。