UI 进阶之拖拽排序的实现

cjdl8294 8年前
   <h3><strong>导读</strong></h3>    <p>拖拽排序是新闻类的App可以说是必有的交互设计,如今日头条,网易新闻等。拖拽排序是一个交互体验非常好的设计,简单,方便。</p>    <p><strong>今日头条的拖拽排序界面</strong></p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/0f30edd6d0c8c09a428977031785a906.png"></p>    <p><strong>我实现的长按拖拽排序效果</strong></p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/72b10f5fb4262e9995ce09855f1caff8.gif"></p>    <p><strong>实现方案</strong></p>    <p>1.给CollectionViewCell添加一个长按手势,通过协议把手势传递到collectionView所在的控制器中。</p>    <pre>  <code class="language-objectivec">- (void)awakeFromNib{      self.layer.cornerRadius = 3;      self.layer.masksToBounds = YES;      //给每个cell添加一个长按手势      UILongPressGestureRecognizer * longPress =[[UILongPressGestureRecognizeralloc]initWithTarget:selfaction:@selector(longPress:)];      longPress.delegate = self;      [self addGestureRecognizer:longPress];  }     - (void)longPress:(UILongPressGestureRecognizer *)longPress{      if (self.delegate && [self.delegaterespondsToSelector:@selector(longPress:)]) {          [self.delegatelongPress:longPress];      }  }  </code></pre>    <p>2.开始长按时对cell进行截图,并隐藏cell。</p>    <pre>  <code class="language-objectivec">- (void)longPress:(UILongPressGestureRecognizer *)longPress{      //记录上一次手势的位置      static CGPointstartPoint;      //触发长按手势的cell      MovingCell * cell = (MovingCell *)longPress.view;      //开始长按      if (longPress.state == UIGestureRecognizerStateBegan) {          [self shakeAllCell];          //获取cell的截图          _snapshotView  = [cellsnapshotViewAfterScreenUpdates:YES];          _snapshotView.center = cell.center;          [_collectionViewaddSubview:_snapshotView];          _indexPath= [_collectionViewindexPathForCell:cell];          _originalCell = cell;          _originalCell.hidden = YES;          startPoint = [longPresslocationInView:_collectionView];      }  </code></pre>    <p>3、在手势移动的时候,移动截图视图,用遍历的方法求出截图移动到哪个cell的位置,再调用系统的api交换这个cell和隐藏cell的位置,并且数据源中的数据也需要调整顺序</p>    <pre>  <code class="language-objectivec">    //手势移动的时候      else if (longPress.state == UIGestureRecognizerStateChanged){      CGFloattranX = [longPresslocationOfTouch:0 inView:_collectionView].x - startPoint.x;      CGFloattranY = [longPresslocationOfTouch:0 inView:_collectionView].y - startPoint.y;      //设置截图视图位置      _snapshotView.center = CGPointApplyAffineTransform(_snapshotView.center, CGAffineTransformMakeTranslation(tranX, tranY));      startPoint = [longPresslocationOfTouch:0 inView:_collectionView];      //计算截图视图和哪个cell相交      for (UICollectionViewCell *cellin [_collectionViewvisibleCells]) {          //跳过隐藏的cell          if ([_collectionViewindexPathForCell:cell] == _indexPath) {              continue;          }          //计算中心距          CGFloatspace = sqrtf(pow(_snapshotView.center.x - cell.center.x, 2) + powf(_snapshotView.center.y - cell.center.y, 2));             //如果相交一半且两个视图Y的绝对值小于高度的一半就移动          if (space  _indexPath.item) {                  for (NSUInteger i = _indexPath.item; i  _nextIndexPath.item ; i --) {                      [self.array exchangeObjectAtIndex:i withObjectAtIndex:i - 1];                  }              }              //移动              [_collectionViewmoveItemAtIndexPath:_indexPathtoIndexPath:_nextIndexPath];              //设置移动后的起始indexPath              _indexPath = _nextIndexPath;              break;          }      }  </code></pre>    <p>4.手势停止时,移除截图的view,显示隐藏cell</p>    <pre>  <code class="language-objectivec">//手势停止时  }else if(longPress.state == UIGestureRecognizerStateEnded){      [self stopShake];      [_snapshotViewremoveFromSuperview];      _originalCell.hidden = NO;  }  </code></pre>    <p><strong>其他</strong></p>    <p>代码还可以进一步封装,写一个数据管理类dataTool,dataTool作为collectionView的数据源,所有的数据源方法都写到dataTool类中。手势的代理方法也在里面实现,这样控制器会简洁很多,控制器就不需要关注拖拽排序的具体逻辑了。大家有空可以自己写写看,也许你们有更好的处理方案,可以评论交流一下。</p>    <p> </p>    <p>来自:http://ios.jobbole.com/90805/</p>    <p> </p>