2 tableview on a single view - objective-c

I need an example or explanations of how to populate 2 table views which are on the same view. I need to understand the "cellForRowAtIndexPath" method, could someone provide me an example on how should the code be?
I mean how to identify which goes which table view?
Thanks
Below is my cellForRowAtIndexPath method:
// Customize the appearance of table view cells.
- (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...
// Set up the cell
MyAppAppDelegate *appDelegate = (MyAppAppDelegate *)[[UIApplication sharedApplication] delegate];
if (tableView == radios_tv) { //radio_tv is an IBOutleet UITableView
sqlClass *aRadio = (sqlClass *)[appDelegate.array_radios objectAtIndex:indexPath.row];
[cell setText:aRadio.r_name];
return cell;
}
if (tableView == presets_tv) { //preset_tv is an IBOutlet UITableView
}
}
and hey vikingsegundo, now I need to delete a cell which is on my TableViewController class, how do I do this? I explain, here is my code:
- (void)tableView:(UITableView *)tv commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath {
if(editingStyle == UITableViewCellEditingStyleDelete) {
//Get the object to delete from the array.
Coffee *coffeeObj = [appDelegate.coffeeArray objectAtIndex:indexPath.row];
[appDelegate removeCoffee:coffeeObj];
//Delete the object from the table.
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
Since we put different controllers, how should we proceed for this line? Should I put the tableViewController instead of the "self"?
//Delete the object from the table.
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];

IMO the cleanest solution would be to have one controller for each tableview.
radios_tv would call it own delegate's method, while presets_tv calls it own.
edit
if you use one controller for n tableview, you will have to use if-statemenst in many places,
in
– numberOfSectionsInTableView:
– tableView:numberOfRowsInSection:
– tableView:titleForHeaderInSection:
…
basically in all UITableViewDatasource-Protocol methods that you will need to implement.
So if you need to change something, you have to change it in many places.
If you use one controller class for one tableview, you won't have to check at all.
write a controller class for every tableview, make it conforming to the UITableViewDatasource protocol
implement the protocol methods you will need. at least
– numberOfSectionsInTableView:,
– tableView:numberOfRowsInSection:,
– tableView:cellForRowAtIndexPath:
call -setDataSource:for every tableview to an object of the right controller class
I think, it was shown in one of the WWDC 2010 videos. I am not sure, but I guess it was Session 116 - Model-View-Controller for iPhone OS.
edit
I wrote an example code: http://github.com/vikingosegundo/my-programming-examples

On one view controller if you have to use two tables then you can set IBOutlet to both tables or assigns different tag to them so when you use following cellForRowAtIndexPath you can differentiate in both tables as below
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCellStyle style =UITableViewCellStyleSubtitle;
static NSString *MyIdentifier = #"MyIdentifier";
DataListCell *cell = (DataListCell*)[tableView dequeueReusableCellWithIdentifier:MyIdentifier];
cell = [[DataListCell alloc] initWithStyle:style reuseIdentifier:MyIdentifier];
cell.selectionStyle=UITableViewCellSelectionStyleNone;
if(tableView==tblLanguage)//tblLanguage IBOutlet for first table
{
if ((selectedIndexPath != nil) && (selectedIndexPath.row == indexPath.row))
{
UIImageView *imgView=[[UIImageView alloc]initWithFrame:CGRectMake(320-30, 9, 22, 15)];
imgView.image=[UIImage imageNamed:#"btn_Expand.png"];
[cell addSubview:imgView];
tblSongs.hidden=NO;
tblSongs.frame=CGRectMake(0,42, 320, ([arrSongListForSpecificLanguage count]*40));
[cell addSubview:tblSongs];
}
else
{
UIImageView *imgView=[[UIImageView alloc]initWithFrame:CGRectMake(320-30, 9, 16, 22)];
imgView.image=[UIImage imageNamed:#"btn_Collaps.png"];
[cell addSubview:imgView];
}
cell.lblCustomerName.textColor=[UIColor blackColor];
cell.lblCustomerName.font=[UIFont boldSystemFontOfSize:16];
//set the first label which is always a NamesArray object
[cell setcustomerName:[objAppDelegate.viewController.arrLanguage objectAtIndex:indexPath.row]];
}
else //for other table
{
ParseData *objParse;
objParse=[arrSongListForSpecificLanguage objectAtIndex:indexPath.row];
cell.lblCustomerName.textColor=[UIColor blackColor];
cell.lblCustomerName.frame=CGRectMake(cell.lblCustomerName.frame.origin.x, cell.lblCustomerName.frame.origin.y, 310, cell.lblCustomerName.frame.size.height);
//set the first label which is always a NamesArray object
[cell setcustomerName:objParse.track];
}
return cell;
}
}
You can also use tag for the same in which your if statement as below
if(tableView.tag==1)//tblLanguage tag=1
Similar if statement use for other delegate & datasource methods of table

Related

Custom NSTableView with custom NSTableCellView?

I would like to create an NSTableview with custom NSTableCellViews.
Here is what I have right now:
A nib file for the cell (view nib) called CustomCell.xib
A custom class for my cell called CustomCell
And the code in my AppDelegate.m:
Here I create my table view programmatically:
NSScrollView *tableContainer = [[NSScrollView alloc]initWithFrame:NSMakeRect(self.window.frame.size.width-TABLEWIDTH, 0, TABLEWIDTH, self.window.frame.size.height)];
NSTableView *tableView = [[NSTableView alloc] initWithFrame:NSMakeRect(self.window.frame.size.width-TABLEWIDTH, 0, TABLEWIDTH, self.window.frame.size.height)];
NSTableColumn *firstColumn = [[[NSTableColumn alloc] initWithIdentifier:#"firstColumn"] autorelease];
[[firstColumn headerCell] setStringValue:#"First Column"];
[tableView addTableColumn:firstColumn];
tableView.dataSource = self;
tableView.delegate = self;
[tableContainer setDocumentView:tableView];
tableContainer.autoresizingMask = NSViewHeightSizable | NSViewMinXMargin;
[self.window.contentView addSubview: tableContainer];
And here is the delegate method where I would like to put my custom cell code:
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
// In IB the tableColumn has the identifier set to the same string as the keys in our dictionary
NSString *identifier = [tableColumn identifier];
if ([identifier isEqualToString:#"myCell"]) {
// We pass us as the owner so we can setup target/actions into this main controller object
CustomCell *cellView = [tableView makeViewWithIdentifier:identifier owner:self];
// Then setup properties on the cellView based on the column
cellView.textField.stringValue = #"Name";
return cellView;
}
return nil;
}
In the nib file for my custom cell I have hooked up the cell view with my custom class called CustomCell which subclasses NSTableCellView. I have not done any other steps as for now. So my CustomCell.m is just default initialization code. I haven't touched it. And I did not do anything else in my nib file, so I did not change file's owner or anything like that because I don't really know what to do.
Can anyone help out ? I looked at sample files from the Apple documentation, but after days of researching I have not found any solutions. I would really appreciate if you could help me.
This is what I ended up doing :
Of course you have to subclass NSTableCellView and return it like I did below. If you are familiar with table views in iOS you should be familiar with methods like:
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView{
//this will be called first. It will tell the table how many cells your table view will have to display
return [arrayToDisplay count];
}
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
//this is called after the count of rows is set. It will populate your table according to the data your array to display contains
[tableView setTarget:self];
[tableView setAction:#selector(click)];
NSString *identifier = [tableColumn identifier];
if ([identifier isEqualToString:#"TheCell"]) {
CustomCell *cellView = [tableView makeViewWithIdentifier:identifier owner:self];
cellView.cellText.stringValue = [arrayToDisplay objectAtIndex:row];
return cellView;
}
return nil;
}
And the click method that is triggered when a row is selected would look like this:
-(void)click{
int index = [table selectedRow];
// Do something with your data
//e.g
[[arrayToDisplay objectAtIndex:index] findHiggsBoson];
}
And something that has to be added to the NSTableView:
NSTableColumn *column = [[NSTableColumn alloc] initWithIdentifier:#"column"];
column.width = self.frame.size.width;
[tableView addTableColumn:column];
You do not need to subclass NSTableView to have custom NSTableViewCell subclasses.
You might consider using a view-based Table View also...

Looping through subview of a custom cell in didSelectRowAtIndexPath to get UITextField text

i know im asking a very common question. but after going through a lots of similar questions and articles im not able understand
How can i access UITextfield inside UITableViewCell inside didSelectRowAtIndexPath delegate method.
im posting my code below. i may b not going with expected way although..
i want to make textfield (of selected row) [becomeFirstResponder] in didSelectRowAtIndexPath
so that i can display uiPicker below to this textfield. Please help me out with this.
- (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];
if(self.isTableForHospital)
{
UIView *myview=[self createRowViewForHospitalTable:[customArray objectAtIndex:indexPath.row]];
myview.tag=indexPath.row;
[cell addSubview:myview];
cell.selectionStyle=UITableViewCellSelectionStyleNone;
}
else
{
cell.textLabel.text=[customArray objectAtIndex:indexPath.row];
}
}
return cell;
}
-(UIView *)createRowViewForHospitalTable:(NSString *)rowText
{
UIView *hospital_row_view=[[UIView alloc]init];
UILabel *lblRowText=[[UILabel alloc]initWithFrame:CGRectMake(0, 0, 300, 50)];
lblRowText.text=rowText;
txtDepartment=[[UITextField alloc]initWithFrame:CGRectMake(310, 0, 185, 30)];
//...rest styling for textfield goes here..
txtRole=[[UITextField alloc]initWithFrame:CGRectMake(495, 0, 185, 30)];
[hospital_row_view addSubview:lblRowText];
[hospital_row_view addSubview:txtDepartment];
[hospital_row_view addSubview:txtRole];
return hospital_row_view;
}
- (void)textFieldDidEndEditing:(UITextField *)textField { }
- (void)textFieldFinished:(id)sender{
NSString *value=#"sa";
[sender resignFirstResponder];
}
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cellSelected = [tableView cellForRowAtIndexPath: indexPath];
UIView *myview=[cellSelected.contentView viewWithTag:indexPath.row];
for(UIView *item in [myview subviews])
{
if([item isKindOfClass:[UITextField class]])
{
[item becomeFirstResponder];
}
}
}
In terms of iterating through the cell subviews and getting the UITextField, I think I have your answer.
I found this on another thread here, and modified it to be more generic:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITextField* textField = [[UITextField alloc] init];
UITableViewCell* cell = [tableView cellForRowAtIndexPath:indexPath];
UIView* subview = [[cell.contentView subviews] lastObject]; // Make sure your UITextField really *is* the last object you added.
if ([subview isKindOfClass:[UITextField class]]) {
textField = (UITextField*)subview;
}
[textField becomeFirstResponder];
}
...where "textField" is the placeholder for your actual text field object.
Hope this helps!
I don't think you need to alloc init the textfield, for it will ultimately be pointing to the cell's textfield (if any).
I believe you are allocating it unnecessarily.

Detailtext is not showing in case?

I have a case but the detailtext is not showing? Does anyone know what te problem is?
i used: UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UIViewController *controller;
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
switch(indexPath.row) {
case 0:
{
NSLog(#"Case 0");
controller = [[wed1 alloc] init]; //WithStyle:UITableViewStylePlain];
[self.navigationController pushViewController:controller animated:YES];
cell.detailTextLabel.text = #"Wedstrijden!";
}
break;
case 0:
{
NSLog(#"Case 0");
controller = [[wed1 alloc] init]; //WithStyle:UITableViewStylePlain];
//created a controller
[self.navigationController pushViewController:controller animated:YES];
//at his point, you are showing next ViewController's view
cell.detailTextLabel.text = #"Wedstrijden!";
//here you are changing the text of the text for current tableView's cell (which is actually going to be off the screen as new controller's view will be shown after previous statement execution)
}
with the piece of code you shared - I don't find anything wrong here, the detail text should not be visible as this view will be gone.
I don't fully understand why you'd want to set the detail text on a cell after pushing a new view controller. As samfisher said, when the user presses the first cell, in case 0, the new view controller will be alloc'd, init'd and then pushed, and after that you set the detail text to "Wedstrijden".
I'm assuming you're probably just confused between which property to use. My question to you is: when and where do you want this text to appear?
If the cell was created with the style UITableViewCellStyleDefault, the detail text label isn't displayed. In tableView:cellForRowAtIndexPath: implementation, you may create the cell with style UITableViewCellStyleSubtitle or UITableViewCellStyleValue1.
Use UIListContentConfiguration instead, or subtitle won't show.
#import <UIKit/UIListContentConfiguration.h>
And in the cellForRowAtIndexPath method:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"AddressCell" forIndexPath:indexPath];
if(cell==nil){
cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"AddressCell"];
}
NSRange range = [self.dataArray[indexPath.row] rangeOfString:#","];
NSString *street;
NSString *restAddress;
if (range.location != NSNotFound) {
street = [self.dataArray[indexPath.row] substringToIndex:range.location];
restAddress= [self.dataArray[indexPath.row] substringFromIndex:range.location + 1];
}
UIListContentConfiguration *configuration = cell.defaultContentConfiguration;
configuration.text=street;
configuration.image=kImage(#"Location");
configuration.secondaryText=restAddress;
cell.contentConfiguration = configuration;
return cell;
}
Will look like this:

cellForRowAtIndexPath not being called

I have a view that adds another view on top in this manner:
- (void)showAreaEditView {
NSLog(#"SHOWING AREA EDITOR VIEW");
if (self.thisAreaEditorView == nil) {
// Create View
AreaEditorView *tmpViewController = [[AreaEditorView alloc] initWithNibName:#"AreaEditorView" bundle:nil];
self.thisAreaEditorView = tmpViewController;
[tmpViewController release];
// Hide the back button
self.thisAreaEditorView.navigationItem.hidesBackButton = YES;
}
self.thisAreaEditorView.myInspectionID = self.myInspectionID;
self.thisAreaEditorView.loggedIn = loggedIn;
self.thisAreaEditorView.loggedInGroup = loggedInGroup;
// Slide view up
[self.view addSubview:thisAreaEditorView.view];
CGRect endFrame = CGRectMake(self.view.frame.size.width/2 - thisAreaEditorView.view.frame.size.width/2,
self.view.frame.size.height/2 - thisAreaEditorView.view.frame.size.height/2,
thisAreaEditorView.view.frame.size.width,
thisAreaEditorView.view.frame.size.height);
CGRect startFrame = endFrame; // offscreen source
// new view starts off bottom of screen
startFrame.origin.y += self.view.frame.size.height;
self.thisAreaEditorView.view.frame = startFrame;
// start the slide up animation
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:.6];
thisAreaEditorView.view.frame = endFrame; // slide in
[UIView commitAnimations];
}
I'm sure you can just ignore the slide part, I feel the addSubview is relevant.
Then in thisAreaEditor I have the view with the table and buttons and such. UITableView delegate/datasource is going to File's Owner as normal.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"numberOfRowsInSection returning %d", [tableData count]);
[tableData count];
}
This function numberOfRowsInSection returns 4
- (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...
NSString *thisText = [tableData objectAtIndex:indexPath.row];
cell.textLabel.text = thisText;
NSLog(#"looking at cell %d text:%#", indexPath.row, thisText);
return cell;
}
But cellForRowAtIndexPath never gets called.
I'm at a loss here, I have no idea how it can seem to work fine but one of the delegate functions simply not be called.
I have tried [bigTable reloadData] and so on, the table just never gets populated and no logs from the function output.
Thanks in advance.
You might have just edited this out, if so I'm sorry, but it looks like you forgot to return tableData's count.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    NSLog(#"numberOfRowsInSection returning %d", [tableData count]);
    return [tableData count];
}
It seems you're missing UITableViewDelegate.
If you're using Interface Builder, right click the table view outlet and drag both delegate and datasource to File's Owner.
And if not using Interface Builder add this where you init your tableView
bigTable.delegate = self;
bigTable.dataSource = self;
Remember to import the UITableViewDelegate and UITableViewDataSource protocols, just as Srikar says.
Hope this is to any help.
Cheers!
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath is also not called when the tableview's height is not set.
Maybe you did not set the tableView delegate as self or the datasource as self. Add this code & see if it works now -
[tableView setDelegate:self];
[tableView setDataSource:self];
Also in your header file inherit these delegates - UITableViewDelegate, UITableViewDataSource
#interface yourViewController: UIViewController <UITableViewDelegate, UITableViewDataSource>
Hope this helps.
This is a older link, but I wanted to update this with putting info on how I resolved this issue.
For me the issue was the Array to populate the table had 0 rows so cellForRowAtIndexPath was never called.
Make sure that the Array you are using to populate the table has data in it.

Can't reach the right text of a UITextField object in a modal UITableViewController subclass

I've got a sublass of UITableViewController which I use to add a new data for a new cell within another Table. That means, I've got a "Cancel" and a "Save" button at the top to save the data and get back to the table where to add the new object into. I show the adding controller modally.
My problem is though that I don't know how to get the data from the user input cells of the tableView in my UITableViewController subclass to save them in my CoreData file.
Here's the code how I try it - but at the console I just get (nil) for the persons name:
- (void)save
{
NSLog(#"Saving ...");
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
UITableViewCell *cell = [self tableView:[self tableView] cellForRowAtIndexPath:indexPath];
NSString *personName = [[cell textField] text];
NSLog(#"New Person: %#", personName);
// Do saving with Core Data and updating here.
[self dismissModalViewControllerAnimated:YES];
}
I guess you will also need the following method to understand the problem:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
EditableDetailCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[EditableDetailCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.accessoryType = UITableViewCellAccessoryNone;
if (indexPath.section == 0) {
[cell.textField setPlaceholder:#"Name"];
} else {
switch (indexPath.row) {
case 0:
[cell.textField setPlaceholder:#"Birth Year"];
break;
case 1:
[cell.textField setPlaceholder:#"Weight in kg"];
break;
case 2:
[cell.textField setPlaceholder:#"Height in cm"];
break;
case 3:
[cell.textField setPlaceholder:#"Sex"];
break;
default:
break;
}
}
return cell;
}
I really can't find the failure. In my understanding it should work this way ... but it doesn't. Could anyone please help?
Don't call your table view datasource method to get the value in the cell. Get it directly from the table view instead.
Instead of this:
UITableViewCell *cell = [self tableView:[self tableView] cellForRowAtIndexPath:indexPath];
Do this:
UITableViewCell *cell = [[self tableView] cellForRowAtIndexPath:indexPath];
Doing it the way you are doing is essentially recreating the cell and so losing the value you have entered. The datasource method is only meant to be called by the table to work out what to display.
In your method to set the cell text, you alter the textField of the cell, but the string you grab to log/save to Core Data is from the textLabel. Is this an intentional discrepancy?