TableViewCell not displaying layout - objective-c

Here's a question about tableViewCell. I am trying my hand at table views for the first time and trying to get my head around reusable cells etc. I have managed to get it working to some extent. I have a tableView that lives on a child view controller which is its delegate and data source. Code for delegate:
#import "ChildViewController.h"
#interface ChildViewController ()
#property NSArray *titles;
#property NSArray *thumblenails;
#end
#implementation ChildViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.titles = [NSArray arrayWithObjects:#"Title 1", #"Title 2", #"Title 3", #"Title 4",nil];
self.thumblenails = [NSArray arrayWithObjects:#"Image1", #"Image2", #"Image3", #"Image4", nil];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return self.titles.count;
}
-(UITableViewCell *)tableView:(UITableView *)TableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
SimpleTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"SimpleTableViewCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
// cell.textLabel.backgroundColor = [UIColor greenColor];
cell.textLabel.text = [self.titles objectAtIndex:indexPath.row];
cell.imageView.image = [UIImage imageNamed:[self.thumblenails objectAtIndex:indexPath.row]];
return cell;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
I also have a SimpleTableViewCell.xib:
I have set the class on the identity inspector to SimpleTableViewCell and imported the SimpleTableViewCell.h file to my ChildViewController.h. I have also set the identifier to "cell" in the attributes inspector of the Table view cell, but here is the thing. As I am not getting the look I want for my cell, I have tried misspelling it and nothing has changed so clearly the identifier is not doing anything. When I run my app I get this:
So the array of images and titles are being loaded but not the actual cell size and labels that I set on the xib file for the cell. I have tried changing something in the cell, like the background color in the attributes inspector.
and on the xib it looks like this:
but when I run it:
I am guessing all this is because the cell identifier is not actually linked, but I thought I had done that in the line:
SimpleTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
Am I missing some important coding in here, linking something in the xib, or is it just a typo? any suggestions greatly appreciated.
//////////////////////////////////////////////////////////////////////UPDATE1////////////////////////////////////////////////////////////////////////
I have tried the second suggestion and the result is this:
So, hopefully this will throw some light into what I am doing wrong?
Also, I have corrected the original text, when I change the color to green it's using the attributes inspector.
Thanks for your help.
//////////////////////////////////////////////////////////////////////UPDATE2////////////////////////////////////////////////////////////////////////
I have removed the lines:
cell.textLabel.text = [self.titles objectAtIndex:indexPath.row];
cell.imageView.image = [UIImage imageNamed:[self.thumblenails objectAtIndex:indexPath.row]];
Also, added the code:
[self.tableView registerNib:[UINib nibWithNibName:#"SimpleTableCell" bundle:nil] forCellReuseIdentifier:#"cell"];
and the code:
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return [UIScreen mainScreen].bounds.size.width * (0.3);
}
Now my table looks like this:
So question now is how do I add the actual values of the original arrays of titles and images?

you should set the height of cell to get the exact same look in the nib file. use this delegate method to set height of cell.
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return [UIScreen mainScreen].bounds.size.width * (0.3);// 0.3 should be your aspect ratio for cell:
// for cell.height/ cell.width in nib file.
}

You forgot to register nib for cell identifier.
Put [self.tableView registerNib:[UINib nibWithNibName:#"SimpleTableViewCell" bundle:nil] forCellReuseIdentifier:#"cell"]; to viewDidLoad method.
And you can remove
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"SimpleTableViewCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}

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...

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.

iOS tableview cell handling

I have this code, where "lineaRedToday" is an UIImageView:
- (void)viewDidLoad {
[super viewDidLoad];
lineaRedToday = [UIImage imageNamed:#"line4.png"];}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *MyIdentifier = #"MyIdentifier";
MyIdentifier = #"tblCellView";
TableViewCell *cell = (TableViewCell*)[tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if(cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"TableViewCell" owner:self options:nil];
cell = tblCell;
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
[[lineDay objectAtIndex:currentTodaylineRed -1] setImage:lineaRedToday];
return cell;
- (IBAction) change{
lineaRedToday = [UIImage imageNamed:#"linea.png"];
[lineDay setImage:lineaRedToday];
[myTableView reloadData];
}
It is a UITableView with 15 custom UITableViewCell and I want to change the image at an UIImageView, this ImageView is "lineDay", lineDay is present in all cells, and I want change its image at all cells, but the IBAction "change" change the UIImageView only in the last cell and not at all....why?
yes it will change the image in last cell because it has the reference of only last cell, if you want to do this then when you are creating cell in cellForRowAtIndexPath check for a BOOL and set image according that BOOL. Also in IBAction change that BOOL value and call reloadData on table view to reload it. As -
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Test";
UITableViewCell *cellView = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cellView == nil)
{
cellView = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
UIImageView *bgImgView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 85.0f)];
[bgImgView setTag:1];
[bgImgView setBackgroundColor:[UIColor clearColor]];
[cellView.contentView addSubview:bgImgView];
[bgImgView release];
}
UIImageView *imgView = (UIImageView*)[cellView viewWithTag:1];
if (buttonPressed)
{
[imgView setImage:[UIImage imageNamed:#"listing_bg"]];
}
else
{
[imgView setImage:[UIImage imageNamed:#"featured_listing_bg"]];
}
return cellView;
}
- (IBAction) change{
buttonPressed = !buttonPressed;
[myTableView reloadData];
}
First, lineaRedToday is an UIImage, not an UIImageView. The first is an image, the second an object in the view hierarchy.
Then, in your code
if(cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"TableViewCell" owner:self options:nil];
cell = tblCell;
}
you use tblCell. I cannot see what this is. You should assign something from what you were just loading from the nib.
I don't know what lineDay is exactly, but a single view (i.e. UIImageView) can only be present in one cell, not in many. If you change the image (lineaRedToday), you still have to set this new image in your views. There should be something like
cell.yourImageView.image = linaRedToday;
when configuring the cell.

Multi-View TableView with RootController

I am trying to create a multi-view app with navigation template. I want table on the bottom part of initial view, with other views (image view, labels, etc) on the top.
Originally I modified RootViewController.xib to resize tableview, and added image view, but nothing displayed except full-size table.
So I modified RootViewController.xib to add UIView, then added a UITableView and UIImageView to that view. I added IBOutlet for the tableView. In my RootViewController.xib, File'S Owner (RootViewController) has outlet connection to the view and the table view. When I right-click the UITableView, I see the referencing outlet to File's Owner. When I right-click the UIView, I see the referencing outlet to File's Owner. (I don't have an outlet to UIImageView, since I don't modify in code; do I need one?).
However, when I launch the app, it crashes with message:
'NSInternalInconsistencyException',
reason: '-[UITableViewController loadView] loaded the "RootViewController" nib but didn't get a UITableView.'
Here is the cellForRowAtIndexPath method:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *QuizIdentifier = #"QuizIdentifier";
UITableViewCell *cell =
[tableView dequeueReusableCellWithIdentifier:QuizIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:QuizIdentifier]
autorelease];
}
// Configure the cell.
UIImage *_image = [UIImage imageNamed:#"icon"];
cell.imageView.image = _image;
NSInteger row = [indexPath row];
cell.textLabel.text = [_categories objectAtIndex:row];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
You're getting that error because when you create a navigation-based iOS app, Xcode makes the RootViewController a subclass of UITableViewController. Once you combine that UITableView with a normal UIView, your subclass no longer complies with the UITableViewController class. So, in your RootViewController.m and .h files change UITableViewController to UIViewController. You may also need to change a few other things in your init method, but let's just start with this.
Try this:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"\n\nI'm in Root / cellForRowAtIndexPath");
static NSString *QuizIdentifier = #"QuizIdentifier";
UITableViewCell *cell =
[tableView dequeueReusableCellWithIdentifier:QuizIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:QuizIdentifier]
autorelease];
UIImage *_image = [UIImage imageNamed:#"icon"];
cell.imageView.image = _image;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
// Configure the cell.
NSInteger row = [indexPath row];
cell.textLabel.text = [_categories objectAtIndex:row];
NSLog(#" We are at row %i with label %# ", row, cell.textLabel.text);
return cell;
}