I have a TableView with data from parse.com where I Placed order to descend according to Functional queryfortable with the "Date" selected by a pickerdate. Now the earliest date turns out to be the last cell and only in the last cell I would like to add a image ... In this specific case, how could I do? This is more 'complicated for me: (
I need to insert an image only in the last cell
Thanks Rory
If you're using PFQueryTableViewController then you should be using a custom subclass of it.
/// MyPFQueryTableViewController.h
#interface MyPFQueryTableViewController : PFQueryTableViewController
self.objects is the Datasource array the PFQueryTableViewController class uses for each table row.
You have to check whether the indexPath.row is the last object inside the self.objects array.
Within MyPFQueryTableViewController.m you override the cellForRowAtIndexPath method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object {
static NSString *CellIdentifier = #"Cell";
PFTableViewCell *cell = (PFTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[PFTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell
// Is this the last displaying cell?
if( indexPath.row == ([self.objects count]-1) )
{
cell.imageView.image = [UIImage imageNamed:#"End_Of_List.jpg"];
cell.textLabel.text = #"";
}
else
{
cell.textLabel.text = [object objectForKey:self.textKey];
}
return cell;
}
Related
I am trying to make a custom tableview cell for an iPad app, using the Parse framework. When i query without the custom cell, it works fine, but as soon as i am changing the cell identifier, i am just stuck at the loading icon.
The code goes as follows:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object {
static NSString *CellIdentifier = #"specielCelle";
sagerCelle *cell = (sagerCelle *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil) {
cell = [[sagerCelle alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell
cell.lblPolice.text = [object objectForKey:#"police"];
//cell.textLabel.text = [object objectForKey:self.textKey];
//cell.imageView.file = [object objectForKey:self.imageKey];
return cell;
}
Here my advices,(By the way the question is not clear)
Firstly change your identifier with an indexpath.Row
NSString *cellIdentifier=[NSString stringWithFormat:#"CELL_%d",(int)indexPath.row];
Second
if you are changing your existing cell then you are not be able to go inside of the block of
if(cell==nil)
because your cell is not nil. Write else condition.
Hope it helps.
I'm seeking how create several cells to go to different ViewControllers.
For my TableView, I'm using a subclass of UITableViewController.
And when I choose 2 in the following method, I just see 2 identical cells which are doing exactly the same thing. I'm not interested by this. I don't even know their IndexPath in order to change their title.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return 2;
}
And When I try to put another UITableViewCell in my TableView, it doesn't appear on iOS simulator, even with the same option (same subclass) than my first UITableViewCell which I can see.
Thanks for your help.
Edit : Here is my new code to create 2 cells but doesn't work :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell2";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[customCell alloc] init];
}
static NSString *CellIdentifier1 = #"Cell1";
UITableViewCell *cell1 = [tableView dequeueReusableCellWithIdentifier:CellIdentifier1];
if (cell1 == nil) {
cell1 = [[customCell alloc] init];
}
// Configure the cell...
return cell;
}
You define your cells in tableView:cellForRowAtIndexPath:, so you should provide an implementation for that method.
tableView:numberOfRowsInSection: only returns the number of cells in the table.
If you need more help, please provide your implementation for tableView:cellForRowAtIndexPath:. This is how a typical implementation looks like:
- (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];
}
... customize your cell ...
}
EDIT:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell2";
static NSString *CellIdentifier1 = #"Cell1";
if(indexPath.row == 0 ) {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[customCell alloc] init];
}
} else {
UITableViewCell *cell1 = [tableView dequeueReusableCellWithIdentifier:CellIdentifier1];
if (cell1 == nil) {
cell1 = [[customCell alloc] init];
}
}
return cell;
}
This method gets called when a cell has been selected. You can decide what you wanna do according to the selected row
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == 0)
[self goToFirstViewController];
else
if(indexPath.row == 1)
[self goToSecondViewController];
}
Use the following:
- (NSInteger) tableView: (UITableView*) tableView numberOfRowsInSection: (NSInteger) section
This delegate method returns the number of rows you want in that particular section. So if you want more than 2 rows, or you want the number of rows to be dynamic, you can create a NSArray in the AppDelegate or in the init method of the viewController class, and return the number in the numberOfRowsInSection method like
return [delegate numberOfNames];
In my example above, I created an array in my AppDelegate and also a method to return the number of objects I have in that array so that I can create the number of rows for my table.
- (UITableViewCell*) tableView: (UITableView*) tableView cellForRowAtIndexPath: (NSIndexPath*) indexPath
This delegate method will show what you want to display in each cell. Therefore, following on from my array created in my AppDelegate, I first create the cell, then I will set the text I want to display on the cell with a method I created in my AppDelegate that will return a NSString while taking in a NSInteger so that I can loop through my array and display the text accordingly.
static NSString* MyIdentifier = #"Default";
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if( cell == nil )
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier] autorelease];
cell.textLabel.text = [delegate nameAtIndex:indexPath.row];
}
nameAtIndex is the name of the method I created in my AppDelegate that will return the NSString object at the specific index (ie. the row number) from the NSArray I created to store all the items of my table.
When the user clicks on any of the rows in the table created, this delegate method will be called
- (void) tableView: (UITableView*) tableView didSelectRowAtIndexPath: (NSIndexPath*) indexPath
And in here, I will check if the text displayed matches any of the items in my array from the AppDelegate that stores the items in the table, and create the view that is necessary.
UIViewController* viewController = nil ;
NSString* nameInArray = [delegate nameAtIndex:indexPath.row] ;
if( [nameInArray isEqualToString:#"firstName"] )
{
viewController = [[FirstViewController alloc] init];
}
else if( [nameInArray isEqualToString:#"secondName"] )
{
viewController = [[SecondViewController alloc] init];
}
else if( [nameInArray isEqualToString:#"thirdName"] )
{
viewController = [[ThirdViewController alloc] init];
}
So with these 3 delegate methods, you will be able to create the table using a NSArray created, and be able to redirect the user to a viewController according to which option in the table he chooses. You will not have to keep editing the delegate methods if you choose to add more rows to the table as well since you are returning the count of the array when setting up the table.
The array and methods to get the data of the array can be created in the viewController as well, not necessarily in the AppDelegate, in case you were wondering.
The methods are as follows:
-(NSInteger) numberOfNames
{
return [myArray count];
}
-(NSString*) nameAtIndex: (NSInteger) index
{
return [myArray objectAtIndex:index] ;
}
Hope this helps! :)
I have a text array backing a TableView in iOS. In the cellForRowAtIndexPath: method I return a UITableViewCell* which is populated with text from the backing array. indexPath is used as the index into the backing array.
I now want to add a "Done" button to the last cell in the TableView. In my StoryBoard I've created a second (prototype) TableView Cell and gave it the identifier "ButtonCell". I've also added an extra element to the end of the backing array so numberOfRowsInSection: can return the count of the backing array and everything will just work.
I thought I would set the text of the last array element to something like #"donebutton" and then I could check for that in cellForRowAtIndexPath:. If it comes up true, I would know I'm at the end of my array and to return the "ButtonCell" cell instead of the normal "Cell". Thing is, it's not quite working right. What's the best way to accomplish this? Code snip is below.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
static NSString *ButtonCellIdentifier = #"ButtonCell";
UITableViewCell *bcell = [tableView dequeueReusableCellWithIdentifier:ButtonCellIdentifier forIndexPath:indexPath];
NSString *rowtext = [_mArCellData objectAtIndex:indexPath.row];
// return button cell if last item in list
if ([rowtext isEqualToString:[NSString stringWithFormat:#"%d", SUBMIT_BUTTON]])
{
NSLog(#"hit last row, so using button row");
return bcell;
}
cell.textLabel.text = rowtext;
return cell;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
static NSString *ButtonCellIdentifier = #"ButtonCell";
UITableViewCell *cell;
if (indexPath.row != ([_mArCellData count] - 1) { // if not the last row
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// configure cell...
} else { // last row
cell = [tableView dequeueReusableCellWithIdentifier:ButtonCell];
// configure button cell...
}
return cell;
}
I would just change your if statement to:
if ([tableView numberOfRowsInSection:0] == indexPath.row + 1) {
NSLog(#"hit last row, so using button row");
bcell.textLabel.text = rowtext;
return bcell;
}
This is a little more abstracted than your solution and doesn't rely on a property of a cell being set to anything in particular. I like the way #bilobatum put the dequeueReusableCellWithIdentifier: call in the if statement. That should save some memory as well.
EDIT: I also noticed that you are setting cell text, but not bcell text.
I have created an tableview with an array. There are 7 items in my array. But in cellForRowAtIndexPath method i'm unable to get indexpath.row == 6. What could be the reason.
Code is below for this.
-(void)viewDidLoad
{
[super viewDidLoad];
self.menu = [NSArray arrayWithObjects:#"Home",#"ansCategory",#"askQue",#"myQue",#"likedQue", #"topQue", #"topUser",nil];
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
// NSLog(#"count::::::%d",self.menu.count);
return self.menu.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
NSLog(#"rows:%#",indexPath);
NSLog(#"row:%#",[self.menu objectAtIndex:indexPath.row]);
}
return cell;
}
I'm getting following out put:
[here] (https://www.dropbox.com/s/pz6t34xr7l4glxz/menu1.png)
first index is overlaying on last one.
The cell is reused.
Put your log statement outside of the if(cell=nil):
Here is the working example for outputting the contents of the array in a tableview. Item with index 6 which is the seventh in the array ("topUser") is in red.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
}
NSLog(#"rows:%#",indexPath);
NSLog(#"row:%#",[self.menu objectAtIndex:indexPath.row]);
cell.textLabel.text = self.menu[indexPath.row];
if (indexPath.row == 6)
cell.textLabel.textColor = [UIColor redColor];
return cell;
}
For N items the last indexpath is (N-1)
Thus, if you have 10 items, then the index path of last item is 9 because the indexpath of 1st item in array is 0.
indexPath of items starts with 0 and not 1.
Try to access the index path in your answer like below in your code
Instead of :
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
NSLog(#"rows:%#",indexPath);
NSLog(#"row:%#",[self.menu objectAtIndex:indexPath.row]);
}
Write
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
}
//Access the indexPath outside here...
//Because once the cells are created and not nil
//then the above scope will be bypassed.
NSLog(#"rows:%#",indexPath);
NSLog(#"row:%#",[self.menu objectAtIndex:indexPath.row]);
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
gets executed whenever the new row is needed to be created and added to the tableview.The tableview populates row such that when it needs to be dispayed on screen it is created by calling the very same method.So If your 7 th row is not visible on screen the method wont get executed for row 7 ie indexpath.row 6 and so to get the method to log the 7 th row just scroll down so that that cell can be made visible by the table and it will execute the method and you can have the log
I changed my code to following line and it worked.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:nil];
i was following this torturial:
http://www.raywenderlich.com/32283/core-graphics-tutorial-lines-rectangles-and-gradients
It covers customization of dynamic table cells, i need to do it with static table cells.
I have given every cell the identifier "Cell", as he does in the tutorial, i then subclassed the table view controller and implemented this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString * CellIdentifier = #"Cell";
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// START NEW
if (![cell.backgroundView isKindOfClass:[CostumCellBackground class]]) {
cell.backgroundView = [[CostumCellBackground alloc] init];
}
if (![cell.selectedBackgroundView isKindOfClass:[CostumCellBackground class]]) {
cell.selectedBackgroundView = [[CostumCellBackground alloc] init];
}
// END NEW
cell.textLabel.backgroundColor = [UIColor clearColor]; // NEW
return cell;
}
CostumCellBackground draws the rect.
I am getting the error "UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath:
As far as i understand UITableView is looped for every Cell in the storyboard, and it is supposed to return cell.
So, whats going on here and why does the cell return nil, or doesnt return at all ?
The only difference is that they are static tables, and not prototypes.
If you are using Storyboards and iOS6 and your view controller is a UITableViewController, you will always get a cell if your cell identifier is present in your storyboard. Checking for cel == nil is the old way to do it.
Are you sure you have a custom cell in your storyboard with the "Cell" identifier?
Also, use this:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
If you look in the UITableView.h file you will find:
// newer dequeue method guarantees a cell is returned and resized properly, assuming identifier is registered
- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(6_0);
Where is you create your cell ??
You should add after:
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
such code (or something another initializer):
if (cell == nil) {
cell = [[UITableViewCell alloc] init];
}
Try this at the beginning of your method:
- (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
];
}