本人iOS新手,借鑒前人經驗封裝了一個可拖動cell,重排cell的tableView,效果與iPhone自帶天氣應用中的tableView相似,可在多個section之間拖動重排,并且如果tableview內容大于屏幕,將cell拖至邊緣時tableView會自動向上或向下滑動。
GitHub下載地址
效果如下:
1.gif
使用方法:
- 必須實現的兩個代理方法,在cell位置發生改變的時候同時更新外部數據源
/**將外部數據源數組傳入,以便在移動cell數據發生改變時進行修改重排*/
- (NSArray *)originalArrayDataForTableView:(RTDragCellTableView *)tableView;
/**將修改重排后的數組傳入,以便外部更新數據源*/
- (void)tableView:(RTDragCellTableView *)tableView newArrayDataForDataSource:(NSArray *)newArray;
- 可選的三個代理方法,分別是cell的三種情況
/**選中的cell準備好可以移動的時候*/
- (void)tableView:(RTDragCellTableView *)tableView cellReadyToMoveAtIndexPath:(NSIndexPath *)indexPath;
/**選中的cell正在移動,變換位置,手勢尚未松開*/
- (void)cellIsMovingInTableView:(RTDragCellTableView *)tableView;
/**選中的cell完成移動,手勢已松開*/
- (void)cellDidEndMovingInTableView:(RTDragCellTableView *)tableView;
基本思路:
- 拖動效果通過添加一個長按手勢和對選中的cell進行截圖來實現。
/**
* cell被長按手指選中,對其進行截圖,原cell隱藏
*/
- (void)cellSelectedAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [self cellForRowAtIndexPath:indexPath];
UIView *snapshot = [self customSnapshotFromView:cell];
[self addSubview:snapshot];
_snapshot = snapshot;
cell.hidden = YES;
CGPoint center = _snapshot.center;
center.y = _fingerLocation.y;
[UIView animateWithDuration:0.2 animations:^{
_snapshot.transform = CGAffineTransformMakeScale(1.03, 1.03);
_snapshot.alpha = 0.98;
_snapshot.center = center;
}];
}
- 在cell的截圖被移動到其他indexPath范圍時移動隱藏的那個cell,這時一定要先更新數據源再移動cell 位置,在跨section拖動的時候如果先移動cell再更新數據源會出現崩潰。
- (void)cellRelocatedToNewIndexPath:(NSIndexPath *)indexPath{
//更新數據源并返回給外部
[self updateDataSource];
//交換移動cell位置
[self moveRowAtIndexPath:_originalIndexPath toIndexPath:indexPath];
//更新cell的原始indexPath為當前indexPath
_originalIndexPath = indexPath;
}
- 自動滾動效果的實現:在cell截圖觸碰頂部或底部時開啟一個定時器,執行自動滾動方法
- (void)startAutoScrollTimer{
if (!_autoScrollTimer) {
_autoScrollTimer = [CADisplayLink displayLinkWithTarget:self selector:@selector(startAutoScroll)];
[_autoScrollTimer addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
}
}
通過計時器不斷改變tableView的contentOffset達到自動滾動效果,并且可以調節滾動速度
- (void)startAutoScroll{
CGFloat pixelSpeed = 4;
if (_autoScrollDirection == RTSnapshotMeetsEdgeTop) {//向下滾動
if (self.contentOffset.y > 0) {//向下滾動最大范圍限制
[self setContentOffset:CGPointMake(0, self.contentOffset.y - pixelSpeed)];
_snapshot.center = CGPointMake(_snapshot.center.x, _snapshot.center.y - pixelSpeed);
}
}else{ //向上滾動
if (self.contentOffset.y + self.bounds.size.height < self.contentSize.height) {//向下滾動最大范圍限制
[self setContentOffset:CGPointMake(0, self.contentOffset.y + pixelSpeed)];
_snapshot.center = CGPointMake(_snapshot.center.x, _snapshot.center.y + pixelSpeed);
}
}