Hi I am developing small IOS application and I am new to IOS development. In my application I am using collection view to display my data. What i am doing I am fetching data from my server and then displaying in my UIView controller. Here is my code looks like
- (void)viewDidLoad
{
[super viewDidLoad];
// call for fetching data from server
}
// My collection view methods
-(NSInteger) numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
-(NSInteger) collectionView:(UICollectionView *)collectionView numberOfItemsInSection: (NSInteger)section
{
return [_channelArray count];
}
-(UICollectionViewCell *) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Cell" forIndexPath:indexPath];
cell.image = // set image from channel array.
return cell;
}
// callback for m web service call
-(void) didReceiveSubscriberChannelList:(SubscriberChannelListDataModel *)subscriberChannelListInfo
{
_channelList = subscriberChannelListInfo;
_channelArray = subscriberChannelListInfo.chanellist;
[collectionView reloadData];
}
Above code works with static data. But now I want to display my server data. My reload data not working. How to do this. Need Help. Thank you.
Did you consider put the callback method data in a block?
// callback for m web service call
-(void) didReceiveSubscriberChannelList:(SubscriberChannelListDataModel *)subscriberChannelListInfo
{
dispatch_async(dispatch_get_main_queue(), ^{
_channelList = subscriberChannelListInfo;
_channelArray = subscriberChannelListInfo.chanellist;
[collectionView reloadData];
});
}
This way, when the callback returns it will reload the data in the main thread (the UI thread)
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've been working my apps to run on iOS 8 and trying to consume data from the restful API. After getting response from the webservice I'm trying to reload the collectionview from the delegate method.I get the valid numeric count as 5 from my array for numberOfItemsInSection but cellForItemAtIndexPath not getting called.
I see in one scenario, If I hardcode the numberOfItemsInSection return count as 5 then cellForItemAtIndexPath is perfectly called while reload.
Here is my code snippet:
#pragma mark = UICollectionViewDataSource
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return [offerModel.arrayOffers count];
}
- (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView
cellForItemAtIndexPath:(NSIndexPath*)indexPath {
NSString *identifier = #"OfferCell";
static BOOL nibMyCellloaded = NO;
if(!nibMyCellloaded){
UINib *nib = [UINib nibWithNibName:identifier bundle: nil];
[offerCollectionView registerNib:nib forCellWithReuseIdentifier:identifier];
nibMyCellloaded = YES;
}
OfferCell* cell = (OfferCell *)[collectionView dequeueReusableCellWithReuseIdentifier:identifier
forIndexPath:indexPath]; // // Commented binding values return
cell;
}
- (void)updateOfferList{
[offerCollectionView reloadData];
}
-(void)viewDidLoad{
[offerCollectionView registerClass:[OfferCell class] forCellWithReuseIdentifier:#"OfferCell"];
// set up delegates
self.offerCollectionView.delegate = self;
self.offerCollectionView.dataSource = self;
}
Please help me on this. Quick replies are most appreciated. Thanks
Finally I found an answer for my blocker. I just Reloading some items didn't work for me using reload data. Since CV default flow layout does some internal operation itself to reload data when we forced, In my case, I'm using customviewlayout here layoutAttributesForItemAtIndexPath and layoutAttributesForElementsInRect called only when the section gets loaded. Here it works because the collectionView has just one section, I've reloaded specific section would make contents correctly reloaded in the CV.
At my API handler delegate method placed the below code snippet,
[self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:0]];
[self.collectionView reloadData];
Thanks.
this is my storyboard view and it's connections:
http://i.stack.imgur.com/uD0pT.png
http://i.stack.imgur.com/FNnVa.png
In my specific case I have the searchResultsTableView that gets its data from the first external web service and the self.tableview that fetches data from another web service.
I add some code to be clear:
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString { ... }
this fetched the first web services, in particular
return NO
and there is a:
[self.searchDisplayController.searchResultsTableView reloadData];
to reload the data when the fetch is completed.
Then we have:
-(void) doSearch:(NSString*) keyword inStore:(NSInteger) store getPage: (int) pagenum {..}
that fetches the second web service and set the results in an array called 'fetchedItems'
Now, to manage this two tables I had to write this method:
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
NSLog(#"Avvio ricerca..");
// Do the search...
NSInteger store = [self buttonSelected];
[self doSearch:searchBar.text inStore:store getPage:1];
[self.searchDisplayController setActive:NO];
}
I tried without the 'setActive:NO' but the self.searchDisplayController.searchTableView remains displayed and I can't se the "underneath" self.tableView with the 'doSearch' results
Ok. Now I have this method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"foundCell";
static NSString *suggestionCellIdentifier = #"suggestionCell";
UITableViewCell *cell;
if (tableView == self.searchDisplayController.searchResultsTableView) {
// HERE I AM WITH SEARCHDISPLAYCONTROLLER
cell = [self.tableView dequeueReusableCellWithIdentifier:suggestionCellIdentifier];
cell.textLabel.text = [self.suggestions objectAtIndex:indexPath.row];
} else {
// HERE I AM WITH SELF.TABLEVIEW
}
return cell;
}
Now it works, but there's a problem!
When i tap on the tableview with the results (denoted by self.tableview) I can't catch the tap with the method
- (void) tableView: (UITableView *) tableView didSelectRowAtIndexPath: (NSIndexPath *) indexPath {...}
but instead I get the re-opening of the uisearchdisplaycontroller in edit mode (so the user can tap inside the searchbar)
Where am I wrong?
fixed! When using
displaysSearchBarInNavigationBar = YES
we need that the searchbar is OUT for the tableview in the storyboard!
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.
I'm kinda newbie in UICollectionView and I'm working in a project that dynamically changes the UICollectionViewLayout in a given action.
My CollectionView has 6 sections, each of them with 10 elements. Those Cells are basically an UIImageView and my Custom Layout called StackViewLayout stacks all elements for each section (something like Apple's Photos.app).
If the user selects the element of the stack (for all sections), the UICollectionView dynamically changes the layout to the UICollectionViewFlowLayout, so all the elements can be viewed as grid.
My problem is that when user selects a stack, no matter which section, when the Layout is changed do Flow Layout, all sections are displayed in the grid, instead of displaying the elements for the selected section (stack), which is the behavior I wanted.
Is there any way to show only the Flow Layout for the selected section in the Custom Layout?
Here is my Controller Implementation snippet code:
- (void)viewDidLoad
{
[super viewDidLoad];
[self loadStackLayout]; // stack all sections at first load.
}
#pragma mark - UICollectionView Data Source Methods
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 6;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return 10;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath;
{
// custom UICollectionViewCell, which will hold an image.
CVCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"MyCell" forIndexPath:indexPath];
cell.imageView.image = _images[indexPath.row];
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
// element size.
return CGSizeMake(100,100);
}
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
if (isStacked)
{
[self loadFlowLayout]; //HERE I WANT TO LOAD FLOW LAYOUT ONLY FOR THE SECTION OF THE SELECTED ITEM!
} else
{
// to implement.
}
}
// HERE IS THE METHOD THAT CALLS MY CUSTOM LAYOUT IN ORDER TO STACK THE ELEMENTS FOR EACH SECTION IN COLLECTION VIEW. IT IS WORKING AS IT SHOULD.
-(void)loadStackLayout
{
if (([self.collectionView.collectionViewLayout isKindOfClass:[UICollectionViewFlowLayout class]]))
{
isStacked = YES;
[self.collectionView setCollectionViewLayout:[[StackViewLayout alloc] init] animated:YES];
}
}
// HERE IS THE METHOD THAT CALLS MY FLOWLAYOUT IN ORDER TO UN-STACK THE ELEMENTS AND SHOW THEM IN A GRID. CURRENTLY IT IS SHOWING ALL SECTIONS IN THE GRID.
-(void)loadFlowLayout
{
if (([self.collectionView.collectionViewLayout isKindOfClass:[StackViewLayout class]]))
{
isStacked = NO;
[self.collectionView setCollectionViewLayout:[[UICollectionViewFlowLayout alloc] init] animated:YES];
}
}
I think you can probably do it by having an if clause in your numberOfItemsInSection: method, to return 0 for any section that's not the selected one. Obviously, you'll need to keep track of the selected section to do this.