为了摇动单元格,我已经在每个单元格上添加了UILongPressGesture.当手势结束时,我已经添加了一个自定义动画.还在左上角添加了一个删除按钮.
长按手势代码:
declaration of variables CGPoint p; UILongPressGestureRecognizer *lpgr; NSIndexPath *gesture_indexPath;
添加手势到集合视图
lpgr = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)]; lpgr.minimumPressDuration = .3; // To detect after how many seconds you want shake the cells lpgr.delegate = self; [self.collection_view addGestureRecognizer:lpgr]; lpgr.delaysTouchesBegan = YES;
回调方法
-(void)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer { if (gestureRecognizer.state != UIGestureRecognizerStateEnded) { return; } p = [gestureRecognizer locationInView:self.collection_view]; NSIndexPath *indexPath = [self.collection_view indexPathForItemAtPoint:p]; if (indexPath == nil) { NSLog(@"couldn't find index path"); } else { [[NSUserDefaults standardUserDefaults]setValue:@"yes" forKey:@"longPressed"]; [self.collection_view reloadData]; } }
单元格在inde路径项
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { NSLog(@"arr_album index row"); BlogAlbumCell *cell; static NSString *identifier = @"UserBlogAlbum"; cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath]; UserAlbum *user_allbum=[arr_userAlbums objectAtIndex:indexPath.row]; cell.label_blog_name.text=user_allbum.album_name; cell.image_blog_image.image = [UIImage imageNamed:@"more.png"]; [cell.image_blog_image setImageWithURL:[NSURL URLWithString:[IMAGE_BASE_URL stringByAppendingString:user_allbum.album_image]]]; if([[[NSUserDefaults standardUserDefaults]valueForKey:@"longPressed"] isEqualToString:@"yes"]) { CABasicAnimation* anim = [CABasicAnimation animationWithKeyPath:@"transform.rotation"]; [anim setToValue:[NSNumber numberWithFloat:0.0f]]; [anim setFromValue:[NSNumber numberWithDouble:M_PI/50]]; [anim setDuration:0.1]; [anim setRepeatCount:NSUIntegerMax]; [anim setAutoreverses:YES]; cell.layer.shouldRasterize = YES; [cell.layer addAnimation:anim forKey:@"SpringboardShake"]; CGFloat delButtonSize = 20; UIButton *delButton = [[UIButton alloc] initWithFrame:CGRectMake(0,delButtonSize,delButtonSize)]; delButton.center = CGPointMake(9,10); delButton.backgroundColor = [UIColor clearColor]; [delButton setImage: [UIImage imageNamed:@"cross_30.png"] forState:UIControlStateNormal]; [cell addSubview:delButton]; [delButton addTarget:self action:@selector(deleteRecipe:) forControlEvents:UIControlEventTouchUpInside]; } else if ([[[NSUserDefaults standardUserDefaults]valueForKey:@"singleTap"] isEqualToString:@"yes"]) { for(UIView *subview in [cell subviews]) { if([subview isKindOfClass:[UIButton class]]) { [subview removeFromSuperview]; } else { // Do nothing - not a UIButton or subclass instance } } [cell.layer removeAllAnimations]; // _deleteButton.hidden = YES; // [_deleteButton removeFromSuperview]; } return cell; }
在这里工作正常
为了移动单元格,我做了一个示例应用程序,其中我添加了UICollectionViewController&覆盖此方法
-(void)collectionView:(UICollectionView *)collectionView moveItemAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath { NSLog(@"Move at index path called"); }
这也很好.它也使用长按手势&当手势被取消时,我可以移动细胞.但现在问题是在一个我可以移动单元格或动画他们.如果我添加我的自定义手势,那么我无法移动图像.请告诉我如何删除这个问题?
解决方法
编辑:这个问题可以分解成2个较小的子问题:
>如何动画细胞
>如何使用拖放重新排序单元格.
您应该将这两个解决方案组合到UICollectionView的子文件夹中,以获得您的主要解决方案.
如何动画细胞
>垂直移动单元格,上下移动
>旋转单元格
>最后,为每个单元格添加一个随机的间隔时间,所以看起来单元格不能均匀地动画化
这是代码:
@interface DragDropCollectionView () @property (assign,nonatomic) BOOL isWiggling; @end @implementation DragDropCollectionView //Start and Stop methods for wiggle - (void) startWiggle { for (UICollectionViewCell *cell in self.visibleCells) { [self addWiggleAnimationToCell:cell]; } self.isWiggling = true; } - (void)stopWiggle { for (UICollectionViewCell *cell in self.visibleCells) { [cell.layer removeAllAnimations]; } self.isWiggling = false; } //- (UICollectionViewCell *)dequ - (UICollectionViewCell *)dequeueReusableCellWithReuseIdentifier:(NSString *)identifier forIndexPath:(nonnull NSIndexPath *)indexPath{ UICollectionViewCell *cell = [super dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath]; if (self.isWiggling) { [self addWiggleAnimationToCell:cell]; } else { [cell.layer removeAllAnimations]; } return [[UICollectionViewCell alloc] init]; } //Animations - (void)addWiggleAnimationToCell:(UICollectionViewCell *)cell { [CATransaction begin]; [CATransaction setDisableActions:false]; [cell.layer addAnimation:[self rotationAnimation] forKey:@"rotation"]; [cell.layer addAnimation:[self bounceAnimation] forKey:@"bounce"]; [CATransaction commit]; } - (CAKeyframeAnimation *)rotationAnimation { CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation.z"]; CGFloat angle = 0.04; NSTimeInterval duration = 0.1; double variance = 0.025; animation.values = @[@(angle),@(-1 * angle)]; animation.autoreverses = YES; animation.duration = [self randomizeInterval:duration withVariance: variance]; animation.repeatCount = INFINITY; return animation; } - (CAKeyframeAnimation *)bounceAnimation { CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.translation.y"]; CGFloat bounce = 3.0; NSTimeInterval duration = 0.12; double variance = 0.025; animation.values = @[@(bounce),@(-1 * bounce)]; animation.autoreverses = YES; animation.duration = [self randomizeInterval:duration withVariance: variance]; animation.repeatCount = INFINITY; return animation; } - (NSTimeInterval)randomizeInterval:(NSTimeInterval)interval withVariance:(double)variance { double randomDecimal = (arc4random() % 1000 - 500.0) / 500.0; return interval + variance * randomDecimal; }
如何使用拖放重新排序单元格
所以想法是这样的:你不是移动实际的单元格,而是移动一个UIImageView与单元格内容的UIImage.
算法或多或少是这样的.我把它分解成3个部分,手势识别器,改变和结束
gestureRecognizerBegan:
>当手势识别器开始时,确定长按确实在一个单元格上(而不是在空白的空间)
>获取单元格的UIImage(请参阅我的方法“getRasterizedImageOfCell”)
>隐藏单元格(即alpha = 0),创建具有单元格确切框架的UIImageView,以便用户不会意识到您实际上已隐藏单元格,并且实际上正在使用imageview.
gestureRecognizerChanged:
>更新UIImageView的中心,使其随手指移动.
>如果用户已经停止移动他的眼睛,即他将鼠标悬停在要替换的单元格上,那么现在需要交换单元格. (看看我的函数“shouldSwapCells”,这个方法返回一个bool是否单元格应该交换)
>将要拖动的单元格移动到新的indexPath. (看我的方法“swapDraggedCell”). UICollectionView有一个称为“moveItemAtIndexPath:toIndexPath”的内置方法,我不知道UITableView是否具有相同的东西
gestureRecognizerEnd:
>将UIImageView“放下”回到单元格
>将单元格alpha从0.0更改为1.0,并从视图中删除UIImageView.
这是代码:
@interface DragDropCollectionView () @property (strong,nonatomic) NSIndexPath *draggedCellIndexPath; @property (strong,nonatomic) UIImageView *draggingImageView; @property (assign,nonatomic) CGPoint touchOffsetFromCenterOfCell; @property (strong,nonatomic) UILongPressGestureRecognizer *longPressRecognizer; @end @implementation DragDropCollectionView - (void)handleLongPress:(UILongPressGestureRecognizer *)longPressRecognizer { CGPoint touchLocation = [longPressRecognizer locationInView:self]; switch (longPressRecognizer.state) { case UIGestureRecognizerStateBegan: { self.draggedCellIndexPath = [self indexPathForItemAtPoint:touchLocation]; if (self.draggedCellIndexPath != nil) { UICollectionViewCell *draggedCell = [self cellForItemAtIndexPath:self.draggedCellIndexPath]; self.draggingImageView = [[UIImageView alloc] initWithImage:[self rasterizedImageCopyOfCell:draggedCell]]; self.draggingImageView.center = draggedCell.center; [self addSubview:self.draggingImageView]; draggedCell.alpha = 0.0; self.touchOffsetFromCenterOfCell = CGPointMake(draggedCell.center.x - touchLocation.x,draggedCell.center.y - touchLocation.y); [UIView animateWithDuration:0.4 animations:^{ self.draggingImageView.transform = CGAffineTransformMakeScale(1.3,1.3); self.draggingImageView.alpha = 0.8; }]; } break; } case UIGestureRecognizerStateChanged: { if (self.draggedCellIndexPath != nil) { self.draggingImageView.center = CGPointMake(touchLocation.x + self.touchOffsetFromCenterOfCell.x,touchLocation.y + self.touchOffsetFromCenterOfCell.y); } float pingInterval = 0.3; dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(int64_t)(pingInterval * NSEC_PER_SEC)),dispatch_get_main_queue(),^{ NSIndexPath *newIndexPath = [self indexPathToSwapCellWithAtPrevIoUsTouchLocation:touchLocation]; if (newIndexPath) { [self swapDraggedCellWithCellAtIndexPath:newIndexPath]; } }); break; } case UIGestureRecognizerStateEnded: { if (self.draggedCellIndexPath != nil ) { UICollectionViewCell *draggedCell = [self cellForItemAtIndexPath:self.draggedCellIndexPath]; [UIView animateWithDuration:0.4 animations:^{ self.draggingImageView.transform = CGAffineTransformIdentity; self.draggingImageView.alpha = 1.0; if (draggedCell != nil) { self.draggingImageView.center = draggedCell.center; } } completion:^(BOOL finished) { [self.draggingImageView removeFromSuperview]; self.draggingImageView = nil; if (draggedCell != nil) { draggedCell.alpha = 1.0; self.draggedCellIndexPath = nil; } }]; } } default: break; } } - (UIImage *)rasterizedImageCopyOfCell:(UICollectionViewCell *)cell { UIGraphicsBeginImageContextWithOptions(cell.bounds.size,false,0.0); [cell.layer renderInContext:UIGraphicsGetCurrentContext()]; UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); return image; } - (NSIndexPath *)indexPathToSwapCellWithAtPrevIoUsTouchLocation:(CGPoint)prevIoUsTouchLocation { CGPoint currentTouchLocation = [self.longPressRecognizer locationInView:self]; if (!isnan(currentTouchLocation.x) && !isnan(currentTouchLocation.y)) { if ([self distanceBetweenPoints:currentTouchLocation secondPoint:prevIoUsTouchLocation] < 20.0) { NSIndexPath *newIndexPath = [self indexPathForItemAtPoint:currentTouchLocation]; return newIndexPath; } } return nil; } - (CGFloat)distanceBetweenPoints:(CGPoint)firstPoint secondPoint:(CGPoint)secondPoint { CGFloat xDistance = firstPoint.x - secondPoint.x; CGFloat yDistance = firstPoint.y - secondPoint.y; return sqrtf(xDistance * xDistance + yDistance * yDistance); } - (void)swapDraggedCellWithCellAtIndexPath:(NSIndexPath *)newIndexPath { [self moveItemAtIndexPath:self.draggedCellIndexPath toIndexPath:newIndexPath]; UICollectionViewCell *draggedCell = [self cellForItemAtIndexPath:newIndexPath]; draggedCell.alpha = 0.0; self.draggedCellIndexPath = newIndexPath; }
希望这可以帮助 :)