TableView在编辑模式下, 可以使用排序控件对cell进行排序(移动cell, 从一个位置移动到另一个位置). 如图7-1所示, 使用reordering控件移动cell.

和其他编辑操作类似, 对cell重排序时, TableView会发送一系列消息给到DataSource和delegate对象, 前提是, DataSource和delegate必须实现相应的方法. 通过这些方法, 可以控制那些cell可以显示排序控件, 接下来的内容就围绕cell的排序来讲解.
当一个cell重定位时会发生什么
TableView的delegate可以通过在方法tableView:cellForRowAtIndexPath:
中, 设置cell的属性showsReorderControl
为YES来控制cell是否可以移动. 另外还需要配合DataSource中的tableView:moveRowAtIndexPath:toIndexPath:
方法使用.
注意:使用
UITableViewController
来管理TableView是, 点击edit button时会自动调用TableView的setEditing:animated:
方法来使TableView进入编辑模式, 所以如果你使用自定义的viewController来管理TableView, 你需要自己实现这一个功能, 前面文章有代码范例.
TableView从进入编辑模式到进行cell的移动这一过程会发送一系列方法的调用, 下图7-2展示了这一过程.

上面的动作:
- tableView发送
tableView:canMoveRowAtIndexPath:
到delegate, 在该方法中, delegate可以确定哪些cell可以移动. - 用户开始拖动cell, 当拖动合适的位置, 下面的cell会往下移动
- 到cell拖动到目的地后, TableView会发送
tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath:
消息给delegate, 在该方法中, delegate可以拒绝当前的目的地, 而提供一个其他位置作为重排序cell的目的地. - 最后TableView发送
tableView:moveRowAtIndexPath:toIndexPath:
消息给到DataSource, 告诉DataSource某个cell移动了, 在该方法中, DataSource需要更新数据模型数组, 将相应的item移动目的位置.
一个cell移动的例子
上面讲了cell重排序的原理, 下面使用代码来展示cell的移动.
代码7-1中, 展示tableView:canMoveRowAtIndexPath:
的实现, 排除TableView中第一行.
代码清单7-1 禁止一下行进行排序
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row == 0) // Don't move the first row
return NO;
return YES;
}
当用户停止拖动cell后, cell会飘入目的位置, 此时会发送tableView:moveRowAtIndexPath:toIndexPath:
消息给DataSource. 代码7-2展示了该方法的实现
代码清单7-2 更新DataSource
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath {
NSString *stringToMove = [self.reorderingRows objectAtIndex:sourceIndexPath.row];
[self.reorderingRows removeObjectAtIndex:sourceIndexPath.row];
[self.reorderingRows insertObject:stringToMove atIndex:destinationIndexPath.row];
}
delegate可以通过tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath:
方法来更改cell的目的位置. 代码7-3实现该方法来阻止将cell移动到同一组或移动到本组的最后一行.
代码清单7-3 限制cell移动的范围
- (NSIndexPath *)tableView:(UITableView *)tableView
targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath
toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath {
NSDictionary *section = [data objectAtIndex:sourceIndexPath.section];
NSUInteger sectionCount = [[section valueForKey:@"content"] count];
if (sourceIndexPath.section != proposedDestinationIndexPath.section) {
NSUInteger rowInSourceSection =
(sourceIndexPath.section > proposedDestinationIndexPath.section) ?
0 : sectionCount - 1;
return [NSIndexPath indexPathForRow:rowInSourceSection inSection:sourceIndexPath.section];
} else if (proposedDestinationIndexPath.row >= sectionCount) {
return [NSIndexPath indexPathForRow:sectionCount - 1 inSection:sourceIndexPath.section];
}
// Allow the proposed destination.
return proposedDestinationIndexPath;
}
网友评论