I'm semi new to developing for iOS.
And when i try to customize a tableview cell to put an image under the description text, it works, until i scroll, then it gets all messed up.
When i scroll down, then back up, the image is in a cell it shouldn't be in. :/
I deleted the code because it wasn't working. But what i was doing was creating a UIView with a frame, with a UIImageView inside it. Then i add it to cell.contentView.
Which works, until i scroll.
So could someone please help :/
Edit: here is what it looks like for anyone interested, i got it working. (Thanks Jonathan)
#define LEVEL_TAG 1
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UIImageView *showLevel;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
showLevel = [[[UIImageView alloc] initWithFrame: CGRectMake(65, 50, 0, 11)] autorelease];
showLevel.tag = LEVEL_TAG;
[cell.contentView addSubview: showLevel];
} else {
showLevel = (UIImageView *)[cell.contentView viewWithTag:LEVEL_TAG];
}
NSDictionary *dictionary = [listOfItems objectAtIndex:indexPath.section];
NSArray *levelArray = [dictionary objectForKey:#"Levels"];
NSString *levelValue = [levelArray objectAtIndex:indexPath.row];
UIImage *levelImage = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource: levelValue ofType:#"png"]];
CGImageRef starImage = levelImage.CGImage;
NSUInteger levelWidth = CGImageGetWidth(starImage);
showLevel.frame = CGRectMake(65, 50, levelWidth, 11);
showLevel.image = levelImage;
return cell;
}
It's because of the way the tableView reuses old cells, rather than creating new ones every time the user scrolls, which would make everything slower, and less efficient.
Have a look at Listing 5-3 on the Apple Documentation about customizing UITableViewCells, it shows you how to set up the cell, within the if statement where the cell is actually created, and not where the cell could have been reused.
Related
I didn't have this problem with iOS6, but am currently having it with iOS7. I have a UITableView and you can see 8 cells at the time the view is loaded. Each populated with different names from and array. If you scroll down, the next two cells look good, but everything past that gets text laid on top of it; That text being the contents of what was in the previous cells. So the 10th cell will have what was in the first cell, as well as what is supposed to be in the 10th cell laid on top of it.
Code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
//Create Label for Name inside cell
UILabel *name = [[UILabel alloc] initWithFrame:CGRectMake( 7.0, 5.0, 300.0, 30.0 )];
[name setText:[self.entriesArray objectAtIndex:indexPath.row]];
//Check to see if current person is a Parent or Child
NSString *class = [self.database getCellDataWithMembership:[self.MembershipArray objectAtIndex:indexPath.row] andColIndex:4];
if([class isEqualToString:#"CHILD"])
{
name.textColor = [UIColor colorWithRed:25.0f/255.0f green:111.0f/255.0f blue:45.0f/255.0f alpha:1.0f];
name.font = [UIFont fontWithName:#"Helvetica-Bold" size:17.0];
}
[cell.contentView addSubview:name];
return cell;
}
My skill with Table views is makeshift at best. I've been reading lots of documentation and researching solutions, but was not able to come up with a solution. I just find it odd that it works perfect for iOS6, but not for iOS7.
So it fetches a person's name from an array and I want to populate the cells with those names. I was able to originally accomplish this using:
cell.textLabel.text = [self.entriesArray objectAtIndex:indexPath.row];
if([class isEqualToString:#"CHILD"])
{
cell.textLabel.textColor = [UIColor colorWithRed:25.0f/255.0f green:111.0f/255.0f blue:45.0f/255.0f alpha:1.0f];
cell.textLabel.font = [UIFont fontWithName:#"Helvetica-Bold" size:17.0];
If I use that instead of the "name" UILabel actions from the first code block, then it displays the names perfectly with no text overlay, but what becomes an issue is the text color. If they are labeled as a CHILD then they should be green text and bold. However, after scrolling down, every person becomes green when they shouldn't be.
Sorry for the lengthy question. I've been working on this and racking my brain around it and I just can't seem to figure it out. Any help would be greatly appreciated.
I'm dynamically adding UI objects to cells. As "caglar" notes, adding and then removing is probs not the best-practice. But, I am doing this also. The way I get around adding loads of UI objects to the cell, each time it's displayed, is by removing all my subviews first. The willDisplayCell delegate then adds them back. Clearly, if you want to remove only certain views, you'll have to tag the view and be more selective with your removal. But you can remove all with the following.
-(void)tableView:(UITableView *)tableView
willDisplayCell:(UITableViewCell *)cell
forRowAtIndexPath:(NSIndexPath *)indexPath {
[[cell.contentView subviews] makeObjectsPerformSelector:#selector(removeFromSuperview)];
}
Just ensure you're adding / removing your labels to the cell's contentView. In iOS7, you'll remove that too, if you're not careful.
Hope it helps you out.
In your code, labels are added to cell whenever cellForRowAtIndexPath: method is called. I mean you add labels many times. You can remove the label which was added before.
//If label was added with tag = 500, remove it
for (UIView *sv in cell.contentView.subviews)
{
if (sv.tag == 500)
{
[sv removeFromSuperview];
}
}
//Create Label for Name inside cell
UILabel *name = [[UILabel alloc] initWithFrame:CGRectMake( 7.0, 5.0, 300.0, 30.0 )];
[name setText:[self.entriesArray objectAtIndex:indexPath.row]];
name.tag = 500;
However, this solution is not a good solution. I think creating a custom UITableViewCell is the right thing to do.
You can try this method, when the cell is nil, you need to creare the UILabel* name, then you set the name label with a tag name.tag = 1000, then you can access this label with this method UILabel* name = (UILabel*)[cell.contentView viewWithTag:1000];.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
//Create Label for Name inside cell
UILabel *name = [[UILabel alloc] initWithFrame:CGRectMake( 7.0, 5.0, 300.0, 30.0 )];
name.tag = 1000;
[cell.contentView addSubview:name];
}
UILabel* name = (UILabel*)[cell.contentView viewWithTag:1000];
[name setText:[self.entriesArray objectAtIndex:indexPath.row]];
//Check to see if current person is a Parent or Child
NSString *class = [self.database getCellDataWithMembership:[self.MembershipArray objectAtIndex:indexPath.row] andColIndex:4];
if([class isEqualToString:#"CHILD"])
{
name.textColor = [UIColor colorWithRed:25.0f/255.0f green:111.0f/255.0f blue:45.0f/255.0f alpha:1.0f];
name.font = [UIFont fontWithName:#"Helvetica-Bold" size:17.0];
}
return cell;
}
You can set uilabels by using ios6/7 delta shown is size inspector .firstly set your total view for ios7 by changing values x,y,width,height and then change value in ios6/7 delta to make it for ios6 .Hope you get
you may change the this code.
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; -> UITableViewCell *cell = nil;
What makes scrolling so choppy on the UITableView? In my mind following code is a culprit. I am having very hard time to replace this logic with something other.
for (UIView *view in cell.contentView.subviews) {
[view removeFromSuperview]; }
This is what I am doing.
- (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];
}
for (UIView *view in cell.contentView.subviews) {
[view removeFromSuperview];
}
BGMArticleAbstract *articleAbstract = [self.section.articleAbstracts objectAtIndex:indexPath.row];
[cell.contentView addSubview:[self getHedlineFromArticleAbstract:articleAbstract]];
[cell.contentView addSubview:[self getThumbnailImageFromArticleAbstract:articleAbstract]];
[cell.contentView addSubview:[self getAbstractParaFromArticleAbstract:articleAbstract]];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell; }
I am doing, addSubview to contentview because I am creating a dynamic cell height. Is there any way I can make this scroll view work smooth ? Thank you for your help.
You should design your cell as you need it. Add labels and whatever you need to the cell, and then change the content of these already available subviews.
If you need to display an image, add once an UIImageView to the cell and only change the image property of it. Same for text fields and so on.
The way you do it makes the built-in cache useless, because you regenerate all subviews again and again..
To boost the performance even more, you can do the drawing of the cell by yourself.
Apple has a quite nice example project:
http://developer.apple.com/library/ios/#samplecode/AdvancedTableViewCells/Introduction/Intro.html
You are right that the problem is caused by how you return cells. The correct pattern is as follows...
- (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];
}
// see if cell contains our image views. A reused cell will, but a new cell won't
UIImageView *imageViewA = (UIImageView *)[cell viewWithTag:32];
UIImageView *imageViewB = (UIImageView *)[cell viewWithTag:33];
UIImageView *imageViewC = (UIImageView *)[cell viewWithTag:34];
if (!imageViewA) {
// the cell must be new, so create it's image views
// you should be able to borrow most of this code from your getHeadline/thumbnail/etc methods.
// the good news is that this relatively expensive code runs only for new
// cells and there are only a few of those - only enough to fill the visible frame
imageViewA = [[UIImageView alloc] initWithFrame:CGRectMake(/* frame it here */)];
[cell.contentView addSubview:imageViewA];
imageViewA.tag = 32;
imageViewB = [[UIImageView alloc] initWithFrame:CGRectMake(/* frame it here */)];
[cell.contentView addSubview:imageViewB];
imageViewB.tag = 33;
imageViewC = [[UIImageView alloc] initWithFrame:CGRectMake(/* frame it here */)];
[cell.contentView addSubview:imageViewC;
imageViewC.tag = 34;
// this too, need only be done upon creation
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
// now, whether it's a new cell or a reused cell, we have image views
BGMArticleAbstract *articleAbstract = [self.section.articleAbstracts objectAtIndex:indexPath.row];
// change your methods getHeadline... getThumbnail... etc to answer UIImages
// not UIImageViews, which are setup only for new cells
imageViewA.image = [self getHedlineFromArticleAbstract:articleAbstract]];
imageViewB.image = [self getThumbnailImageFromArticleAbstract:articleAbstract]];
imageViewC.image = [self getAbstractParaFromArticleAbstract:articleAbstract]];
// as a side note, once you get these methods returning images (more like model objects)
// rather than image views (view objects) they might be more appropriately placed
// in the BGMArticleAbstract class rather than the view controller
return cell;
}
I'm dynamically loading images from a web service. The images will be loaded (with [UIImage imageWithData:data];) and be placed in a in an UIImageView in my custom UITableViewCell using the setImage message
. I gave the imageView a width and height of 27 by 19 in the interface builder and told him to "Aspect fit" (tried all the others too btw), but the image doesn't do that. It just scales (in aspect, I think) to fill the view cell.
I tried a lot of things, like resizing the image (does the job, but I can count the pixels on my retina display), resizing the UIImageView... But I just don't get is... Someone got an idea what I'm doing wrong?
The code that changes the cell:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"NewsTableViewCell" owner:self options:nil];
cell = self.tableCell;
self.tableCell = nil;
}
viArticle *article = [self.viData.articles objectAtIndex:indexPath.row];
UILabel *label;
label = (UILabel *)[cell viewWithTag:1];
label.text = article.title;
label = (UILabel *)[cell viewWithTag:2];
label.text = [NSString stringWithFormat:#"%# %#", article.time, article.type];
if (article.image != nil) {
UIImageView *imageView;
imageView = (UIImageView *)[cell viewWithTag:0];
[imageView setImage:article.image];
}
return cell;
}
This is the view:
And the settings:
What happens if you untick "Autoresize Subviews"?
#GuidoH hey sorry for the late reply..
Here is the code that will add the image to the table view cell.
-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *SimpleTableIdentifier = #" SimpleTableIdentifier ";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: SimpleTableIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault reuseIdentifier:SimpleTableIdentifier] autorelease];
}
UIImage *image = [UIImage imageNamed:#"star.png"];
cell.imageView.image = image;
NSUInteger row = [indexPath row];
cell.textLabel.text = [listData objectAtIndex:row];
return cell;
}
//use this delegate it will increase the row size and thus your imagesize will get increased too.
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 80; //value can be changed
}
I would suggest scaling the images will surely lead to slow performance by your app.
I just posted a "solution" earlier today, but that seem to work, but was a wrong assumption. After asking on IRC I found the real solution. I was using the tag 0, that one shouldn't be used. Changing it to an higher value really solved my problem. Sometimes it can be thát easy. :)
Thanks y'all.
If you want to resize the UIImageView you can use the frame property.
suppose you have a UIImageView declare in .h file(lets take UIImageView *myImage;) and it is linked to the interface builder too.
you have synthesis it in .m class etc.
then when you want to resize the UIImageView, use
myImage.frame = CGRect(x,y,width,height);
Note: by declaring the width and height in the code, the width and height declared in the IB will be override.
then dont forget to add it to subview,
i.e [self.view addSubview:myImage];
and its done, you can see the changes.
Hey guys i have a table view that can add and delete cells. but when i delete the only cell that comes with the app, and i try to add a new cell with the text of "Meghan Way" and the text just automatically changes it self to the original cells text which is "House 1" here is my code!
- (IBAction)saveButton:(id)sender {
FacePlatesViewController * viewController = (FacePlatesViewController
*)self.parentViewController;
[viewController addObject:[NSMutableDictionary dictionaryWithObject:text.text
forKey:#"name"]];
[self dismissModalViewControllerAnimated:YES];
}
- (IBAction)cancel:(id)sender {
[self dismissModalViewControllerAnimated:YES];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:
(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero
reuseIdentifier:CellIdentifier] autorelease];
cell.textLabel.text = [[cells objectAtIndex:indexPath.row] valueForKey:#"name"];
UIImage * myimage = [UIImage imageNamed: #"check.png"];
image = [[UIImageView alloc]initWithImage:myimage];
tableView.backgroundColor = [UIColor clearColor];
self.myTableView = tableView;
}
return cell;
}
this is for the save button! any help would be very appreciated:D Thanks
You code is quite messed up. I have improved it below and added comments:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:
(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero
reuseIdentifier:CellIdentifier] autorelease];
} //The if block should end here. You should set the cell's label irrespective whether the cell was nil. This is the cause of the issue you are facing.
cell.textLabel.text = [[cells objectAtIndex:indexPath.row] valueForKey:#"name"];
//You are doing nothing with the UIImage
//UIImage * myimage = [UIImage imageNamed: #"check.png"];
//image = [[UIImageView alloc]initWithImage:myimage];
//You should be setting the background color just once, in ViewDidLoad, not here.
//tableView.backgroundColor = [UIColor clearColor];
//I don't see why this is required
//self.myTableView = tableView;
return cell;
}
Are you storing the text labels for these cells in any kind of array or dictionary and loading them in there using the standard "cellForRowAtIndexPath?" If so, then you need to delete the dictionary / array entry in that data source to prevent it from being used again.
I can't tell for sure without seeing some more code...but it sounds like a cell recycling issue. I could be wrong...but I'd need to see more info.
hey people im having trouble with loading my array of strings into a tableview , what i have already done is parse information and stored the data i need into an mutablearray of elements called statues1, now what i want to do is load up the statues1 into the table view with customize lable so the user can see all the values , now my problem is that when i load up the table view it gives an error ""BAD EXCESS", Please help me out for this?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
int counter=indexPath.row;
NSString *CellIdentifier = [NSString stringWithFormat:#"%d",counter];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell.selectionStyle=UITableViewCellSelectionStyleNone;
UIImageView *imgViewBack=[[UIImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 100.0)];
imgViewBack.image=[UIImage imageNamed:#"black-_image.png"];
[cell.contentView addSubview:imgViewBack];
if(statuses1)
{
UILabel *lblTitle=[[UILabel alloc] initWithFrame:CGRectMake(100.0, 10.0, 200.0, 20.0)];
lblTitle.text=[statuses1 objectAtIndex:indexPath.row];
[cell.contentView addSubview:lblTitle];
[lblTitle release];
}
//[cell.contentView addSubview:btnRowButton];
}
return cell;
}
Instead of adding a new label view for each cell, you can
cell.detailTextLabel.text = [statuses1 objectAtIndex:indexPath.row];
I'm not sure, but that release after that could be causing the error. You just check out hte traceback to see if you can figure out which call caused it (the little yellow button with a bug on it)