iOS 9以前のcollectionViewのドラッグアンドドロップ再配置の実装
6790 ワード
最近、ラベルクラスのdemoを実装する必要があるため、ドラッグ・アンド・ドロップの再配置をサポートする必要があります.まず、collectionViewが考えられ、すぐにAPIドキュメントに類似のインタフェースが見つかりました.
システムで提供されたこれらのインタフェースはすぐに私たちのニーズを実現することができます.コードはgitbubアドレスを参照してください.しかし、上記の方法の後ろに付いているNSを発見しましたか?AVAILABLE_IOS(9_0)、iOS 9がサポートを開始したばかりで、気まずい思いをしました.iOS 9の前にどのように手動でこのニーズを実現するかを分析しながら、実装手順をリストし始めました. cellを長押ししてドラッグモード に入る現在のcellを非表示にし、collectionView上の に現在のcellのスクリーンショットを追加します.ジェスチャーに従ってスクリーンショットを移動し、スクリーンショットのcenterが別のcell 2の範囲内に入ると、隠されたcellをcell 2の位置に移動し、cell 2およびcell 2の後のcell を移動する.移動を続けると(3) が実行する.指を離す移動を終了すると、スクリーンショットが除去され、前に隠すcell が表示する.
プロセスが順調になったら、次はコードの実現です.
1.cellを長押ししてドラッグモードに入る
ここではcollectionViewにロングプッシュジェスチャーを直接追加しました
2.現在のcellを非表示にし、現在のcellのスクリーンショットをcollectionViewに追加
3.スクリーンショットの移動
データソースの変更
4.移動を続けると(3)
5.指を離して移動を終了すると、スクリーンショットが除去され、以前に隠していたcellが表示されます
はい、これでiOS 9以下の適合が完成しました.実現も複雑ではありません.主に実現する前に構想を整理しておけば、実現は難しくありません.
詳細なコードはgitbubアドレスを参照してください.収穫があれば、starを歓迎します!
- (BOOL)beginInteractiveMovementForItemAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(9_0);
- (void)updateInteractiveMovementTargetPosition:(CGPoint)targetPosition NS_AVAILABLE_IOS(9_0);
- (void)endInteractiveMovement NS_AVAILABLE_IOS(9_0);
- (void)cancelInteractiveMovement NS_AVAILABLE_IOS(9_0);
システムで提供されたこれらのインタフェースはすぐに私たちのニーズを実現することができます.コードはgitbubアドレスを参照してください.しかし、上記の方法の後ろに付いているNSを発見しましたか?AVAILABLE_IOS(9_0)、iOS 9がサポートを開始したばかりで、気まずい思いをしました.iOS 9の前にどのように手動でこのニーズを実現するかを分析しながら、実装手順をリストし始めました.
プロセスが順調になったら、次はコードの実現です.
1.cellを長押ししてドラッグモードに入る
ここではcollectionViewにロングプッシュジェスチャーを直接追加しました
UILongPressGestureRecognizer *longG = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(longPress:)];
longG.minimumPressDuration = 0.2f;
[self.collectionView addGestureRecognizer:longG];
- (void)longPress:(UILongPressGestureRecognizer *)lpGesture
{
switch(lpGesture.state) {
case UIGestureRecognizerStateBegan:
{
[self collectionViewCellDidBeginChange:lpGesture];
break;
}
case UIGestureRecognizerStateChanged:
{
[self collectionViewCellDidChange:lpGesture];
break;
}
case UIGestureRecognizerStateEnded:
{
[self collectionViewCellDidEndChange:lpGesture];
break;
}
default:
if (AVAILABLE_IOS_9_0)
{
[self.collectionView cancelInteractiveMovement];
}
break;
}
}
2.現在のcellを非表示にし、現在のcellのスクリーンショットをcollectionViewに追加
- (void)collectionViewCellDidBeginChange:(UILongPressGestureRecognizer *)lpGesture
{
self.beginIndexPath = [self.collectionView indexPathForItemAtPoint:[lpGesture locationInView:self.collectionView]];
self.beginCell = (CollectionViewCell *)[self.collectionView cellForItemAtIndexPath:self.beginIndexPath];
if (AVAILABLE_IOS_9_0)
{
[self.collectionView beginInteractiveMovementForItemAtIndexPath:self.beginIndexPath];
}
else
{
// cell
self.tempView = [self.beginCell snapshotViewAfterScreenUpdates:YES];
self.tempView.frame = self.beginCell.frame;
[self.collectionView addSubview:self.tempView];
self.beginPoint = [lpGesture locationInView:self.collectionView];
self.beginCell.hidden = YES;
}
}
3.スクリーンショットの移動
- (void)collectionViewCellDidChange:(UILongPressGestureRecognizer *)lpGesture
{
CGPoint targetPosion = [lpGesture locationInView:lpGesture.view];
if (AVAILABLE_IOS_9_0)
{
[self.collectionView updateInteractiveMovementTargetPosition:targetPosion];
}
else
{
CGFloat tranX = [lpGesture locationOfTouch:0 inView:self.collectionView].x - self.beginPoint.x;
CGFloat tranY = [lpGesture locationOfTouch:0 inView:self.collectionView].y - self.beginPoint.y;
//
self.tempView.center = CGPointApplyAffineTransform(self.tempView.center, CGAffineTransformMakeTranslation(tranX, tranY));
self.beginPoint = [lpGesture locationOfTouch:0 inView:_collectionView];
// cell
for (UICollectionViewCell *cell in [_collectionView visibleCells])
{
// cell
if ([_collectionView indexPathForCell:cell] == self.beginIndexPath)
{
continue;
}
//
CGFloat space = sqrtf(pow(self.tempView.center.x - cell.center.x, 2) + powf(self.tempView.center.y - cell.center.y, 2));
// Y
if (space <= self.tempView.bounds.size.width * 0.5 && (fabs(self.tempView.center.y - cell.center.y) <= self.tempView.bounds.size.height * 0.5))
{
NSIndexPath *nextIndexPath = [_collectionView indexPathForCell:cell];
[self updateDataWithSourceIndexPath:self.beginIndexPath toIndexPath:nextIndexPath];
[_collectionView moveItemAtIndexPath:self.beginIndexPath toIndexPath:nextIndexPath];
// indexPath
self.beginIndexPath = nextIndexPath;
break;
}
}
}
}
データソースの変更
- (void)updateDataWithSourceIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{
if (sourceIndexPath.section == destinationIndexPath.section) // section
{
if (destinationIndexPath.item > sourceIndexPath.item) {
for (NSUInteger i = sourceIndexPath.item; i < destinationIndexPath.item ; i ++) {
[self.dataArray[sourceIndexPath.section] exchangeObjectAtIndex:i withObjectAtIndex:i + 1];
}
}else{
for (NSUInteger i = sourceIndexPath.item; i > destinationIndexPath.item ; i --) {
[self.dataArray[sourceIndexPath.section] exchangeObjectAtIndex:i withObjectAtIndex:i - 1];
}
}
}
else // section , sourceData, destinationData
{
NSMutableArray *sourceArr = self.dataArray[sourceIndexPath.section];
NSMutableArray *destinationArr = self.dataArray[destinationIndexPath.section];
id obj = [sourceArr objectAtIndex:sourceIndexPath.row];
[sourceArr removeObjectAtIndex:sourceIndexPath.row];
[destinationArr insertObject:obj atIndex:destinationIndexPath.row];
}
}
4.移動を続けると(3)
5.指を離して移動を終了すると、スクリーンショットが除去され、以前に隠していたcellが表示されます
- (void)collectionViewCellDidEndChange:(UILongPressGestureRecognizer *)lpGesture
{
if (AVAILABLE_IOS_9_0)
{
[self.collectionView endInteractiveMovement];
}
else
{
[UIView animateWithDuration:0.25 animations:^{
self.tempView.center = self.beginCell.center;
}completion:^(BOOL finished) {
[self.tempView removeFromSuperview];
self.beginCell.hidden = NO;
}];
}
}
はい、これでiOS 9以下の適合が完成しました.実現も複雑ではありません.主に実現する前に構想を整理しておけば、実現は難しくありません.
詳細なコードはgitbubアドレスを参照してください.収穫があれば、starを歓迎します!