在UICollectionView中选择多个单元格

问题描述 投票:1回答:1

[我想要实现的是类似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个回答
0
投票

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

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

正如我现在所知道的那样,它可以工作,但是滚动并不流畅,我根本不喜欢它。

这是修改后的-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];
}
© www.soinside.com 2019 - 2024. All rights reserved.