繁体   English   中英

在iOS中移动UICollectionView的单元格?

[英]Move cells of UICollectionView in iOS?

我有一个UICollectionView 。我试图将它作为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, 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个较小的子问题:

  1. 如何为细胞制作动画
  2. 如何使用拖放重新排序单元格。

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

如何为细胞制作动画

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

  1. 垂直移动单元格,即上下反弹
  2. 旋转细胞
  3. 最后,为每个单元格添加一个随机间隔时间,这样看起来单元格不会均匀地生成动画

这是代码:

@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,Changed和Ended

gestureRecognizerBegan:

  1. 当gestureRecognizer开始时,确定长按是否确实在单元格上(而不是在空白区域)
  2. 获取单元格的UIImage(请参阅我的方法“getRasterizedImageOfCell”)
  3. 隐藏单元格(即alpha = 0),使用单元格的精确框架创建UIImageView,这样用户就不会意识到您实际上隐藏了单元格,而您实际上正在使用imageview。

gestureRecognizerChanged:

  1. 更新UIImageView的中心,使其随手指移动。
  2. 如果用户已经停止移动他的手指,即他将鼠标悬停在他想要替换的单元格上,则现在需要交换单元格。 (看看我的函数“shouldSwapCells”,这个方法返回一个是否应该交换单元格的bool)
  3. 将要拖动的单元格移动到新的indexPath。 (看看我的方法“swapDraggedCell”)。 UICollectionView有一个名为“moveItemAtIndexPath:toIndexPath”的内置方法,我不确定UITableView是否有相同的东西

gestureRecognizerEnd:

  1. 将UIImageView“丢弃”回到单元格上
  2. 将单元格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;
}

希望这可以帮助 :)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM