首页 > 解决方案 > Obj-c - 使用 PanGesture 突出显示 UICollectionViewCells?

问题描述

当用户将手指拖到单元格上时,我正在使用下面的代码来跟踪单元格(这很好用)。也就是说,当用户将手指拖到它们上方时,我想突出显示每个单元格(或更改自定义单元格中背景视图的颜色)。我怎样才能做到这一点?见下文。

视图控制器.m

  - (void)viewDidLoad {
        [super viewDidLoad];
       
        UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)];
        [self.ringCollectionView addGestureRecognizer:panGesture];
        
    }
    
    
    - (void) handlePanGesture:(UIPanGestureRecognizer*) panGesture{
    
            CGPoint location = [panGesture locationInView:self.ringCollectionView];
    
            NSIndexPath *indexPath = [self.ringCollectionView indexPathForItemAtPoint:location];
            NSMutableArray *selectedIndexes = [NSMutableArray arrayWithArray:[self.ringCollectionView indexPathsForSelectedItems]];
              
        
               if (![selectedIndexes containsObject:@(indexPath.row)]){
             
                   NSLog(@"THIS CELL IS %ld", (long)indexPath.row);
                }
        
            else if (panGesture.state == UIGestureRecognizerStateEnded){
              
            }
    
    }

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{

    
    return 10;
    
}

 
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *cellIdentifier = @"RingCollectionViewCell";
    RingCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
    
  
        return cell;
   

}
 

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
  
    NSLog(@"Tapping");
}

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
  
    return CGSizeMake(118, 118);
        
  
}

标签: objective-cuicollectionviewuipangesturerecognizer

解决方案


我最初的答案是无关紧要的,因为我一开始并不了解想要的结果,所以我完全删除了它。这是更新的一个:

首先,我相信通过“本机”机制跟踪选定的单元格UICollectionView是合理且一致的,不需要在单元格内使用自定义手势处理程序。但是,为了表示选定状态,您需要设置selectedBackgroundView属性,如下所示:

- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"RingCollectionViewCell" forIndexPath:indexPath];
    if (!cell.selectedBackgroundView) {
        cell.selectedBackgroundView = [[UIView alloc] initWithFrame:cell.bounds];
        cell.selectedBackgroundView.backgroundColor = [UIColor grayColor];
    }
    return cell;
}

我不知道您的RingCollectionViewCell课程是如何设计的,但请注意,您需要确保contentView此单元格具有透明的背景颜色,否则它将遮盖selectedBackgroundView.

现在是棘手的部分。UIPanGestureRecognizer非常快速地获取事件,并且当用户只是将手指保持在屏幕上时,将经常调用句柄方法,因此您需要以某种方式抑制不应切换单元格选定状态的事件。我的建议是,如果它们发生在同一个单元格中,则忽略所有后果事件。为了实现这样的行为,我们需要存储最后一个单元格的索引路径,让我们使用一个简单的属性:

@interface ViewController ()

@property (strong, nonatomic, nullable) NSIndexPath *trackingCellIndexPath;

@end

现在您需要在手势句柄方法中将最后触摸单元格的索引路径分配给此属性。您还需要在手势完成或取消时重置此属性,如果给定索引路径不等于跟踪的索引路径,则切换选择,否则忽略触摸事件:

- (void)handlePanGesture:(UIPanGestureRecognizer *)recognizer {
    // Reset the tracking state when the gesture is finished
    switch (recognizer.state) {
        case UIGestureRecognizerStateEnded:
        case UIGestureRecognizerStateCancelled:
            self.trackingCellIndexPath = nil;
            return;
        default:
            break;
    }
    
    // Obtain the cell the user is currently dragging over
    CGPoint location = [recognizer locationInView:self.collectionView];
    NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:location];
    
    // If the user currently doesn't touch any cell, reset the tracking state and prepare to listen to another cell
    if (!indexPath) {
        if (self.trackingCellIndexPath) {
            self.trackingCellIndexPath = nil;
        }
        return;
    }

    // If current event is subsequent gesture event which happens within the same cell, ignore it
    if (self.trackingCellIndexPath == indexPath) {
        return;
    }
    
    // If the cell hasn't been previously tracked, switch the selected state and start tracking it
    self.trackingCellIndexPath = indexPath;
    if ([self.collectionView.indexPathsForSelectedItems containsObject:indexPath]) {
        [self.collectionView deselectItemAtIndexPath:indexPath animated:YES];
    } else {
        [self.collectionView selectItemAtIndexPath:indexPath animated:YES scrollPosition:UICollectionViewScrollPositionNone];
    }
}

最后要更改的是集合视图的选择模式。正如您期望多个单元格保持选中状态一样,只需在以下位置切换allowsMultipleSelection您的集合视图viewDidLoad

- (void)viewDidLoad {
    ... 
    self.collectionView.allowsMultipleSelection = YES;
}

推荐阅读