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.. :)
Related
I implemented a calendar view with UICollectionView, when scrolling the calendar view very fast, it's not smooth. So I'm thinking whether I can load static content of each cell firstly, and then refresh once specific content has been loaded. So how to delay loading specific contents of each UICollectionViewCell
Specifically, in below function, I'll construct each UICollectionViewCell and return it. Now I just want to construct static contents (such as the date), and delay loading specific contents (such as the background color, if I have an event this day, I'll change the background of this cell), so where should I load specific contents, and how to only refresh showing cell
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [self.collectionView dequeueReusableCellWithReuseIdentifier:UICollectionViewCellIdentifier
forIndexPath:indexPath];
NSDate *date = [self dateAtIndexPath:indexPath];
cell.dateLabel.text = [date description];
// This is the part I want to delay, since it's cost.
if (dataModel.hasEventAtDate(date)) {
cell.dateLabel.backgroundColor = [UIColor blue];
}
return cell;
}
You may need have an instance variable to track if cells need to update:
Boolean cellNeedsUpdate = NO
In cellForItemAtIndexPath, check if you need to fully update the cells:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
if (cellNeedsUpdate) {
// fully update the cell
} else {
// do partial update
}
}
Track end scrolling of the collectionView, then reload the collectionView:
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
cellNeesUpdate = !cellNeedsUpdate;
[collectionView reloadData];
}
I have code:
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return 30;
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:REUSE_IDENTIFIER forIndexPath:indexPath];
[[cell subviews]
makeObjectsPerformSelector:#selector(removeFromSuperview)];
[cell addSubview:someView];
return cell;
}
Above code gets executed in viewWillAppear
If I make the above code executed 30 times, the view appearance is really slow.
Due to cell reuse, I need to make a call to removeFromSuperView. Otherwise stale wrong data is displayed on the cell.
I am not able to figure out what could be causing the slowness??
Can you provide hints?
Your appearance is slow because you are iterating through all the subviews within the cell and removing from superview. This is a very expensive process and should not be done in the cellForItemAtIndexPath method of the collectionView data source/ Infact this should never be done. If you need to display relevant content you need to access the instance of the cell and update the properties of the UI elements within the cell.
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 UITableView with a cell that has two labels in it. The table view is linked to the dataSource and delegate, the labels in the cell are linked to an IBOutlet, what not. It looks to me like this should work, but this code below is not running so the Cell or labels are not populated with text. Any ideas? Or anything I'm missing?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"theLabelCell";
CustomClassCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
CustomClassText *customText = _arrayThatHasText[indexPath.row];
if (![self isSelectionMode]) {
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
cell.TitleLabel.text = customText.firstLabel;
cell.TextLabel.text = customText.secondLabel;
return cell;
}
Did you remember to also register the cell identifier for reuse?
- (void)viewDidLoad
{
[super viewDidLoad];
[self.tableView registerNib:[UINib nibWithNibName:#"CustomClassCell" bundle:nil] forCellReuseIdentifier:#"theLabelCell"];
}
If you are not seeing any cells, then check whether numberofSections and numberOfRowsInSection delegate methods are not returning 0
When does your _arrayThatHasText get populated? The issue might very well be that the data source (_arrayThatHasText) is getting instantiated before the numberofSections and numberOfRowsInSection delegate methods are being called and then after these methods are called the data source is being populated with actual data -> which would result in the 0 values in the delegate methods as you are experiencing.
You might want to try putting a [self.tableView reloadData] call at the end of ViewWillAppear or in ViewDidAppear method and see if that helps.
I have a test application I have made for a part of my workflow. What I am trying to achieve is a fancy way of showing the user what they are typing for a Word styled game.
At the moment this is the approach but there could be an easier/better route. I have a UITextField which is not shown to the user and the keyboard is shown on viewDidLoad. What I am trying to have happen is each time a letter is pressed on the keyboard a new Tile showing the letter capitalised is added to the screen area above i.e. 'W', then another letter would mean another tile added i.e. 'I' next to the previous...
I have setup a UICollectionView and custom cell with a label in, that is all. The VC is the dataSource of the UICollectionView. The UITextField also has its delegate set to the self (the VC).
I cannot work out how to have the tiles (cells) created each letter.
#pragma mark -
#pragma mark - Key board delegate methods
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSLog(#"%s",__PRETTY_FUNCTION__);
NSString *lastLetterTyped = [textField.text substringFromIndex:[textField.text length] - 1];
[self.wordArray addObject:lastLetterTyped];
[self.tileCollectionView reloadData];
return YES;
}
#pragma mark -
#pragma mark - Collection View Data Source Methods
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return 3;
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath {
// we're going to use a custom UICollectionViewCell, which will hold an image and its label
//
WordCVCell *cell = [cv dequeueReusableCellWithReuseIdentifier:kCellID forIndexPath:indexPath];
// make the cell's title the actual NSIndexPath value
NSString *lastLetter = [self.typedWord substringFromIndex:[self.typedWord length] - 1];
cell.label.text = lastLetter;
return cell;
}
Your
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return 3;
}
Should read as
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
[self.wordArray count];
}
This will trigger the following the same number of times as there are objects in your array.
-(UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath {
// we're going to use a custom UICollectionViewCell, which will hold an image and its label
//
WordCVCell *cell = [cv dequeueReusableCellWithReuseIdentifier:kCellID forIndexPath:indexPath];
// make the cell's title the actual NSIndexPath value
NSString *lastLetter = [self.wordArray objectAtIndex:indexPath.row];
cell.label.text = lastLetter;
return cell;
}
You need to have a NSMutableArray that you will add to each time the user types a character. For that you need to hook up your controller to UITextfieldDelegate. After that each time you add to this array you need to call [collectionView reloadData] and your number of items will be [myMutableCharacterArray count];
So basically each time a user types a letter, add it to a mutable array and call [collectionView reload data] to refresh the collectionview.