Adding Accessory to UITableView - iphone

I've got a UITableView displayed on screen for a while. In each cell is a song and artist name. In the background, each song and artist name is searched for online (using the Spotify API). It finds the URL to play one song, and then moves on to the next one! :) Sounds simple... but what I want is when each song is found, for the Checkmark accessory to appear in that row.
Currently i've got the following code to do this...
[[table cellForRowAtIndexPath:[NSIndexPath indexPathForRow:currentConnectionNumber inSection:0]] setAccessoryType:UITableViewCellAccessoryCheckmark];
[table setNeedsDisplay];
But all that happens is when all of the songs has been found, THEN the checkmarks appear... Why is this and how can I make the checkmarks appear one at a time?
thanks

You need to set the checkmark in tableView:cellForRowAtIndexPath:
- (void)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *reuseIdentifier = #"cell";
UITableViewCell *cell = nil;
cell = [tableView dequeueReusableCellForIdentifier:reuseIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier] autorelease];
}
NSString *cellTitle = [self cellTitleForRowAtIndexPath:indexPath]; // You need to implement this method
BOOL hasURL = [self hasURLForRowAtIndexPath:indexPath]; // You need to implement this method
cell.textLabel.text = cellTitle;
if (hasURL)
cell.accessoryType = UITableViewCellAccessoryCheckmark;
else
cell.accessoryType = UITableViewCellAccessoryNone;
return cell;
}
Then reload the cells when your request finishes
- (void)myRequestFinished:(SomeKindOfWebRequest *)webRequest {
NSIndexPath *indexPathToReload = [self indexPathForWebRequest:webRequest]; // You need to implement this method
NSArray *indexPaths = [NSArray arrayWithObject:indexPathToReload];
[self.tableView reloadRowsAtIndexPaths:indexPaths withRowAnimtation:UITableViewRowAnimationNone];
}

I think rather than doing this you can set a bool flag for as per your requirement and add your checkmark logic in
cellForRowAtIndexPath:
and if that flag is true add accessary checkmark otherwise don't.
if (isValid) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else{
cell.accessoryType = UITableViewCellAccessoryNone;
}

Are you reloading your tableView using
[yourtableView reloadData]
when your data modifies.

Related

uitextfield of custom table cell

I am creating a table with three different types of custom cell, One of them, one custom cell is having UITextField. I create two rows using this custom cell. I set tag and delegate for textfields of both row.
My problem is, when I scroll the table, these rows with textfields move up and disappear from the screen, when scroll down, that time my app gets crash.
I get an error like
-[CellImageViewController txtField]: unrecognized selector sent to instance 0xa0ea5e0
Here is my code for cellForRowAtIndexPath:
if (indexPath.row == 0 )
{
if (cell == nil) {
cell = [[[CellWithTextFieldViewController alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID] autorelease];
}
cell.txtField.tag =1;
cell.txtField.delegate = self;
cell.txtField.text = #"kjfkd";
}
return cell;
}
else if(indexPath.row==1)
{
if (cell == nil) {
cell = [[[CellWithTextFieldViewController alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID] autorelease];
}
cell.txtField.tag = 2;
cell.txtField.text = #"glk";
cell.txtField.delegate = self;
return cell;
}
Any one have idea about this issue?
you have different type of cells, so you need to use a cellIdentifier different for each one.
Try this:
customOrNormalCell *cell [tableView dequeueReusableCellWithIdentifier:CellIdentifier]
if(!cell){
cell = [[CellWithTextFieldViewController alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:[NSString stringWithFormat:#"%i", indexPath.row]];
}
With this code, each cellIdentifier will be 1,2,3,4... (All different)
I'm pretty sure that it will solves the problem
create UITextField before create UITableView and Add your Textfield object in cell Content view
[cell.contentView addSubview:yourTxtFieldOblect];
It looks like you might be reusing a cell of a different type.
Try making sure which kind of class the cell you are reusing is before trying to access it's properties.
why you are define cell for each row?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = [NSString stringWithFormat:#"Cell%d",indexPath.row];
CellWithTextFieldViewController *cell = (CellWithTextFieldViewController *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
cell =[[[CellWithTextFieldViewController alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]autorelease];
cell.txtField.tag = indexPath.row;
cell.txtField.text = [SET TEXT FROM ARRAY];
cell.txtField.delegate = self;
}
}
I had also faced this problem in my project.
just try this:
Disabled the scrolling property in Tableview and create a scrollview.Then add your Tableview in your scrollview.
UITableView *table=[[UITableView alloc]initWithFrame:CGRectMake(0, 0, 976, 395) style:UITableViewStylePlain];
[table setSeparatorStyle:UITableViewCellSelectionStyleNone];
UIScroll *scroll=[[UIScrollView alloc]initWithFrame:CGRectMake(24, 168, 978, 395)];
[table setScrollEnabled:NO];
[scroll addSubview:table];
[self.view addSubview:scroll];
[scroll sendSubviewToBack:table];
Try this
static NSString *cellIdentifier= #"Cell";
CellWithTextFieldViewController *cell = (CellWithTextFieldViewController *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[CellWithTextFieldViewController alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.txtField.tag =indexPath.row+1;
cell.txtField.delegate = self;
cell.txtField.text = #"kjfkd";
return cell;
While scrolling tableView your cell is getting reused. Thats why textField is disappearing. Try to use different cell id for different custom cells. Dont forget to give the same id in nib file for cell identifier
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *customCellOne = #"customCell1";
static NSString *customCellTwo = #"customCell2";
UITableViewCell *cell =nil;
if (0 == indexPath.row)
{
cell = (CustomCellOne *)[tableView dequeueReusableCellWithIdentifier:customCellOne];
if (nil == cell)
{
// Create custom cell one and do what ever you want
}
}
else if (1 == indexPath.row)
{
cell=(CustomCellTwo *)[tableView dequeueReusableCellWithIdentifier:customCellTwo];
if (nil == cell)
{
// Create custom cell two and do what ever you want
}
}
return cell;
}
I don't know,may be when reused the cell,the textfield delegate was released.
may be you can set the
textfield.deleagate = self;
in CellWithTextFieldViewController.m

UITableView not refreshed

I have an app consisting of a TabBar with a few TabBarControllers. One Controller contains a very simple table, which is supposed to display the contents of a NSMutableDictionary. When you hit the appropriate button, the Dictionary is updated in a separate Controller and the view switches to the UITableViewController, displaying the newly updated table.
I can see the Dictionary being updated. But the TableView never reflects the changes. In fact, it seems to display the changes only the 1st time I enter that screen.
I have tried [self table.reloadData] and while it gets called, the changes aren't reflected to the UITableView.
Does anyone have any suggestions? I am happy to post code, but am unsure what to post.
Update: the table is updated and refreshed properly only the 1st time it is displayed. Subsequent displays simply show the original contents.
Background:
The tableview gets filled from a dictionary: appDelegate.currentFave. The tableview should get refreshed each time the ViewController is invoked by the TabBarController.
- (void)viewWillAppear:(BOOL)animated
{
NSLog(#"in viewWillAppear");
[super viewWillAppear:animated];
[self loadFavesFile];
[self.tableView reloadData];
}
// load the Favorites file from disk
- (void) loadFavesFile
{
// get location of file
NSString *path = [self getFavesFilePath];
// The Favorites .plist data is different from the Affirmations in that it will never be stored in the bundle. Instead,
// if it exists, then use it. If not, no problem.
if ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
// read Faves file and store it for later use...
NSMutableDictionary *tempDict = [NSMutableDictionary dictionaryWithContentsOfFile:path];
appDelegate.sharedData.dictFaves = tempDict;
// grab the latest quote. Append it to the list of existing favorites
NSString *key = [NSString stringWithFormat:#"%d", appDelegate.sharedData.dictFaves.count + 1];
NSString *newFave = [NSString stringWithFormat:#"%#", appDelegate.currentFave];
[appDelegate.sharedData.dictFaves setObject:newFave forKey:key];
} else {
NSLog(#"Favorites file doesn't exist");
appDelegate.sharedData.dictFaves = nil;
}
}
// this gets invoked the very first call. Only once per running of the App.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// reuse or create the cell
static NSString *cellID = #"cellId";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:cellID];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
}
// allow longer lines to wrap
cell.textLabel.numberOfLines = 0; // Multiline
cell.textLabel.lineBreakMode = UILineBreakModeWordWrap;
cell.textLabel.font = [UIFont fontWithName:#"Chalkduster" size:(16)];
cell.textLabel.textColor = [UIColor yellowColor];
// NOTE: for reasons unknown, I cannot set either the cell- or table- background color. So it must be done using the Label.
// set the text for the cell
NSString *row = [NSString stringWithFormat:#"%d", indexPath.row + 1];
cell.textLabel.text = [appDelegate.sharedData.dictFaves objectForKey:row];
return cell;
}
I found the problem. I was not properly initializing and assignng the TableView in my view controller. See below
- (void)viewDidLoad
{
[super viewDidLoad];
tableView = [[UITableView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame] style:UITableViewStylePlain];
tableView.dataSource = self;
tableView.delegate = self;
tableView.backgroundColor=[UIColor blackColor];
self.view = tableView;
}
Assuming the code you have put up is correct, you want to use [self.table reloadData]. You have the . in the wrong place.
I had this same problem yesterday, for me it turned out I had set the wrong file owner in interface builder and hadn't set up the data source and delegates for the table view properly.
Try going into interface builder and right-clicking on the file owner, this should show you if anything isn't connected up properly.
You should make sure that your Interface Builder connections are set up properly, but what this problem really sounds like is that you have your UITableViewCell setup code in cellForRowAtIndexPath: inside your if(cell == nil) statement. Which it shouldn't be. Let me explain. If you have a list of cells, and you want to set the titles to each cell to a string in an array called myArray, right now your (incorrect) code looks like this:
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cellIdentifier"];
if (cell == nil) {
// No cell to reuse => create a new one
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:#"cellIdentifier"] autorelease];
[[cell textLabel] setText:[myArray objectAtIndex:[indexPath row]]];
}
return cell;
}
Can you see the problem with that logic? The cell will only get an updated title if no reusable cell can be found, which, in your case, sounds like the situation. Apple says that you should create a 'new' cell each time cellForRowAtIndexPath: is called, which means that you put all of your setup code outside of the if(cell == nil) check.
Continuing with this example, the proper code would look like this:
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cellIdentifier"];
if (cell == nil) {
// No cell to reuse => create a new one
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:#"cellIdentifier"] autorelease];
}
[[cell textLabel] setText:[myArray objectAtIndex:[indexPath row]]];
return cell;
}
This way, the cell gets assigned the proper string whether or not a reusable cell is found and so calling reloadData will have the desired effect.

Problem: Multiple selection tableview cells being reused

I have a tableview, i need to have a checkmark displayed everytime i select a row. (Multiple selection) My code is given below. I am also able to unselect a row.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *RootViewControllerCell = #"RootViewControllerCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:RootViewControllerCell];
if(nil == cell)
{
cell = [[[UITableViewCell alloc]initWithFrame:CGRectZero reuseIdentifier:RootViewControllerCell] autorelease];
}
cell.textLabel.font = [UIFont fontWithName:[NSString stringWithFormat:#"HelveticaNeue-Bold"] size:12];
textView.textColor = [UIColor colorWithRed:0.281 green:0.731 blue:0.8789 alpha:1];
cell.textLabel.text = [optionsArray objectAtIndex:[indexPath row]];
if (pathIndex == indexPath)
{
if (cell.accessoryType == UITableViewCellAccessoryCheckmark)
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
else {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
pathIndex = indexPath;
[surveytableView reloadData];
}
But i have a problem with the cells being reused. When i select a cell another cell elsewhere also gets selected. Only the checkmark (or no checkmark) is getting reused other details like the row title, etc., don't get reused. Any solutions to fix this. Thanks in advance.
Add it to cellForRowAtIndexPath:
if ([tableView.indexPathsForSelectedRows containsObject:indexPath]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else if (![tableView.indexPathsForSelectedRows containsObject:indexPath]) {
cell.accessoryType = UITableViewCellAccessoryNone;
}
Worked for me
At your
if (pathIndex == indexPath)
you're comparing pointers not the values of them, try
[pathIndex isEqual:indexPath]
or use
- (NSComparisonResult)compare:(NSIndexPath *)otherObject;
Next you're assigning a value to pathIndex without retaining or copying it like
pathIndex = [indexPath copy];
(of course now since you're retaining the value, before copying your new object you have to release the previous one [pathIndex release];)
Finally, no multiple selection is provided by your implementation, only single selection. You could try adding and removing NSIndexPath objects to an NSMutableArray and check against their presence in your mutable array at cellForRowAtIndexPath instead.
The issue is that you only do something with the accessory if the current row matches pathIndex.... so what if it is a normal cell...? You never set it back. You want...
cell.accessoryType = UITableViewCellAccessoryNone;
if ([pathIndex isEqual:indexPath])
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
It is good practice to reset the cells before you set any specific properties.

Programmatically scrolling to and coloring a UITableViewCell at runtime

I have UITableViewController which contains a list of items. Now, I want the list to be automatically scrolled to a item (index = bestOne ) once the view appears. Meanwhile I want the item to be colored into red and be labeled as Marked.
My code roughly achieves what I want. But, I actually see more than one red items iterating: every 10 items, there is a red item.
I am quite new to iphone development, I figure it might have something to do with reusable cells. But I am not exactly sure why. Can anybody suggest one way to solve this issue? Thanks in advance.
(void)viewDidAppear:(BOOL)animated
{
if (self.bestOne != -1)
{
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.bestOne inSection:0];
[self.tableView scrollToRowAtIndexPath: atScrollPosition: animated:YES];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:reuseIdentifier:CellIdentifier] autorelease];
}
cell.textLabel.text = [self.array objectAtIndex:indexPath.row];
if (indexPath.row == self.bestOne)
{
cell.detailTextLabel.text = #"Marked";
cell.textLabel.textColor = [UIColor redColor];
}
return cell;
}
You are right about the reusable cells part.
Your code should be something like –
cell.textLabel.text = [self.array objectAtIndex:indexPath.row];
if (indexPath.row == self.bestOne)
{
cell.detailTextLabel.text = #"Marked";
cell.textLabel.textColor = [UIColor redColor];
}
else
{
cell.detailTextLabel.text = #"";
}
On reuse, you get the exact cell that you had set before. While other cells are undistinguishable, the marked cell stands out with its specifically set detailTextLabel. You need to reset it before you can use it as an unmarked cell.
you look like you are on the right track with the color issue, you may accumulate red colored text cells, if you aren't calling [tableView reloadData] or reloading the old red cells specifically, which you would want to do if you have a large table. your scrolling looks good, don't know why that wouldn't work.

UITableView Checklist Problem

I have this bizarre problem. I'm making a checklist program with XCode and I'm using UITableView with UITableViewCellAccessoryCheckmark. I can select cells and the checkmark will appear, but somehow, other cells that I have NOT yet selected below will also have a checkmark appear. Any ideas?
Here's my check mark coding:
- (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell;
cell = [aTableView cellForRowAtIndexPath: indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
I don't know if this affects it, but I also implemented this method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"CellIdentifier";
// Dequeue or create a cell of the appropriate type.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryNone;
}
// Configure the cell.
if(tableView == Table1){
switch(indexPath.section){
case 0:
cell.textLabel.text = [array1 objectAtIndex:indexPath.row];
break;
case 1:
cell.textLabel.text = [array2 objectAtIndex:indexPath.row];
break;
case 2:
cell.textLabel.text = [array3 objectAtIndex:indexPath.row];
break;
}
//cell.textLabel.text = [NSString stringWithFormat:#"Row %d", indexPath.row];
}
if(tableView == Table2){
cell.textLabel.text = [array4 objectAtIndex:indexPath.row];
}
return cell;
}
Thanks.
Set the cell.accessoryType each time you call tableView:cellForRowAtIndexPath:. Otherwise, when you reuse a cell, you'll get it's accessoryView instead of what you're expecting.
So, yeah, you'll need to keep track in when NSIndexPaths are selected by some method other than just looking at the accessoryType.
You should keep the checked/unchecked info in data source (array).
I also advise you to remove the cell.accessoryType = UITableViewCellAccessoryNone; line.
This line will be executed only for few first cells. All the other cells will be "reused" - meaning that the old (already initiated) cells will be used, and you will have to modify the details that are displayed on these cells (all inside cellForRowAtIndexPath as you do now).
In addition you will have to add a similar line (something like cell.accessoryType = ([[array objectAtIndex:indexPath.row] boolValue] ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;).
In general, I suggest you to use one array for holding the data for your table, when each item in the array will be a dictionary. This way you will be able to hold the texts and the boolean checkmarks (inside NSNumber) and easily access them when needed.