iOS 关于UITableView Group移动的那些事儿(tableview section move)

来源:互联网 发布:网络播放平台 编辑:程序博客网 时间:2024/05/21 09:10

section的移动

github:https://github.com/Avanlanching/QJYTableViewSectionMove/tree/master/QJYTableViewSectionMove
具体的demo放在该路径下。
很多时候,我们都会遇到TableView cell 移动的问题,这个问题比较容易解决,apple官方给出了比较好的解决方案,iOS版的QQ也做了类似的方案。
这里分享一下以为大神的cell移动的方法,我也是从他的方法里面获取到的思路:http://blog.csdn.net/u012399689/article/details/45370567

在之前的项目里面有一个比较有趣的需求,在列表中去移动section,从而达到分组排序的效果。
这里与移动cell不同的是移动的过程中如何处理数据的问题。我这里是移动了section,在移动的同时还要保持结构完整。可以说,我在上面那位大神的基础上进行了改进。

- (void)longPressGestureRecognized:(UILongPressGestureRecognizer *)longPress {    UIGestureRecognizerState state = longPress.state;    CGPoint location = [longPress locationInView:self.tableView];    // 判断长按手势的坐标落在哪一个section上面,如果不想写这个代码,可以将长按手势添加在section上    NSIndexPath *indexPath = [self.tableView indexPathForSectionAtPoint:location numberOfSecton:self.dataArray.count];    // 这里是快照 我们拖动不是真正的UITableViewHeaderFooterView 而是一张快照    static UIView       *snapshot = nil;    // 记录section的初始的行号    static NSIndexPath  *initialLocation = nil;    switch (state) {        case UIGestureRecognizerStateBegan: {            if (indexPath) {                initialLocation = indexPath;                self.moveSection = [self.tableView headerViewForSection:indexPath.section];                // 创建section的一个快照                snapshot = [self customSnapshoFromView:self.moveSection];                // 添加快照至tableView中                __block CGPoint center = self.moveSection.center;                snapshot.center = center;                snapshot.alpha = 0.0;                [self.tableView addSubview:snapshot];                // 按下的瞬间执行动画 这里最终目的是为了隐藏选中的Section                [UIView animateWithDuration:0.25 animations:^{                    center.y = location.y;                    snapshot.center = center;                    // 稍微设置一下快照的样式                    snapshot.transform = CGAffineTransformMakeScale(1.05, 1.05);                    snapshot.alpha = 0.98;                    self.moveSection.alpha = 0.0;                } completion:^(BOOL finished) {                    self.moveSection.hidden = YES;                }];            }            break;        }        case UIGestureRecognizerStateChanged: {            // 保持位置数组存有前后两个坐标点            [self.locations addObject:[NSValue valueWithCGPoint:location]];            if (self.locations.count > 2) {                [self.locations removeObjectAtIndex:0];            }            // 移动快照            CGPoint center = snapshot.center;            center.y = location.y;            CGPoint firstPoint = [[self.locations firstObject] CGPointValue];            CGPoint lastPoint = [[self.locations lastObject] CGPointValue];            // 注意这里是中心点,而不是快照的frame.origin.x            CGFloat moveX = lastPoint.x - firstPoint.x;            center.x += moveX;            // 如果section的移动在有效范围执行动画            if (center.y + SECTION_HEIGHT / 2 <= self.tableView.contentSize.height && center.y - SECTION_HEIGHT / 2 >= 0) {                snapshot.center = center;                // 对比新的indexPath和初始的是否一致,                // 这里使用NSIndexPath是因为,在某些场景中可能出现垃圾数值,使用对象可以进行nil的判断                if (indexPath && ![indexPath isEqual:initialLocation]) {                    // 这里使用try 是为了避免数据源错误造成的崩溃,                    // 常规情况下OC比较少用 try catch,因为OC是动态语言一下野指针和空指针是在运行时才产生的                    @try {                        // 更新数组中的内容                        [self.dataArray exchangeObjectAtIndex:                         indexPath.section withObjectAtIndex:initialLocation.section];                        // 把section移动至指定行 这里是从API中找出来的方法,apple没有像处理cell那样给定了一个编辑模式的样式                        // 这里参考cell的移动                        /**                         *- (void)moveSection:(NSInteger)section toSection:(NSInteger)newSection;                         *                         *- (void)moveRowAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath;                         */                        [self.tableView moveSection:initialLocation.section toSection:indexPath.section];                        // 这里判断是否滚动了屏幕的顶部或者底部,这里是指相对坐标。                        [self scrollTableViewToTargetView:indexPath];                    } @catch (NSException *exception) {                        NSLog(@"row is error");                    } @finally {                        // 存储改变后indexPath的值,以便下次比较                        initialLocation = indexPath;                    }                } else {                    // 判断屏幕上的最上方一个和最下方一个,滚动tableView                    CGRect targetViewFrame = [self.tableView rectForSection:indexPath.section];                    if (self.moveSection.center.y < snapshot.center.y) {                        // 向下滚                        targetViewFrame.origin.y += SECTION_HEIGHT;                        [self.tableView scrollRectToVisible:targetViewFrame animated:YES];                    } else if (self.moveSection.center.y > snapshot.center.y) {                        // 向上滚                        targetViewFrame.origin.y -= SECTION_HEIGHT;                        [self.tableView scrollRectToVisible:targetViewFrame animated:YES];                    }                }            }            break;        }            // 长按手势取消状态        default: {            // 清空数组            [self.locations removeAllObjects];            self.moveSection.hidden = NO;            self.moveSection.alpha = 0.0;            // 将快照恢复到初始状态            [UIView animateWithDuration:0.25 animations:^{                snapshot.center = self.moveSection.center;                snapshot.transform = CGAffineTransformIdentity;                snapshot.alpha = 0.0;                self.moveSection.alpha = 1.0;            } completion:^(BOOL finished) {                [snapshot removeFromSuperview];                snapshot = nil;                // 这个地方必须加上这一句,否则在响应长按手势的瞬间取消手势,section将无法显示                self.moveSection.hidden = NO;            }];            break;        }    }}

以上是长按手势的响应,在里面我们需要做是如何实现tableView配合section的移动。
使用到apple的API

- (void)moveSection:(NSInteger)section toSection:(NSInteger)newSection NS_AVAILABLE_IOS(5_0);

在过程中我们要如何获得我们的点击是那一个section,根据长按手势的响应点去获取,这里其实可以把长按手势添加到section上面,但是考虑复用和多次添加的问题,最终添加在了tableview上面

- (nullable NSIndexPath *)indexPathForSectionAtPoint:(CGPoint)point numberOfSecton:(NSInteger)count {    static NSIndexPath *indexPath = nil;    indexPath = nil;    /** 使用indexPath可以为空 点击在外面 */    for (NSInteger i = 0; i < count ; i++) {        UIView *targetView = [self headerViewForSection:i];        CGRect rect = targetView.frame;        if (point.y <= rect.origin.y + 44) {            indexPath = [NSIndexPath indexPathForRow:0 inSection:i];            break;        }    }    return indexPath;}

这里用了一个比较笨的方式去算section的行数, 44为一个section的高度。

自定义section的响应方法

- (nullable UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{    SectionModel *model = self.dataArray[section];    NSString *key = model.title;    CustomHeadView  * sectionView = [self.tableView dequeueReusableHeaderFooterViewWithIdentifier:key];    if (!sectionView) {        sectionView = [[CustomHeadView alloc] initWithReuseIdentifier:key];    }    __weak TestViewController *weakSelf = self;    [sectionView setModelToSectionWithModel:self.dataArray[section] editSectionBlock:^(CustomHeadView *targetView) {        if (!weakSelf.editAlertView) {            weakSelf.editAlertView  = [[UIAlertView alloc] initWithTitle:@"修改标题" message:@"" delegate:weakSelf cancelButtonTitle:@"cannel" otherButtonTitles:@"confit", nil];            weakSelf.editAlertView.alertViewStyle = UIAlertViewStylePlainTextInput;        }        weakSelf.editAlertView.tag = [weakSelf.tableView indexPathForSectionAtPoint:targetView.center numberOfSecton:weakSelf.dataArray.count].section;        [weakSelf.editAlertView show];    } deleteSectionBlock:^(CustomHeadView *targetView) {        /** section删除按钮的回调 */        NSIndexPath *indexPath = [self.tableView indexPathForSectionAtPoint:targetView.center numberOfSecton:weakSelf.dataArray.count];        [weakSelf.dataArray removeObjectAtIndex:indexPath.section];        [weakSelf.tableView deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationTop];    } spreadSectionBlock:^(CustomHeadView *targetView) {        /** section展开效果的回调 */        NSIndexPath *indexPath = [self.tableView indexPathForSectionAtPoint:targetView.center numberOfSecton:weakSelf.dataArray.count];        SectionModel *model = targetView.strongModel;        model.sectionSwitch = !model.sectionSwitch;        [weakSelf.tableView reloadSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationFade];    } longpressSectionBlock:^(UILongPressGestureRecognizer *longPress, CustomHeadView *targetView) {         /** section长按的回调 */        [weakSelf longPressGestureRecognized:longPress];    }];    return sectionView;}

里面具体的方式可以参考一下Demo中实现。
Demo中包含了section的一下相关操作,比如:展开,移动,删除,添加等等。这里仅仅为大家提供一种解决方案,不代表最优解决方案。

0 0
原创粉丝点击