Display multiple custom cells in a UITableView? - objective-c

I am using Xcode 4.2 on SnowLeopard, and my project is using storyboards. I am trying to implement a UITableView with 2 different custom cell types, sessionCelland infoCell. I can get the 2 types to appear within the same list, but now I have a new problem?! The sessionCell is displayed once, and then X number of infoCells are displayed after it - just as I wanted - except that the first infoCell is always overwritten by the sessionCell!
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
return [self.people count];
}
//inside cellForRowAtIndexPath
if(indexPath.row == 0) {
cell = [tableView dequeueReusableCellWithIdentifier:#"sessionCell"];
} else {
cell = [tableView dequeueReusableCellWithIdentifier:#"infoCell"];
}
...
return cell;
I've tried to say return array count + 1, or even hardcoded return 7 (it fits my example) but both are incorrect!
myObject *person = [self.people objectAtIndex:indexPath.row];
Or does my problem lie in the above line? I've even tried indexPath.row+1...
Any help would be greatly appreciated!!

If I understand your question correctly, the first infoCell (second UITableView row) should display the first person object's data, right?
Then it seems you want:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *sessionCellID = #"sessionID";
static NSString *infoCellID = #"infoID";
if( indexPath.row == 0 ) {
SessionCellClass *cell = nil;
cell = (SessionCellClass *)[tableView dequeueReusableCellWithIdentifier:sessionCellID];
if( !cell ) {
// do something to create a new instance of cell
// either alloc/initWithStyle or load via UINib
}
// populate the cell with session model
return cell;
}
else {
InfoCellClass *cell = nil;
cell = (InfoCellClass *)[tableView dequeueReusableCellWithIdentifier:infoCellID];
if( !cell ) {
// do something to create a new instance of info cell
// either alloc/initWithStyle or load via UINib
// ...
// get the model object:
myObject *person = [[self people] objectAtIndex:indexPath.row - 1];
// populate the cell with that model object
// ...
return cell;
}
}
and you need to return [[self people] count] + 1 for the row count:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [[self people] count] + 1;
}
so that the n'th row shows the (n-1)th data.

if you look at the if else section it shows that the first row is an "sessionCell" and all other rows are "infoCells" what i think you want to do is make the first row an sessionCell, the second row an infoCell and all of the other rows peopleCells
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.people count] + 2; // Added two for sessionCell & infoCell
}
//inside cellForRowAtIndexPath
if(indexPath.row == 0) {
cell = [tableView dequeueReusableCellWithIdentifier:#"sessionCell"];
} else if (indexPath.row == 1 {
cell = [tableView dequeueReusableCellWithIdentifier:#"infoCell"];
} else {
cell = [tableView dequeueReusableCellWithIdentifier:#"personCell"];
Person *person = [self.people objectAtIndex:index.path.row - 2];
}
...
return cell;
Better yet, I would try to make two different sell sections, one for info and one for people
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 2;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return section == 0 ? 2 : self.people.count
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell = nil;
if (indexPath.section == 0) {
if(indexPath.row == 0) {
cell = [tableView dequeueReusableCellWithIdentifier:#"sessionCell"];
// configure session cell
} else if (indexPath.row == 1 {
cell = [tableView dequeueReusableCellWithIdentifier:#"infoCell"];
// configure info cell
}
} else {
cell = [tableView dequeueReusableCellWithIdentifier:#"infoCell"];
Person *person = [self.people objectAtIndexPath:indexPath.row];
// configure person cell
}
return cell;
}

Related

How to load tableview based on button values with custom cells?

In my app I want to display a tableview(custom cells) based on button tags,when I am clicking on my 1st button it is showing empty table view and clicking on 2nd button it is showing 1st button data.
Here is my Code upto now i tried,
I am Calling my IBAction button in ViewDidLoad Method,
- (void)viewDidLoad
{
value1=0;
[self details:nil];
}
Here is my IBAction Method,
-(IBAction)details:(id)sender
{
value1 = 0;
detaiLine.hidden = NO;
rewardLine.hidden = YES;
[testTableView reloadData];
}
Here is my tableViewDataSource Methods,
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return responseArray.count;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (value1 == 0)
{
return 104;
}
if(value1 == 1)
{
return 180;
}
return 0;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (value1 == 0)
{
static NSString *cellId = #"Cell1";
ContestDetailCell1 * cell = (ContestDetailCell1 *)[contestTableView dequeueReusableCellWithIdentifier:cellId];
if (cell == nil)
{
NSArray *myNib;
myNib = [[NSBundle mainBundle]loadNibNamed:#"ContestDetailCell1" owner:self options:nil];
cell = [myNib lastObject];
}
}
if(value1 == 1)
{
static NSString *cellIdentifier = #"Cell2";
ContestDetailCell2 *cell = (ContestDetailCell2 *)[contestTableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil)
{
NSArray *myNib;
myNib = [[NSBundle mainBundle]loadNibNamed:#"ContestDetailCell2" owner:self options:nil];
cell =[myNib objectAtIndex:0];
}
}
What is the problem in my code.
You are not assigning tag value to your value1 variable. Try this code,
-(IBAction)details:(id)sender
{
value1 = sender.tag;
detaiLine.hidden = NO;
rewardLine.hidden = YES;
[testTableView reloadData];
}
I think that you have not implemented your logic correctly. I didn't understand why you are calling IBAction from viewdidload.
Please find this as a work around,
add tag for each button in xib or using code.
In your IBAction Method get the tag and identify the button as follows,
-(IBAction)details:(id)sender
{
value1 = sender.tag;
\\your remaining code here
}
Using this value1 load your data in table view.
Hope this will help you. Please correct me if i'm wrong. :P

UITableView scroll is never end after search

I have UITableView to show whole bunch of words from array.
I also provide search bar on top of table view so when people type a word in textbox search then my code start filtering data from array.
My result is good but my scroll in tableview is never end even though there is only one row.
My tableview result can scroll down and down without no row.
I don't know what going on with my table view.
My code that I have implement.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
if(self.tableView == tableView){
return [self.alphabet count];
}else{
return 1;
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (self.tableView == tableView) {
return [[self.vocabularyInfo objectAtIndex:section] count];
}else{
return [self.filteredVocabs count];
}
}
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return [self.alphabet objectAtIndex:section];
}
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
if(self.tableView == tableView){
return self.alphabet;
}else{
return nil;
}
}
// Display cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellIdentifier = #"CommentTableCell";
//-- try to get a reusable cell --
CommentTableCell *cell = (CommentTableCell *) [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
//-- create new cell if no reusable cell is available --
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:cellIdentifier owner:self options:nil];
cell = [nib objectAtIndex:0];
}
VocabularyController *vc;
// Display word from database else display vocabulary when searching
if (tableView != self.searchDisplayController.searchResultsTableView) {
vc = [self.vocabularyInfo[indexPath.section] objectAtIndex:indexPath.row];
}else{
vc = [self.filteredVocabs objectAtIndex:indexPath.row];
}
cell.nameLabel.text = vc.korean;
return cell;
}
// My method that I used for filtering my array to display the result
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString{
if (searchString.length > 0) {
NSArray *vocabToSearch = self.vocabularyInfo;
if (self.currentSearchString.length > 0 && [searchString rangeOfString:self.currentSearchString].location == 0) {
vocabToSearch = self.filteredVocabs;
}
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"korean CONTAINS[cd] %#", searchString];
self.filteredVocabs = [vocabToSearch filteredArrayUsingPredicate:predicate];
} else {
self.filteredVocabs = self.vocabularyInfo;
}
self.currentSearchString = searchString;
return YES;
}
Please help me!!
Check your tableview's datasource delegate function.
Maybe more detail about your implementation is helpful.
Please check the value you are returning for the number of rows in the following method:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

UISearchDisplayController Not Displaying Results in searchResultsTableView

I have a UISearchDisplayController properly connected to the header of a custom UITableView in IB. However, when I search for anything the searchResultsTableView only displays "No Results", and I cannot seem to find where the code is incorrect.
searchResults Property
- (NSMutableArray *)searchResults {
if (!_searchResults) {
_searchResults = [[NSMutableArray alloc] initWithCapacity:self.listingPreviews.count];
}
return _searchResults;
}
Table View Data Source Methods
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
NSInteger numberOfRows = 0;
if (tableView == self.tableView) {
numberOfRows = self.listingPreviews.count;
} else {
numberOfRows = self.searchResults.count;
}
return numberOfRows;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Listing";
ListingPreviewTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[ListingPreviewTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell.
if (tableView == self.tableView) {
cell.listingPreview = [self.listingPreviews objectAtIndex:indexPath.row];
} else {
NSLog([[self.searchResults objectAtIndex:indexPath.row] title]);
cell.listingPreview = [self.searchResults objectAtIndex:indexPath.row];
}
return cell;
}
Search Bar Delegate Method
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
NSInteger searchTextLength = searchText.length;
for (ListingPreview *listingPreview in self.listingPreviews) {
if ((listingPreview.title.length >= searchTextLength) && ([listingPreview.title rangeOfString:searchText].location != NSNotFound)) {
[self.searchResults addObject:listingPreview];
}
}
}
Just try this instead:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Listing";
ListingPreviewTableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell.
if (tableView == self.tableView) {
cell.listingPreview = [self.listingPreviews objectAtIndex:indexPath.row];
} else {
NSLog([[self.searchResults objectAtIndex:indexPath.row] title]);
cell.listingPreview = [self.searchResults objectAtIndex:indexPath.row];
}
return cell;
}
Please note that the change was applied on:
ListingPreviewTableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
This way you deque a Cell from your own tableView and not from the one created by UISearchDisplayController.
It seems that nothing in your code forces searchDisplayController to reload it's searchResultTableView.
The standard approach is to set UISearcDisplayController's delegate (note the protocol - UISearchDisplayDelegate) and implement – searchDisplayController:shouldReloadTableForSearchString:
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
// perform your search here and update self.searchResults
NSInteger searchStringLength = searchString.length;
for (ListingPreview *listingPreview in self.listingPreviews) {
if ((listingPreview.title.length >= searchStringLength) && ([listingPreview.title rangeOfString:searchString].location != NSNotFound)) {
[self.searchResults addObject:listingPreview];
}
}
// returning YES will force searchResultController to reload search results table view
return YES;
}

UITextField content gets lost when the view is scrolled off the screen

I have a custom UITableViewCell prototype containing UITextField. I am adding new cells automatically when filling the UITextField in the last section. Where there are more sections that do not fit on one screen and I add another one, it gets filled with values from the first section and the first section inputs are emptied!
Screenshots:
Related code:
#implementation TMNewTripPeopleViewController
#synthesize sectionsCount = _sectionsCount;
#synthesize firstCellShowed = _firstCellShowed;
- (int) sectionsCount
{
if (_sectionsCount == 0) {
_sectionsCount = 1;
}
return _sectionsCount;
}
- (IBAction)inputChanged:(id)sender {
UITextField* input = (UITextField*) sender;
NSIndexPath* indexPathName = [NSIndexPath indexPathForRow:0 inSection:input.tag - 1];
UITableViewCell* cellName = [self.tableView cellForRowAtIndexPath:indexPathName];
if (input == [cellName viewWithTag:input.tag]) {
// last name input - add next section?
if (input.tag == self.sectionsCount) {
if (input.text.length > 0) {
self.sectionsCount++;
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:self.sectionsCount - 1] withRowAnimation:UITableViewRowAnimationTop];
}
}
}
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return self.sectionsCount;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return 2;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = #"PersonName";
if (indexPath.row % 2 == 1) {
CellIdentifier = #"PersonEmail";
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
UITextField* input = (UITextField*) [cell viewWithTag:indexPath.section + 1];
if (indexPath.row == 0 && indexPath.section == 0 && !self.firstCellShowed) {
[input becomeFirstResponder];
self.firstCellShowed = YES;
}
[cell viewWithTag:1].tag = indexPath.section + 1;
return cell;
}
#end
I'm not seeing tableView:willDisplayCell:forRowAtIndexPath: in your implementation. You generally set your cell's display values in this method.
When you use dequeueReusableCellWithIdentifier (and you almost always should) then your cells will be reused when the table view is scrolled. If you don't update their values in willDisplayCell then they will show whatever values they previously had before reuse (if any).

Populating UITableView from NSMutableArray

I am experiencing a strange issue with this code.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell...
if (accounts != nil) {
NSLog(#"Cell: %#", indexPath.row);
cell.textLabel.text = [self.accounts objectAtIndex: indexPath.row];
}
else
{
NSLog(#"No cells!");
[cell.textLabel setText:#"No Accounts"];
}
return cell;
}
My table view populates just fine, except all rows contain the first item in my NSMutableArray, accounts. I am logging the value of indexPath.row and it remains at (null) no matter how many values are in the array. Am I doing something wrong here?
I don't believe this! I am bonking myself on the head for not finding this sooner!
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [accounts count]; //<--This is wrong!!!
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 1; // <--This needs to be switched with the error above
}
The above code was the reason why it was printing the same row in my array twice, rather than marching forward in my array.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [accounts count];
}
This code is correct and produces the proper result. What a fuster cluck. ^^;
Should be #"%i", indexPath.row not #"%#", indexPath.row
Also I recommend putting this at the top of your method:
NSUInteger row = [indexPath row];
Then your method looks like this:
// Cell Ident Stuff
// Then configure cell
if (accounts) {
NSLog(#"Cell: %i", row);
cell.textLabel.text = [self.accounts objectAtIndex:row];
}
else {
NSLog(#"No accounts!");
// Only setting for the first row looks nicer:
if (row == 0) cell.textLabel.text = #"No Accounts";
}
It's good practice when dealing with table view methods. Try that.