Uitableview iOS 7-如何在表视图中就地显示日期选择器?
在WWDC 2013视频中,苹果建议在iOS 7的表格视图中显示选择器。如何在表格视图单元格之间插入视图并设置其动画 如下所示,从Apple日历应用程序:Uitableview iOS 7-如何在表视图中就地显示日期选择器?,uitableview,swift,ios7,uidatepicker,datecell,Uitableview,Swift,Ios7,Uidatepicker,Datecell,在WWDC 2013视频中,苹果建议在iOS 7的表格视图中显示选择器。如何在表格视图单元格之间插入视图并设置其动画 如下所示,从Apple日历应用程序: 通过iOS7,苹果发布了示例代码DateCell 演示表格单元格中日期对象的格式化显示,以及使用UIDatePicker编辑这些值。 作为此表的委托,示例使用方法“DidSelectRowatineXpath”打开UIDatePicker控件 对于iOS 6.x及更早版本,UIViewAnimation用于在屏幕上上上下滑动UIDatePi
通过iOS7,苹果发布了示例代码
DateCell
演示表格单元格中日期对象的格式化显示,以及使用UIDatePicker编辑这些值。
作为此表的委托,示例使用方法“DidSelectRowatineXpath”打开UIDatePicker控件
对于iOS 6.x及更早版本,UIViewAnimation用于在屏幕上上上下滑动UIDatePicker。对于iOS 7.x,UIDatePicker被在线添加到表视图中
UIDatePicker的操作方法将直接设置自定义表单元格的NSDate属性。此外,此示例还显示了如何使用NSDateFormatter类实现自定义单元格的日期格式外观
您可以在此处下载示例代码:。您可以使用我之前给出的以下答案,或者使用我在Swift中创建的新类,使此任务更简单、更清晰:
我发现苹果提供的代码在以下几个方面存在问题:
- 不能使用静态tableView,因为它们使用的是tableView:CellForRowatineXpath方法
- 如果在最后一个日期选择器单元格下没有其他行,代码将崩溃
- (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];
}];
}
}
如果在同一个表中有多个日期/时间选择器,我会相应地在单击上设置标志并重新加载相应的行。我发现我可以保留我的静态表,使用更少的代码,并且更容易理解正在发生的事情。使用故事板和静态表,我能够使用以下代码实现相同的结果。这是一个很好的解决方案,因为如果您有许多形状奇怪的单元格,或者希望有多个动态显示/隐藏的单元格,那么这段代码仍然有效
@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];
}
我已经从Apple获取了DateCell源代码,并删除了脚本文件 如果您想要一个没有故事板的,请查看:
我制作了自己的自定义视图控制器,以简化在tableview中内联添加内联选择器的过程。您只需将其子类化并遵循一些简单的规则,它就可以处理日期选择器表示 您可以在这里找到它,以及演示如何使用它的示例项目:
我找到了苹果datecell示例中一个缺陷的答案,其中必须在最后一个datecell下面有一行,否则会出现错误。在CellForRowAtIndexPath方法中,将ItemData行替换为
NSArray *itemsArray = [self.dataArray objectAtIndex:indexPath.section];
NSDictionary *itemData = nil;
if(![indexPath isEqual:self.datePickerIndexPath])
itemData = [itemsArray objectAtIndex:modelRow];
在替换了示例代码之后,我现在可以显示一个datePicker单元格,而不必在其下面显示单元格
我刚刚加入了stackoverflow,所以如果这是在错误的地方或其他地方,我道歉。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];
}];
}
//将数据返回给委托:任何一种方法都可以,尽管传回对象可能更有效
//[_所选代表图像:currentRecord.image with title:currentRecord.title with creator:currentRecord.creator];
//[_代表动物选择:currentRecord];
如果(indexPath.section==1&&indexPath.row==0){//这是选择器单元格上方的我的日期单元格
editingStartTime=!editingStartTime;
[UIView animateWithDuration:.4个动画:^{
整数高度=0;
如果(编辑开始时间){
高度=162;
}
UITableViewCell*temp=[tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:1第1节:1]];
[temp setFrame:CGRectMake(temp.frame.origin.x、temp.frame.origin.y、temp.frame.size.width、height)];
对于(int x=2;x<[tableView numberOfSections];x++){
对于(int y=0;y<[表视图行数部分:x];y++){
UITableViewCell*temp=[tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:y目录:x]];
int y_坐标=温度框架原点y-162;
如果(编辑开始时间){
y_坐标=温度帧原点y+162;
}
[温度设置框:CGRectMake(温度框原点x、y坐标、温度框尺寸宽度、温度框尺寸高度)];
}
}
}完成:^(布尔完成){
[self.tableView重载数据];
}];
}
这方面最好的教程之一是。基本上,这里我使用静态表视图单元格并实现一些附加方法。我用Xamarin和C#来做这个:
您必须激活剪辑子视图
设置高度:
public override float GetHeightForRow (UITableView tableView, NSIndexPath indexPath)
{
if (indexPath.Row == 4) {
return (datePickerIsShowing) ? 206f : 0.0f;
}
return base.GetHeightForRow(tableView,indexPath);
}
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;
}
);
}
而不是类变量:private bool datePickerIsShowing=false代码>
显示日期选择器:
public override float GetHeightForRow (UITableView tableView, NSIndexPath indexPath)
{
if (indexPath.Row == 4) {
return (datePickerIsShowing) ? 206f : 0.0f;
}
return base.GetHeightForRow(tableView,indexPath);
}
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 float GetHeightForRow (UITableView tableView, NSIndexPath indexPath)
{
if (indexPath.Row == 4) {
return (datePickerIsShowing) ? 206f : 0.0f;
}
return base.GetHeightForRow(tableView,indexPath);
}
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);
}
除了前面的答案之外
我尝试了@datinc和@Aaron Bratcher两种解决方案,它们都很有效,但在分组静态表视图中动画不是很清晰
在玩了一点之后,我得到了这段代码,它对我来说是干净和伟大的-
- (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在iOS 8中不使用动画也能正常工作
- (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");
}
-(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;
}
}