就像这样,来自苹果日历应用程序的图片:
![In-place date picker](https://istack.dev59.com/hUDZK.webp)
iOS7发布后,苹果公司提供了样例代码DateCell
。
演示了日期对象在表格单元中的格式化显示以及使用UIDatePicker编辑这些值的方法。 该示例作为此表格的代理,使用方法“didSelectRowAtIndexPath”打开UIDatePicker控件。
对于iOS 6.x及更早版本,UIViewAnimation用于将UIDatePicker向上滑动到屏幕上并向下移出屏幕。对于iOS 7.x,则在表视图中内联添加UIDatePicker。
UIDatePicker的操作方法将直接设置自定义表格单元的NSDate属性。此外,此示例展示了如何使用NSDateFormatter类实现自定义单元格的日期格式化外观。
您可以从此处下载样例代码:DateCell。
您可以使用我之前下面给出的答案,或者使用我写的这个Swift新类,使这个任务变得更加简单和清晰:https://github.com/AaronBratcher/TableViewHelper
我发现苹果提供的代码有几个问题:
对于静态单元格表格,我将我的日期选择器单元格定义在日期显示单元格下面,并设置一个标志来标识我是否正在编辑它。如果我正在编辑,我将返回适当的单元格高度,否则我将返回零高度的单元格。
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 0 && indexPath.row == 2) { // this is my picker cell
if (editingStartTime) {
return 219;
} else {
return 0;
}
} else {
return self.tableView.rowHeight;
}
}
当单击显示日期的行时,我会更改标记并执行更新动画以显示选择器。
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 0 && indexPath.row == 1) { // this is my date cell above the picker cell
editingStartTime = !editingStartTime;
[UIView animateWithDuration:.4 animations:^{
[self.tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:2 inSection:0]] withRowAnimation:UITableViewRowAnimationFade];
[self.tableView reloadData];
}];
}
}
如果在同一个表中有多个日期/时间选择器,我会根据点击设置标志并重新加载适当的行。我发现可以保持静态表格,使用更少的代码,并且更容易理解正在发生的事情。
使用storyboard和静态表格,我能够使用以下代码实现相同的结果。这是一个很好的解决方案,因为如果你有许多奇怪形状的单元格或者想要动态显示/隐藏多个单元格,这个代码仍然可以工作。
@interface StaticTableViewController: UITableViewController
@property (weak, nonatomic) IBOutlet UITableViewCell *dateTitleCell; // cell that will open the date picker. This is linked from the story board
@property (nonatomic, assign, getter = isDateOpen) BOOL dateOpen;
@end
@implementation StaticTableViewController
-(CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
// This is the index path of the date picker cell in the static table
if (indexPath.section == 1 && indexPath.row == 1 && !self.isDateOpen){
return 0;
}
return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell* cell = [tableView cellForRowAtIndexPath:indexPath];
[tableView beginUpdates];
if (cell == self.dateTitleCell){
self.dateOpen = !self.isDateOpen;
}
[tableView reloadData];
[self.tableView endUpdates];
}
[tableView reloadData];
调用并非必需。目前它会禁用行选择,但最好像这样取消选择行:
[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES];
- Barry Haanstra这方面最好的教程之一是iOS 7 in-line UIDatePicker – Part 2。基本上我使用静态表格视图单元并实现了一些额外的方法。我使用Xamarin和C#进行了编写:
您需要激活Clip Subviews
。
设置高度:
public override float GetHeightForRow (UITableView tableView, NSIndexPath indexPath)
{
if (indexPath.Row == 4) {
return (datePickerIsShowing) ? 206f : 0.0f;
}
return base.GetHeightForRow(tableView,indexPath);
}
比类变量更好的是:private bool datePickerIsShowing = false;
显示日期选择器:
private void showDatePickerCell(){
datePickerIsShowing = true;
this.TableView.BeginUpdates ();
this.TableView.EndUpdates ();
this.datePicker.Hidden = false;
this.datePicker.Alpha = 0.0f;
UIView.Animate (0.25, animation:
() => {
this.datePicker.Alpha = 1.0f;
}
);
}
隐藏日期选择器:
private void hideDatePickerCell(){
datePickerIsShowing = false;
this.TableView.BeginUpdates ();
this.TableView.EndUpdates ();
UIView.Animate (0.25,
animation: () => {
this.datePicker.Alpha = 0.0f;
},
completion: () => {
this.datePicker.Hidden = true;
}
);
}
同时调用这些函数:
public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
if (indexPath.Row == 3) {
if (datePickerIsShowing) {
hideDatePickerCell ();
} else {
showDatePickerCell ();
}
}
this.TableView.DeselectRow (indexPath, true);
}
UIPickerView
替换UIDatePicker
。我尝试了一些方法,并能够在每个单元格上显示pickerView
,但它不会随着每个单元格的更新而更新。我已经在这里发布了我的问题和代码。请看一下,如果您能为我提供解决方案,那将非常友善。 - Mughees MusaddiqUIPickerView
替换了UIDatePicker
,但出现了一些问题。1.当您打开UIPickerView
并滚动表格时,它会崩溃。2.当值被分配给顶部行的详细标签时,它会自动将该值分配给表格底部行的UILabel
详细信息。这是我的代码。 - Mughees Musaddiq在之前的回答中,我尝试了@datinc和@Aaron Bratcher的解决方案,两者都非常好用,但在分组静态tableView中动画效果不太流畅。
经过一些尝试后,我得到了以下代码,对我来说运行得很流畅:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 0 && indexPath.row == 1)
{
if (self.isPickerOpened)
{
return 162;
}
else
{
return 0;
}
}
else
{
return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 0 && indexPath.row == 0) {
[tableView beginUpdates];
self.isPickerOpened = ! self.isPickerOpened;
[super tableView:tableView heightForRowAtIndexPath:indexPath];
[self.tableView endUpdates];
}
}
主要的变化是使用 -
[super tableView:tableView heightForRowAtIndexPath:indexPath];
为了更新行,这样表格的其余部分和单元格都不会动画。
希望能对某人有所帮助。
Shani
Aaron Bratcher 的答案在使用多个部分时存在问题。动画有点卡顿,而且它不能很好地下滑到下一部分。为了解决这个问题,我遍历了下一个部分的行,并将它们向下平移与日期选择器的高度相同的量。
我编辑了 didSelectRowAtIndexPath 方法:
// Return Data to delegate: either way is fine, although passing back the object may be more efficient
// [_delegate imageSelected:currentRecord.image withTitle:currentRecord.title withCreator:currentRecord.creator];
// [_delegate animalSelected:currentRecord];
if (indexPath.section == 1 && indexPath.row == 0) { // this is my date cell above the picker cell
editingStartTime = !editingStartTime;
[UIView animateWithDuration:.4 animations:^{
int height = 0;
if (editingStartTime) {
height = 162;
}
UITableViewCell* temp = [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:1]];
[temp setFrame:CGRectMake(temp.frame.origin.x, temp.frame.origin.y, temp.frame.size.width, height)];
for (int x = 2; x < [tableView numberOfSections]; x++) {
for (int y = 0; y < [tableView numberOfRowsInSection:x]; y++) {
UITableViewCell* temp = [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:y inSection:x]];
int y_coord = temp.frame.origin.y-162;
if (editingStartTime) {
y_coord = temp.frame.origin.y+162;
}
[temp setFrame:CGRectMake(temp.frame.origin.x, y_coord, temp.frame.size.width, temp.frame.size.height)];
}
}
}completion:^(BOOL finished){
[self.tableView reloadData];
}];
}
NSArray *itemsArray = [self.dataArray objectAtIndex:indexPath.section];
NSDictionary *itemData = nil;
if(![indexPath isEqual:self.datePickerIndexPath])
itemData = [itemsArray objectAtIndex:modelRow];
在替换示例代码之后,我现在可以显示一个没有下面单元格的datePicker单元格。
我刚加入stackoverflow,如果这个问题不应该在这里或者在其他地方,请见谅。
在之前的答案和@Aaron Bratcher的解决方案基础上...
iOS 9以来,我的动画变得卡顿,表格加载时间过长,让人感到烦恼。我发现是由于从storyboard中加载日期选择器太慢导致的。通过以编程方式添加选择器而不是在storyboard中添加选择器,可以提高加载性能,同时也使动画更加流畅。
从storyboard中移除日期选择器并保留一个空单元格,在其中设置与之前答案相同的高度,然后在viewDidLoad中调用初始化函数:
- (void)initialiseDatePickers
{
self.isEditingStartTime = NO;
self.startTimePickerCell.clipsToBounds = YES;
UIDatePicker *startTimePicker = [[UIDatePicker alloc] init];
[startTimePicker addTarget:self action:@selector(startTimePickerChanged:) forControlEvents:UIControlEventValueChanged];
[self.startTimePickerCell addSubview:startTimePicker];
}
然后实现动作,例如:
- (IBAction)startTimePickerChanged:(id)sender
{
NSLog(@"start time picker changed");
}
这比之前更快地加载了表格。您还可以从didSelectRowAtIndexPath
中删除动画行,因为即使没有该行,它也可以平稳地进行动画(可能因人而异)。
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 0 && indexPath.row == 1) { // this is my date cell above the picker cell
editingStartTime = !editingStartTime;
}
}