【问题标题】:Selecting multiple cells in a UICollectionView在 UICollectionView 中选择多个单元格
【发布时间】:2020-04-21 07:45:24
【问题描述】:

我想要实现的是类似于 WhatsApp 的视频长度编辑器:您可以通过拖动卷轴的开头或结尾来修改长度。

我需要能够通过在集合视图中拖动手指来选择单元格,然后如果您触摸最后一个或第一个选定的单元格并再次拖动,选择应该会调整。

编辑: 我已经能够做几乎所有我需要的事情,但还是有一些不对劲的地方。

我最终使用了一个长按手势识别器,它会在 0.3 秒后触发“编辑模式”。 问题是:有时只是第一次进入“编辑模式”你不能真正编辑任何东西,所以你必须释放长按并重新开始。

我不得不锁定编辑方向,因为我无法让它双向工作。这意味着如果您进入编辑模式并开始向左移动,例如,您将无法向右移动。

这是我目前的代码:

ReservationViewController.m

#import "ReservationViewController.h"
#import "RoomTest.h"

@interface ReservationCollectionViewCell : UICollectionViewCell

@property (weak, nonatomic) IBOutlet UILabel *timeLbl;
@property (weak, nonatomic) IBOutlet UIView *upLine;
@property (weak, nonatomic) IBOutlet UIView *leftLine;
@property (weak, nonatomic) IBOutlet UIView *bottomLine;
@property (weak, nonatomic) IBOutlet UIView *rightLine;

@end

@implementation ReservationCollectionViewCell

@end


@interface ReservationViewController ()

@property (strong, nonatomic) NSMutableArray *cellsArray;
@property (strong, nonatomic) NSMutableArray *selectedIndexes;
@property (strong, nonatomic) NSArray *orderedIndexes;
@property (strong, nonatomic) NSIndexPath *startPath;
@property (nonatomic) BOOL dirLockAddSelection;
@property (nonatomic) BOOL dirLockDelSelection;
@property (weak, nonatomic) IBOutlet UILabel *resultLbl;
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (strong, nonatomic) NSString *selectedRoom;
@property (weak, nonatomic) IBOutlet UILabel *roomLbl;
@property (nonatomic) BOOL gestureActivated;

@end

@implementation ReservationViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    _cellsArray = [[NSMutableArray alloc] initWithCapacity:96];
    _selectedIndexes = [[NSMutableArray alloc] init];
    _startPath = [[NSIndexPath alloc] init];

    _selectedRoom = [NSString new];

    // Test data
    NSMutableArray *tempArray = [[NSMutableArray alloc] init];
    for (int i=0; i<5; i++) {
        RoomTest *temp = [[RoomTest alloc] init];
        temp.start = @"05:00";
        temp.end = @"08:30";
        temp.room = [NSString stringWithFormat:@"%d00",i+1];
        [tempArray addObject:temp];
    }
    // End of test data


    _rooms = [[NSArray alloc] initWithArray:tempArray];

    NSDateComponents *components= [[NSDateComponents alloc] init];
    [components setSecond:00];
    [components setMinute:00];
    [components setHour:00];
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSDate *zeroDate = [calendar dateFromComponents:components];
    NSDateFormatter *df = [[NSDateFormatter alloc] init];
    [df setDateFormat:@"HH:mm"];
    NSString *test = [df stringFromDate:zeroDate];

    for (int i=0; i<1440; i+=15) {
        [_cellsArray addObject:test];
        [components setMinute:15];
        zeroDate = [calendar dateByAddingComponents:components toDate:zeroDate options:0];
        test = [df stringFromDate:zeroDate];
    }

    UILongPressGestureRecognizer *longPressRecognizer = [[UILongPressGestureRecognizer alloc] init];
    [longPressRecognizer addTarget:self action:@selector(didLongPress:)];
    longPressRecognizer.minimumPressDuration = 0.3;
    [_collectionView addGestureRecognizer: longPressRecognizer];
}

- (void)didLongPress: (UILongPressGestureRecognizer *)gesture {
    if (UIGestureRecognizerStateBegan == gesture.state) {
        _gestureActivated = YES;
        CGPoint location = [gesture locationInView:_collectionView];
        _startPath = [_collectionView indexPathForItemAtPoint:location];
        NSLog(@"Start: %ld", (long)_startPath.row);
    } else if (UIGestureRecognizerStateChanged == gesture.state) {
        CGPoint location = [gesture locationInView:_collectionView];
        NSIndexPath *indexPath = [_collectionView indexPathForItemAtPoint:location];
        NSLog(@"Changed: %ld", (long)indexPath.row);

        if ([_orderedIndexes count] == 0 && ![_selectedIndexes containsObject:@(indexPath.row)]) {
            [_selectedIndexes addObject:@(indexPath.row)];
            [_collectionView reloadData];
        } else {
            NSNumber *first = (NSNumber*)[_orderedIndexes firstObject];
            NSNumber *last = (NSNumber*)[_orderedIndexes lastObject];
            if ((_startPath.row == [first intValue] && indexPath.row < _startPath.row) || (_startPath.row == [last intValue] && indexPath.row > _startPath.row)) {
                if (![_selectedIndexes containsObject:@(indexPath.row)] && indexPath.row != _startPath.row && !_dirLockDelSelection) {
                    [_selectedIndexes addObject:@(indexPath.row)];
                    _dirLockAddSelection = YES;
                }
            } else if ((_startPath.row == [first intValue] && indexPath.row > _startPath.row)) {
                if ([_selectedIndexes containsObject:@(indexPath.row-1)] && [_selectedIndexes count] > 0 && !_dirLockAddSelection) {
                    [_selectedIndexes removeObject:@(indexPath.row-1)];
                    _dirLockDelSelection = YES;
                }
            } else if ((_startPath.row == [last intValue] && indexPath.row < _startPath.row)) {
                if ([_selectedIndexes containsObject:@(indexPath.row+1)] && [_selectedIndexes count] > 0 && !_dirLockAddSelection) {
                    [_selectedIndexes removeObject:@(indexPath.row+1)];
                    _dirLockDelSelection = YES;
                }
            }

            NSArray *visibleCells = [_collectionView indexPathsForVisibleItems];
            NSSortDescriptor *rowDescriptor = [[NSSortDescriptor alloc] initWithKey:@"row" ascending:YES];
            NSArray *sortedRows = [visibleCells sortedArrayUsingDescriptors:@[rowDescriptor]];
            if (indexPath == [sortedRows lastObject]) {
                NSIndexPath *newPath = [NSIndexPath indexPathForRow:indexPath.row + 1 inSection:0];
                [_collectionView scrollToItemAtIndexPath:newPath atScrollPosition:UICollectionViewScrollPositionNone animated:YES];
            } else if (indexPath == [sortedRows firstObject]) {
                NSIndexPath *newPath = [NSIndexPath indexPathForRow:indexPath.row - 1 inSection:0];
                [_collectionView scrollToItemAtIndexPath:newPath atScrollPosition:UICollectionViewScrollPositionNone animated:YES];
            }
            NSIndexPath *temp = [sortedRows lastObject];
            NSLog(@"Current Row: %ld - Visible Cell Row: %ld", (long)indexPath.row, (long)temp.row);
            [_collectionView reloadData];
        }
    } else if(UIGestureRecognizerStateEnded == gesture.state) {
        CGPoint location = [gesture locationInView:_collectionView];
        NSIndexPath *indexPath = [_collectionView indexPathForItemAtPoint:location];
        NSLog(@"End: %ld", (long)indexPath.row);
        _orderedIndexes = [_selectedIndexes sortedArrayUsingSelector:@selector(compare:)];
        _dirLockAddSelection = NO;
        _dirLockDelSelection = NO;
        _gestureActivated = NO;
        [_collectionView reloadData];
    }
}

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return 100.0;
}

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [_rooms count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [_tableView dequeueReusableCellWithIdentifier:@"tableCellReserve" forIndexPath:indexPath];

    RoomTest *room = _rooms[indexPath.row];

    cell.textLabel.text = room.room;

    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    RoomTest *selRoom = _rooms[indexPath.row];
    _selectedRoom = selRoom.room;

    for (RoomTest *test in _rooms) {
        if ([_selectedRoom isEqualToString:test.room]) {
            NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[_cellsArray indexOfObject:test.start] inSection:0];

            int start = [_cellsArray indexOfObject:test.start];
            int end = [_cellsArray indexOfObject:test.end];
            _selectedIndexes = [[NSMutableArray alloc] init];
            for (NSString *time in _cellsArray) {
                if ([_cellsArray indexOfObject:time] >= start && [_cellsArray indexOfObject:time] <= end) {
                    [_selectedIndexes addObject:@([_cellsArray indexOfObject:time])];
                }
            }

            [_collectionView reloadData];
            [_collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionNone animated:YES];
        }
    }
}

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
    return 1;
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return 96;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath
{
    ReservationCollectionViewCell *cell = [_collectionView dequeueReusableCellWithReuseIdentifier:@"reserveCell" forIndexPath:indexPath];

    cell.upLine.hidden = YES;
    cell.leftLine.hidden = YES;
    cell.bottomLine.hidden = YES;
    cell.rightLine.hidden = YES;

    if ((indexPath.row % 2) == 0) {
        cell.timeLbl.text = _cellsArray[indexPath.row];
    } else {
        cell.timeLbl.text = @"";
    }

    int first = [[_selectedIndexes valueForKeyPath:@"@min.intValue"] intValue];
    int last = [[_selectedIndexes valueForKeyPath:@"@max.intValue"] intValue];

    if ([_selectedIndexes count] > 0) {
        if (indexPath.row == first && indexPath.row == last) {
            cell.leftLine.layer.borderColor = [UIColor redColor].CGColor;
            cell.leftLine.layer.borderWidth = 2.0;
            cell.leftLine.hidden = NO;
            cell.upLine.hidden = NO;
            cell.bottomLine.hidden = NO;
            cell.rightLine.hidden = NO;
            cell.rightLine.layer.borderColor = [UIColor redColor].CGColor;
            cell.rightLine.layer.borderWidth = 2.0;
        } else  if (first == indexPath.row) {
            cell.leftLine.layer.borderColor = [UIColor redColor].CGColor;
            cell.leftLine.layer.borderWidth = 2.0;
            cell.leftLine.hidden = NO;
            cell.upLine.hidden = NO;
            cell.bottomLine.hidden = NO;
            cell.rightLine.hidden = YES;
        } else if (last == indexPath.row){
            cell.leftLine.hidden = YES;
            cell.upLine.hidden = NO;
            cell.bottomLine.hidden = NO;
            cell.rightLine.hidden = NO;
            cell.rightLine.layer.borderColor = [UIColor redColor].CGColor;
            cell.rightLine.layer.borderWidth = 2.0;
        } else if ([_selectedIndexes containsObject:@(indexPath.row)]) {
            cell.leftLine.hidden = YES;
            cell.rightLine.hidden = YES;
            cell.upLine.hidden = NO;
            cell.bottomLine.hidden = NO;
        }
        if (_gestureActivated && (first == indexPath.row || last == indexPath.row)) {
            cell.leftLine.layer.borderWidth = 4.0;
            cell.rightLine.layer.borderWidth = 4.0;
        } else {
            cell.leftLine.layer.borderWidth = 2.0;
            cell.rightLine.layer.borderWidth = 2.0;
        }
    }

    return cell;
}

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewFlowLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
    return CGSizeMake(50.0, _collectionView.bounds.size.height);
}

-(IBAction)onOKBtnPressed:(id)sender {
    if ([_selectedIndexes count] > 0) {
        //        if (_delegate != nil) {
        int first = [[_selectedIndexes valueForKeyPath:@"@min.intValue"] intValue];
        int last = [[_selectedIndexes valueForKeyPath:@"@max.intValue"] intValue];

        //            NSArray *temp = [[NSArray alloc] initWithObjects:_cellsArray[first], _cellsArray[last], nil];
        //            [_delegate onSelectionEnded:temp];
        _resultLbl.text = [NSString stringWithFormat:@"Selected %@ from %@ to %@", _selectedRoom, _cellsArray[first], _cellsArray[last]];
        //        }
    }
}

@end

视图控制器在左侧包含一个显示房间号的垂直表格视图,在其右侧是显示时间线的集合视图。

当一个单元格被选中时,我只是在单元格中画一些线来显示它被选中。

非常欢迎任何帮助解决我的问题,也欢迎对我到目前为止编写的代码提出任何建议。

【问题讨论】:

    标签: ios objective-c uicollectionview uipangesturerecognizer


    【解决方案1】:

    我几乎解决了我遇到的所有问题。我现在唯一不喜欢的是当用户选择单元格并在屏幕边缘拖动手指时集合视图的“自动滚动”。

    集合视图应该滚动,而用户将手指放在屏幕上,选择必须继续。

    现在我得到了它,它可以工作,但是滚动不流畅,我一点也不喜欢它。

    这是修改后的 -didLongPress 方法:

    - (void)didLongPress: (UILongPressGestureRecognizer *)gesture {
        if (UIGestureRecognizerStateBegan == gesture.state) {
            _gestureActivated = YES;
            CGPoint location = [gesture locationInView:_collectionView];
            _startPath = [_collectionView indexPathForItemAtPoint:location];
            _lastIndex = _startPath;
            _orderedIndexes = [_selectedIndexes sortedArrayUsingSelector:@selector(compare:)];
            NSLog(@"Start: %ld", (long)_startPath.row);
        } else if (UIGestureRecognizerStateChanged == gesture.state) {
            CGPoint location = [gesture locationInView:_collectionView];
            NSIndexPath *indexPath = [_collectionView indexPathForItemAtPoint:location];
            NSLog(@"Changed: %ld", (long)indexPath.row);
            if ([_orderedIndexes count] == 0 && ![_selectedIndexes containsObject:@(indexPath.row)]) {
                [_selectedIndexes addObject:@(indexPath.row)];
            } else {
                NSNumber *first = (NSNumber*)[_orderedIndexes firstObject];
                NSNumber *last = (NSNumber*)[_orderedIndexes lastObject];
    
                if (_startPath.row == [last intValue] || _startPath.row == [first intValue]) {
                    if ([_selectedIndexes count] == 0) {
                        [_selectedIndexes addObject:@(indexPath.row)];
                    }
                    if ((_lastIndex.row - indexPath.row) == 1 || (_lastIndex.row - indexPath.row) == -1) {
                        if (![_selectedIndexes containsObject:@(indexPath.row)]) {
                            [_selectedIndexes addObject:@(indexPath.row)];
                        } else if ([_selectedIndexes containsObject:@(indexPath.row)] && [_selectedIndexes containsObject:@(_lastIndex.row)]) {
                            [_selectedIndexes removeObject:@(_lastIndex.row)];
                        }
                    }
    
                    _lastIndex = indexPath;
    
                    //Auto-scroll collectionview if touch is on the first or last visible cells
                    NSArray *visibleCells = [_collectionView indexPathsForVisibleItems];
                    NSSortDescriptor *rowDescriptor = [[NSSortDescriptor alloc] initWithKey:@"row" ascending:YES];
                    NSArray *sortedRows = [visibleCells sortedArrayUsingDescriptors:@[rowDescriptor]];
                    if (indexPath == [sortedRows lastObject]) {
                        NSIndexPath *newPath = [NSIndexPath indexPathForRow:indexPath.row + 1 inSection:0];
                        if (newPath.row <= [_cellsArray count]-1) {
                            [_collectionView scrollToItemAtIndexPath:newPath atScrollPosition:UICollectionViewScrollPositionRight animated:YES];
                        }
                    } else if (indexPath == [sortedRows firstObject]) {
                        NSIndexPath *newPath = [NSIndexPath indexPathForRow:indexPath.row - 1 inSection:0];
                        if (newPath.row >= 0) {
                            [_collectionView scrollToItemAtIndexPath:newPath atScrollPosition:UICollectionViewScrollPositionLeft animated:YES];
                        }
                    }
                }
            }
        } else if(UIGestureRecognizerStateEnded == gesture.state) {
            CGPoint location = [gesture locationInView:_collectionView];
            NSIndexPath *indexPath = [_collectionView indexPathForItemAtPoint:location];
            NSLog(@"End: %ld", (long)indexPath.row);
            _orderedIndexes = [_selectedIndexes sortedArrayUsingSelector:@selector(compare:)];
            _gestureActivated = NO;
        }
        [_collectionView reloadData];
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多