iOS TableView 编程指导(七)-行的排序

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


iOS TableView 编程指导(七)-行的排序_第1张图片
图7-1 对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展示了这一过程.


iOS TableView 编程指导(七)-行的排序_第2张图片
图7-2 移动cell的方法调用序列图

上面的动作:

  1. tableView发送tableView:canMoveRowAtIndexPath:到delegate, 在该方法中, delegate可以确定哪些cell可以移动.
  2. 用户开始拖动cell, 当拖动合适的位置, 下面的cell会往下移动
  3. 到cell拖动到目的地后, TableView会发送tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath:消息给delegate, 在该方法中, delegate可以拒绝当前的目的地, 而提供一个其他位置作为重排序cell的目的地.
  4. 最后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;
}

你可能感兴趣的:(iOS TableView 编程指导(七)-行的排序)