When i tap one of UICollectionView's cell more than once-double tap, triple tap-, it's delegate method didSelectItemAtIndexPath also get called more than once. What can be the slickest way to prevent it?
I would appreciate any comments.
You can use your model object to hold selected property in it (or you can create a boolean array for only this purpose) . And check it in shouldSelectItemAtIndexPath method.
#cihangirs code:
- (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath {
if (someModel.isSelected) {
return NO;
} else {
someModel.isSelected = YES;
return YES;
}
}
This is safest way to do your objective:-
(void)collectionView:(UICollectionView *)collectionView
didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
if([[collectionView indexPathsForSelectedItems] containsObject:indexPath]) // checking whether cell is already selected or not
{
return;
}
else
{
// do whatever you want to do on selection of cell
}
}
The thing happening here is, whenever you select a cell it automatically get stored "indexPathsForSelectedItems" of Collection view, so the next time you tap on the selected cell again this method [[collectionView indexPathsForSelectedItems] containsObject:indexPath] will check whether that cell is already selected or not , if yes then it will return the method so that it doesnot go any step further.
Related
Hello everyone I have a problem with the selection of cells in my collection.
To manage the selection and deselection, of course, I have provided the delegated methods didSelectItemAtIndexPath and didDeselectItemAtIndexPath
Everything works correctly but I have a problem that I can not solve. In short, when I selected a cell I would like to have the possibility to deselect the last cell selected by reselecting the cell itself ... for example
I will use a name for the cell to make you understand my problem better
The user selects the cell "22" to deselect it. I would like the user to reselect cell 22 again and deselect it.
I tried to use allowMultipleSelection = YES and this seems to be in the system that I prefer but the problem is that the cell is not reselected, all the other entries selected and so it is wrong ... How can I solve this problem ... ??
This is the code I utilize for select and deselect the cell
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
SmartCalendarDayCell *calendarDayCell = (SmartCalendarDayCell *)[self.dayCollectionView cellForItemAtIndexPath:indexPath];
calendarDayCell.day.textColor = [UIColor colorWithHexString:#"#D97E66" setAlpha:1];
}
-(void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath {
SmartCalendarDayCell *calendarDayCell = (SmartCalendarDayCell *)[self.dayCollectionView cellForItemAtIndexPath:indexPath];
calendarDayCell.day.textColor = [UIColor lightGrayColor];
}
As I understand, you want your collectionView can only select 1 cell at a time and if selected cell is clicked again, it will be deselected. If I'm misunderstanding anything, please tell me.
First
You shouldn't change textColor of day in didSelectItemAtIndexPath and didDeselectItemAtIndexPath methods. Because when you scroll collectionView, cells will be reused and color of day will be wrong for some cells.
To resolve it, using property selected of UICollectionViewCell.
SmartCalendarDayCell.m
- (void)setSelected:(BOOL)selected {
[super setSelected:selected];
if (selected) {
self.day.textColor = [UIColor colorWithHexString:#"#D97E66" setAlpha:1];
} else {
self.day.textColor = [UIColor lightGrayColor];
}
}
Second
To deselect selected cell, you should check and do it on collectionView:shouldSelectItemAtIndexPath: method.
- (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath {
if ([collectionView.indexPathsForSelectedItems containsObject:indexPath]) {
[collectionView deselectItemAtIndexPath:indexPath animated:NO];
return NO;
}
return YES;
}
For more detail, you can check my demo repo here.
I want to call didSelectItemAtIndexPath: for particular index path but I can't call it programmatically in cellForItemAtIndexPath because collection is not yet ready, I will get cell as nil. Do we have any delegate method or any other UIView method that is called after collection view is ready?
I have tried willDisplayCell: but it is not made for relevant work, couldn't find anything else.
I want to call didSelectItemAtIndexPath:
Don't. This is a delegate method. It is called by the runtime when the user selects an item. You must never call this yourself.
You have to do it programmatically utilising your manual logics. :)
The underlying concept is that get the indexes of selected cells and reload those specific cells only.
Declare a global var
NSMutableArray array_indexpath;
in your did select method add indexes of selected cells.
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
array_indexpath=[[NSMutableArray alloc]init];
[array_indexpath addObject:indexPath];
[self.myCollectionView reloadItemsAtIndexPaths:array_indexpath];
}
and in your cell for cellForItemAtIndexPath method check the indexes and reload it as required.
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
ShubhCalendarCollectionViewCell *cell =[collectionView dequeueReusableCellWithReuseIdentifier:#"ShubhCalendarCollectionViewCell" forIndexPath:indexPath];
cell.backgroundColor=[UIColor clearColor];
if (array_indexpath.count !=0)
{
for (int i=0; i<[array_indexpath count]; i++)
{
if ([array_indexpath objectAtIndex:i] == indexPath)
{
cell.backgroundColor=[UIColor greenColor];
}
}
}
return cell;
}
Hope it helps.. Happy Coding.. :)
I have a problem when tap an item into CollectionView.
didSelectItemAtIndexPath doesn't called when tapped the item. Only execute this method when hold the item.
This is the method implementation.
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"did select at index path %#", indexPath);
_magazine = [[AppController instance] magazines][indexPath.row];
[self loadEditionsForMagazine:_magazine];
_magazineEditionsView.hidden = NO;
}
My CollectionView is linked to the datasource and delegate.
Thanks.
Check these:
Nothing is upon your UICollectionView.
No subviews of UICollectionView receiving gesture before UICollectionView.
Or there is no other gesture recognition active.
Hope this helps.. :)
I want to use KVO to be notified when the number of selected cells in a UICollectionView changes. When I tried to subclass UICollectionView and add a new property nSelectedCells, I ran into a problem when trying to add the logic that updates nSelectedCells. There are too many places where the selected cells count can change:
Programmatically - View: deselectItemAtIndexPath, selectItemAtIndexPath, reloadData, ...
UI - Controller: didDeselectItemAtIndexPath, didSelectItemAtIndexPath
More?
What would be the best way to keep track of this value. Preferably from within the UICollectionView subclass.
UICollectionViewCell has a selected property. You could override the setter for this method, as it's the only thing guaranteed to be called when a cell's selection status is changed.
Perhaps subclass a UICollectionView with a property to keep a counter of selected cells and register for notifications fired by your UICollectionViewCell subclasses in setSelected: based on whether the cells was selected or deselected.
As a note, just because setSelected: was called doesn't mean the selection status has changed.
- (void)setSelected:(BOOL)selected {
if (super.selected != selected) {
if (selected) {
// cell was unselected and became selected, increase counter
} else {
// cell was selected and become unselected, decrease counter
}
}
super.selected = selected;
}
use a NSMutableSet to track selected cell's index path, when select a cell, add its indexPath to set; deselect a cell, remove its index path from set.
The collection view calls these methods only when the user successfully selects/deselect an item in the collection view. It does not call the method when you programmatically set the selection/deselection.
#property (nonatomic) NSMutableSet *selectedCellIndexPathsSet;
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
//do some things.
[self.selectedCellIndexPathsSet addObject:indexPath];
}
- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath
{
//do some thing.
[self.selectedCellIndexPathsSet removeObject:indexPath];
}
I'm using GLTapLabel to display my text in my UITableView. It will have some links I can click on as GLTapLabels, but when I click those links the tableView:didSelectRowAtIndexPath: fires. So how can I detect the click action in those links?
Implement tableView:willSelectRowAtIndexPath: and return nil for any row you don't want to be selected.
Return Value
An index-path object that confirms or alters the selected row. Return an NSIndexPath object other than indexPath if you want another cell to be selected. Return nil if you don't want the row selected.
For example, to only prevent selection in the first section:
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 0) {
return nil;
}
return indexPath;
}
You can also try setting exclusiveTouch on the GLTapLabel or overriding its hitTest:withEvent: as described in the answer to Why is UIView exclusiveTouch property not blocking?.