在iOS中移动UICollectionView的单元格?

前端之家收集整理的这篇文章主要介绍了在iOS中移动UICollectionView的单元格?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有一个UICollectionView.I我试图给它作为 SpringBoard的功能.我有能力给每个单元格摇动动画.但是我想当图标摇动时,我应该能够移动他们.

为了摇动单元格,我已经在每个单元格上添加了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");
}

这也很好.它也使用长按手势&当手势被取消时,我可以移动细胞.但现在问题是在一个我可以移动单元格或动画他们.如果我添加我的自定义手势,那么我无法移动图像.请告诉我如何删除这个问题?

解决方法

看看这个名为 DragDropCollectionView的项目,它实现拖放以及动画.

编辑:这个问题可以分解成2个较小的子问题:

>如何动画细胞
>如何使用拖放重新排序单元格.

您应该将这两个解决方案组合到UICollectionView的子文件夹中,以获得您的主要解决方案.

如何动画细胞

要获得摆动动画,您需要添加2种不同的动画效果

>垂直移动单元格,上下移动
>旋转单元格
>最后,为每个单元格添加一个随机的间隔时间,所以看起来单元格不能均匀地动画化

这是代码

@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;
}

希望这可以帮助 :)

猜你在找的iOS相关文章