[英]Selecting multiple cells in a UICollectionView
我想要实现的是类似于 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
视图控制器在左侧包含一个垂直表格视图,显示房间的编号,在其右侧有一个显示时间轴的集合视图。
当一个单元格被选中时,我只是在单元格中画一些线来显示它被选中了。
任何解决我的问题的帮助都是非常受欢迎的,对我到目前为止编写的代码的任何建议也是如此。
我几乎解决了我遇到的所有问题。 我现在唯一不喜欢的是当用户选择单元格并在屏幕边缘拖动手指时集合视图的“自动滚动”。
集合视图应该滚动,而用户将手指放在屏幕上,选择必须继续。
正如我现在得到的那样,它可以工作,但滚动不流畅,我根本不喜欢它。
这是修改后的 -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];
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.