对 UITableView
的常见操作包括增加行、删除行和移动行等操作,效果图如下:
- NSBundle 指定 XIB
使用 NSBundle
类可以载入指定的 XIB 文件。该类是“应用程序包”和“应用程序包所包含的可执行文件”之间的接口,可以访问程序包中的某个文件。载入应用程序包中的某个 XIB 文件,示例代码如下:
- (UIView *)headerView {
if (!_headerView) { // 如果还没有载入 Headerview
// 载入 HeaderView.xib
[[NSBundle mainBundle] loadNibNamed:@"HeaderView"
owner:self
options:nil];
}
return _headerView;
}
PS: HeaderView
是 XIB 文件的名字 (没有后缀)
该方法使用了使用了延迟实例化,某些情况下,这种设计模式可以显著减少内存占用。
- editing 属性
UITableView
有一个名为 editing
的属性,若将 editing
属性设置为 YES
,UITableView
就会进入编辑模式(可以进行增删移动等操作)。示例代码:
- (IBAction)toggleEditingModel:(id)sender {
// 若已经处于编辑模式
if (self.editing) { // 或者 self.isEditing
[sender setTitle:@"Edit" forState:UIControlStateNormal];
[self setEditing:NO animated:YES]; //关闭编辑模式
} else {
[sender setTitle:@"Done" forState:UIControlStateNormal];
[self setEditing:YES animated:YES]; //开启编辑模式
}
}
- 增加行
示例代码:
- (IBAction)addNewItem:(id)sender {
// 创建 NSIndexPath 对象,代表的位置是:第一个表格段,最后一个表格行
NSInteger lastRow = [self.tableView numberOfRowsInSection:0];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:lastRow inSection:0];
// 将新行插入 UITableView 对象
[self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationTop];
}
+ indexPathForRow:inSection:
方法:
Returns an index-path object initialized with the indexes of a specific row and section in a table view.
这样写会抛出 NSInternalInconsistencyException
异常,详细信息:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'attempt to insert row 0 into section 0, but there are only 0 rows in section 0 after the update'
这是因为任何一个 UITableView
对象都要从其数据源获取需要显示的数据,数据源决定 UITableView
对象需要显示的函数。这样写只是增加了行数,并没有增加数据源,因此报错。
为此,添加表格行时,必须确保 UITableView
对象当前显示的行数与数据源提供的行数相同。示例代码如下:
- (IBAction)addNewItem:(id)sender {
// 创建新的 BNRItem 对象并将其加入到 BNRItemStore 对象
BNRItem *newItem = [[BNRItemStore sharedStore] createItem];
// 获取新创建的对象在 allItems 数组中的索引
NSInteger lastRow = [[[BNRItemStore sharedStore] allItems] indexOfObject:newItem];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:lastRow inSection:0];
// 将新行插入 UITableView 对象
[self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationTop];
}
- 删除行
示例代码:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) { // 如果 UITableView 对象请求确认的是删除操作
NSArray *items = [[BNRItemStore sharedStore] allItems];
BNRItem *item = items[indexPath.row];
[[BNRItemStore sharedStore] removeItem:item];
// 删除表格视图中的相应表格行
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
- tableView:commitEditingStyle:forRowAtIndexPath:
Asks the data source to commit the insertion or deletion of a specified row in the receiver.
/** 删除一行 */
- (void)removeItem:(BNRItem *)item {
[self.privateItems removeObjectIdenticalTo:item];
}
removeObjectIdenticalTo:
和removeObject:
的区别:
removeObject:
会枚举数组,向每一个对象发送isEqual:
消息。
removeObjectIdenticalTo:
不会比较对象所包含的数据,只会比较指向对象的指针。
删除一行时右边的确认按钮标题 (默认为 "Delete") 可以自定义。重写 tableView:titleForDeleteConfirmationButtonForRowAtIndexPath:
方法即可,示例代码如下:
- (NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath
{
return @"Remove";
}
- 移动行
示例代码:
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{
[[BNRItemStore sharedStore] moveItemAtIndex:sourceIndexPath.row
toIndex:destinationIndexPath.row];
}
- moveRowAtIndexPath:toIndexPath:
Moves the row at a specified location to a destination location.
/** 移动一行 */
- (void)moveItemAtIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex {
if (fromIndex == toIndex) {
return;
}
BNRItem *item = self.privateItems[fromIndex];
[self.privateItems removeObjectAtIndex:fromIndex];
[self.privateItems insertObject:item atIndex:toIndex];
}
代码地址:
https://github.com/Ranch2014/iOSProgramming4ed/tree/master/09-EditUITableView/Homepwner
《iOS编程(第4版)》 笔记
网友评论