I have a collection view. I would like to programmatically select a cell. This is the code I use
[_collectionView selectItemAtIndexPath:[NSIndexPath indexPathForItem:currentSelectedVideo inSection:0] animated:YES scrollPosition:UICollectionViewScrollPositionNone];
For some reason the functions:
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
-(void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath
Are not called and therefore the visual effect I am using for showing the selected cell is not shown on the screen.
Is it a proper behavior?
You can make it.
[self.collectionView selectItemAtIndexPath:indexPath animated:YES scrollPosition:UICollectionViewScrollPositionNone];
[self collectionView:self.collectionView didSelectItemAtIndexPath:indexPath];
if use only selectItemAtIndexPath:animated:scrollPosition: method, don't call delegate method.
if use only collectionView:didSelectItemAtIndexPath: method, it don't work stabil
happy code :)
Yes, this is proper behaviour. Documentation for
[selectItemAtIndexPath:animated:scrollPosition:] says:
This method does not cause any selection-related delegate methods to be called.
Osmenda's answer in Swift with my custom collection view:
self.collectionView(calendarCV, didSelectItemAtIndexPath: indexPath)
Swift 4:
self.collectionView(daysCollectionView, didSelectItemAt: indexPath)
Related
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'm not using storyboard, everything is done by code..
and when I scroll the UICollectionView.. after it reusing correctly..some cells..
than it happen :
-the cell initWithFrame is being call
-new gray hair appear on my head.
I read other q/a and check maybe it's something with threads but all the reloadData is on the main thread.
any directions ?
I have no idea what's your code, so I'll propose how do I do it:
// somewhere in eg viewDidLoad
[self.collectionView setDelegate:self];
[self.collectionView setDataSource:self];
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:CellId];
And later the delegate:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = cell = [collectionView dequeueReusableCellWithReuseIdentifier:MyCellId forIndexPath:indexPath];
// do something with your cell, set title or anything
return cell;
}
There is another possibility. Your cell, as it's reusable, will have already saved previous properties. So if you did something like this:
if (iCanAddGrayHair) {
[cell.imageView setImage:[UIImage imageNamed:#"hair"]]
}
Then do notice, that new cell will still have this image set! You need to add:
else {
[cell.imageView setImage:nil];
}
To reset it from previous state. You can also override prepareForReuse: method of UICollectionViewCell class to reset the values (don't forget to call super).
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 have a UICollectionView controller embedded inside a navigation controller. The collectionView lists projects and each cell is supposed to segue to a ProjectDetail screen.
I simply cannot get the segue to trigger. If I simply drop a button on the nav bar and hook up a segue to the detail, it works. But triggering from my CollectionView cell doesn't.
Here is what the storyboard looks like: http://cl.ly/RfcM I do have a segue hooked up from the CollectionViewCell to the ProjectDetailViewController
Here's the relevant code inside my ProjectDetailViewController:
#interface ProjectCollectionViewController () {
NSArray *feedPhotos;
Projects *projects;
}
#end
#implementation ProjectCollectionViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self.collectionView registerClass:[FeedViewCell class] forCellWithReuseIdentifier:#"cell"];
[self loadData];
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"selected %d", indexPath.row);
Project *project = [projects getProject:indexPath.row];
NSLog(#"project = %#", project);
}
- (void)loadData {
[self.projectLoader loadFeed:self.username
onSuccess:^(Projects *loadedProjects) {
NSLog(#"view did load on success : projects %#", loadedProjects);
projects = loadedProjects;
[self.collectionView reloadData];
}
onFailure:^(NSError *error) {
[self handleConnectionError:error];
}];
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return projects.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
static NSString *identifier = #"cell";
FeedViewCell *cell = (FeedViewCell *) [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
cell.backgroundColor = [UIColor colorWithRed:0.0 green:0.0 blue:1.0 alpha:1.0];
UIImageView *cellImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
Project *project = [projects getProject:indexPath.row];
NSString *imageUrl = [project coverPhotoUrl:200 forHeight:200];
NSLog(#"imageurl =>%#", imageUrl);
if (imageUrl) {
[cellImageView setImageWithURL:[NSURL URLWithString:imageUrl]];
}
[cell addSubview:cellImageView];
cell.imageView = cellImageView;
return cell;
}
I'm guessing the problem is somewhere in how I'm hooking up the Cells to the CollectionView.
Any help would be greatly appreciated!
You cannot create segues directly from cells in a storyboard because the collectionview is populated dynamically through the data source. You should use the collectionView:didSelectItemAtIndexPath: and perform the segue programatically using performSegueWithIdentifier:sender:. Something like this:
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
[self performSegueWithIdentifier:#"MySegueIdentifier" sender:self];
}
where MySegueIdentifier is the identifier of the segue defined in storyboard.
TLDR: FOR A STORYBOARD, do not call registerClass:forCellWithReuseIdentifier:. It overrides what the storyboard sets up for the cell (including how segues are handled):
How to set a UILabel in UICollectionViewCell
Brief setup
Used a storyboard
Created a new collection view controller using the Xcode template,
setting it as a subclass of UICollectionViewController.
Initially used the default UICollectionViewCell, adding a UILabel
programmatically.
The generated UICollectionViewController code registered the cell in viewDidLoad:
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:reuseIdentifier];
First Issue:
The prepareForSegue:sender: event was not firing, which brought me to this answer .
I implemented the UICollectionViewDelegate and collectionView:didSelectItemAtIndexPath: event, then called the segue programmatically.
This fixed my first issue.
Second Issue: I switched to a custom cell containing one label. After hooking everything up, the cell label was not displaying.
After some digging, I found a solution contained in the link at the top of my answer.
Third Issue and Solution: I removed the registerClass:forCellWithReuseIdentifier: line. When I ran my app, the label appeared correctly, but when I tapped a cell, it called the prepareForSegue:sender event twice. By removing the registerClass:forCellWithReuseIdentifier line, the cell was processing cell touches directly, without the need of the delegate method. This is how I expected the storyboard to work. I deleted the collectionView:didSelectItemAtIndexPath: event, which resolved the double-firing of prepareForSegue:sender:. If you are using a storyboard, do not register the cell class. It overwrites what storyboard sets up.
Have you made your CollectionView Cell's connection in Triggered Segues on selection?
You can also trigger a segue programatically using
[self performSegueWithIdentifier:#"segueIdentifier" sender:nil]
in
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
Equivalent Swift code for similar question.
override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier(#"TargetSegway", sender: self)
}
Make sure, in case if your cell has other overlapping views, "User Interaction Enabled" is unchecked (you can find this option, under attribute inspector View/Interaction). Otherwise, your Tap Gesture is consumed by the overlapping view, didSelectItemAtIndexPath may not be called.
I have a tableView that I have set allowsMultipleSelection to YES in storyboard.
EDIT
I was wrong about one thing... [tableView indexPathsForSelectedRows] does return a NSArray with 1 object in it during didSelectRowAtIndexPath.
However it does not work in cellForRowAtIndexPath after I reload the table so it will check which accessory (check mark or not) to apply.
In the original question I was trying to manually select the rows... Apparently that is handled by the tableView itself.. but somewhere along the way it is automatically deselecting my row as I never call deselectRowAtIndexPath on it...
Original Question:
For some reason when I set the cell to selected it does not change.
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
//cell does not update selected property to YES after this next line
cell.selected = YES;
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
}
I suppose I can keep track of the selected index paths myself... but I can swear I used a method that involved indexPathsForSelectedRows previously with success...
You cannot set the selected property directly
So instead of
cell.selected = YES;
Use
[tableView selectRowAtIndexPath:TheIndexPAth animated:YES scrollPosition:UITableViewScrollPositionBottom];
please post your all codes for this class in pastbean and put your link here we need more information,
and also try:
//in your interface
#interface YourClass (){
NSInteger _selectedIndex;
}
// cellForRowAtIndexPath: method
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath
*)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
// didSelectRowAtIndexPath: method
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
_selectedIndex = indexPath.row;
[self.tableView reloadData];
}
Try [cell setSelected:YES animated:YES]
I'm pretty sure cell.selected is read only
A bit unfair since the question changed but.. for me.. the answer is either don't use
indexPathsForSelectedRows
or don't call
reloadTable
on your tableView.
I opted for the later, I decorated the accessory in didSelectRow and didDeselectRow instead of doing it on reload and just never reloading the table.
If someone can come up with a solution that involves both of the above, I will select that answer instead.