I'm creating a UITableView, containing information about a company. It has multiple sections, and I filled most cells with just a textlabel and a detailtextlabel through 2-dimensional array's. I want 1 cell (the second cell of the first section to be exact) to be filled with an image.
The first thing that popped up in my mind, was creating another 2-dimensional array, and fill it with empty objects, except for the one image. however, that doesn't make sense and i'm sure there are more professional and logical ways to do this.
So the question is: How do I fill one tableViewCell with an image, in a tableview with multiple sections. any help would be highly appreciated, thank you in advance!
You need not to create a multidimension array.Just add a check in cellForRowAtIndexPath method of UITableView datasource
if(indexpath.section == 0)
and set the background image of cell content view or you can also create a new UIImageView and add that in cell as a subview.
If you expect a few such exceptions, you can create a dictionary of exceptions, where the keys are NSIndexPath objects, the values images. Then in tableView:cellForRowAtIndexPath: check to see if the dictionary contains the index path. If so, use the image, else go to your array for data.
Your problem is not uncommon, the only thing to understand now is the delegate methods give you enough information about the section and the row displayed. Now in those methods you can use your datasource and check for the required conditions and construct/return the cell.
It will be something on these lines:
(UITableViewCell *)tableView:(UITableView *)tableview cellForRowAtIndexPath:(NSIndexPath*)indexPath {
// When you get to the section where you want customisation create and return the cell accordingly
if(indexpath.section == 0) {
// create Special Cell
} else {
// Create Normal Cell
}
return cell;
}
Dont forget to reuse the created cells using dequecellwithreuseindentifier method. I am sure you can figure that out.
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{
if (indexPath.section==0 && indexPath.row==1) {
UIView *v=[[UIView alloc] initWithFrame:cell.frame];
[v setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:#"image1.png"]]];
cell.backgroundView=v;
}else{
UIView *v=[[UIView alloc] initWithFrame:cell.frame];
[v setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:#"image2.png"]]];
cell.backgroundView=v;//OR SET cell.backgroundView=nil;
}
}
You can use -
(UITableViewCell *)tableView:(UITableView *)atable cellForRowAtIndexPath:(NSIndexPath*)indexPath {
cell.imageView.image = [UIImage imageNamed:#"image.png"];
return cell;
}
I hope, it will help you.
Related
This is driving me absolutely insane.
I have a UITableView with cells populated via an NSFetchedResultsController that should have their background color set based upon one of the Core Data parameters.
This table view is in the master view of a UISplitViewController and the selected cell needs to remain visibly selected to indicate what is being displayed in the detail view.
Based upon guidance from several other Stack Overflow questions, I have learned that the ideal place to configure the cell is during the willDisplayCell delegate call, like this:
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
WorkTask *workTask = (WorkTask*) [self.fetchedResultsController objectAtIndexPath:indexPath];
if ([workTask.strStatus isEqualToString:#"A"]) {
cell.backgroundColor = [self colorWithHexString:#"fffdcf"];
// cell.textLabel.backgroundColor = [self colorWithHexString:#"fffdcf"];
// cell.detailTextLabel.backgroundColor = [self colorWithHexString:#"fffdcf"];
} else if ([workTask.strStatus isEqualToString:#"B"]) {
cell.backgroundColor = [self colorWithHexString:#"cfffd1"];
// cell.textLabel.backgroundColor = [self colorWithHexString:#"cfffd1"];
// cell.detailTextLabel.backgroundColor = [self colorWithHexString:#"cfffd1"];
} else if ([workTask.strStatus isEqualToString:#"C"]) {
cell.backgroundColor = [self colorWithHexString:#"ffcfcf"];
// cell.textLabel.backgroundColor = [self colorWithHexString:#"ffcfcf"];
// cell.detailTextLabel.backgroundColor = [self colorWithHexString:#"ffcfcf"];
} else {
cell.backgroundColor = [self colorWithHexString:#"ffffff"];
// cell.backgroundColor = cell.contentView.backgroundColor;
}
This mostly sort of works. But...
Depending on how I play around with different variants of accomplishing this, I end up with the background color being ignored sometimes (and only sometimes?!?) behind the textLabel and detailTextLabel. Or causing the cell to display incorrectly while selected. Or having the checkmark indicator displayed without a background color. Or having new items added to the core data database showing up in the table, but with the no background color for the cell, but the text labels having a background color.
No matter what I do, I have not found a simple and intuitive way to make things behave overall as expected - particularly when cells are being programmatically selected.
In fact - the cell selection seems like it might be at the root of the problem. The selected cell is usually the one that ends up drawn incorrectly after I change the selection to another, particularly if the color of the cell changed while the cell was selected.
Is there any example out there anywhere of how this is supposed to work?!?!
Thanks!
If I were you I would create a UITableViewCell subclass with your own titleLabel/subtitleLabel UILabels in it and stop using the textLabel/detailTextLabel. In the xib file you can just change the background color of the labels and of the cell. I have never had the sort of problem you are experiencing when I have used custom cells as opposed to the default cells.
Here's an example of how to load a UITableViewCell from an xib:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:#"CustomCell"];
if (cell == nil) {
// Load the top-level objects from the custom cell XIB.
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"CustomCell" owner:self options:nil];
// Grab a pointer to the first object (presumably the custom cell, as that's all the XIB should contain).
cell = [topLevelObjects objectAtIndex:0];
}
cell.titleLabel.text = #"whatever";
cell.subtitleLabel.text = #"whatever";
return cell;
}
You could also try setting the background color of the cell's contentView.
cell.contentView.backgroundColor = ...;
If you really can't figure it out, then in a UITableViewCell subclass you could always just put a UIView of your own in the background of the cell and change the background color of that view instead.
willDisplayCell:forRowAtIndexPath: might not get called after insertRowsAtIndexPaths: is called (i.e. when you add items into core data w/ a fetchedresultscontroller). If absolutely necessary maybe you should try setting the background color of the cell and it's contentView in both cellForRowAtIndexPath: and willDisplayCell:forRowAtIndexPath:.
For some bizarre reason the background color of UITableViewCell objects can only be set just before the cell is drawn. In your UITableView's delegate implement this method:
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
Set the background color of the cell there and it will draw the way you want.
i have the following code which will displays result in a UItable view along with an image.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//create a cell
UITableViewCell *cell = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:#"cell"];
// fill it with contnets
NSDictionary *exercise = [exercises objectAtIndex:indexPath.row];
cell.textLabel.text = [exercise valueForKey:#"player"];
UIImage *image = [UIImage imageNamed:#"iphone.gif"];
cell.imageView.image = image;
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
// return it
return cell;
}
is there an option where i can display one image for all the cells for ex. 1 image on the left side and then 3 rows by the right side. I am a new bid and still getting my grip on iPhone coding.Please suggest me how we can do this.Thanks.
Yup, a UITableViewCell is pretty much another UIView, so you can add subviews to it and customize it anyway you need. For example, if you need to add an image to all the cells, just add it onto the contentView;
[cell.contentView addSubview:myImageView];
If you have several customizations needed for your cell, and are looking for a highly custom look as opposed to the generic look provided by the standard cells, I'd recommend looking into creating a custom UITableViewCell. The reason is that the standard cells have already laid out UI's with labels, images etc, and anything you add onto it may interfere with the existing UI in ways you do not intend.
I've got this nasty problem. My class, which is subclassing UITableViewController, has a method which is invoking
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
The method which is invoking what is above is this one:
- (void) insertInfo:(UIImage *)image
{
self.hotelImage = nil;
self.hotelImage = image;
numRows = numRows + 1;
[self.tableView beginUpdates];
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
}
This is how I am creating a cell:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
self.datacell = nil;
self.datacell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:#"SimpleTableIdentifier"] autorelease];
self.myImageView = nil;
self.myImageView = [[UIImageView alloc] initWithImage:self.hotelImage];
[self.myImageView setFrame:CGRectMake(5, 5, 80, 75)];
[self.datacell.contentView addSubview:self.myImageView];
[self.myImageView release];
self.tableView.userInteractionEnabled = YES;
self.tableView.separatorColor = [UIColor clearColor];
return self.datacell;
}
So, my problem is that when I scroll the table, all images in the table get replaced by a single image at index 0. My guess is that it has something to do with the fact that when cell is created, every image in the section is considered at index 0, but different image is shown when table is created. But when the table is scrolled by user, different images get overtaken by an image the is in the index 0 of the first cell.
This is exactly what happens, the image on the first cell is shown on all cells when the table begins to scroll.
I just don't know how to make every cell retain its unique image when the table is scrolled. My guess is it has something to do with placing image indexPath.section??? But I am not sure. Could somebody please help me with this problem?
Thank you,
Victor.
Effectively you're editing the contents of your table with insertInfo, but not editing its actual source, so as soon as it needs to redraw those cells, they get reverted to its original source. Try using something along the lines of:
self.myImageView=[[UIImageView alloc] initWithImage:[myImageArray objectAtIndex:indexPath.row]];
The fact is that the tableView doesn't keep your cells around. As soon as you scroll them out of view they are gone, released, deallocated as far as you know, and the table view asks the data soucre for new replacement cells. Your cellForRowAtIndexPath is always returning the same cell, independent of what the table view asks for.
You should be storing the images sent to insertInfo into an array, then in cellForRowAtIndexPath, always return the image from the array by index, looked up by indexPath.row and indexPath.section. Every time you scroll, that cellForRowAtIndexPath is called to get all the new cells that weren't on screen, this is why the cells always "change to" the most recent image sent to insertInfo.
Try adding a new file to your project, subclass of UITableViewController, and check out the default code there. You'll find dequeueReusableCellWithIdentifier is also a useful one.
The key concept here is that cellForRowAtIndexPath: is a question, and your code needs to check the values of indexPath.section and indexPath.row, and return a value that belongs to that row/section.
I want to make a table view in which i want to show some items or images ( 4 items in a row)For eg: If i have 7 images i want to show 4 in first row and 3 in next row and if i have 13 images then it should display like 4,4,4,1 in rows 1,2,3,4 respectively. I have achievd this but my problem is those images keep changing their position (shift from 1 to 3 row and vice versa) when i scroll the table view. Please tell me some way so that my images automatically adjust themselves 4 in a row and does not repeat if i scroll the table view.
My code is:
(array has 7 image-datas stored in it)
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 93;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [array count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Avi"];
for (UIView *view in cell.contentView.subviews) {
[view removeFromSuperview];
}
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Avi"] autorelease];
cell.backgroundColor = [UIColor clearColor];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
NSData *imageData;
for(int i=0;i<4;i++){
imageData=[array objectAtIndex:indexpath.row];
UIButton *Button = [UIButton buttonWithType:UIButtonTypeCustom];
Button.frame = CGRectMake(5+(i*77), 5, 77,85);
[Button setBackgroundImage:[UIImage imageWithData:imageData] forState:UIControlStateNormal];
[cell.contentView addSubview:Button];
}
return cell;
So the code snippet you've posted isn't particularly helpful, but this almost certainly is a case of not recycling your table view cells properly.
Table views 'recycle' their cells for efficiency and performance - when a cell scrolls out of view it is marked for recycling: when you next request a new cell you will be given a recycled cell if one is available (otherwise a new cell will be created).
If all your cells use the same layout, this isn't a problem. However, if you adjust the layout of your cells (as you do) this can cause problems, because you might have set up a cell for 2-picture layout and have it be recycled for a 4-picture cell.
You have two options here: either take care to reset your cells as required (when you request a new cell reset all the view parameters you've created, which in your case would be by removing all the superviews), or create different cells with different identifiers for each of your layouts.
By the way, just looking at your current code it seems like you may want to consider some custom cells. Currently you add new images to the cell's contents view, which means since you never remove them every time your cell gets recycled more and more and more images get added! It's quite inefficient. Better to create a cell that has four image views ready to go, and you just assign the image property as required.
I'm trying to add a subview to a UITableViewCell and the design that I'm working from demands that this particular subview (an image) needs to be larger than the actual UITableViewCell and thus partly overlap its siblings.
So I've set up my table cell, generated my image and added it to the cell's contentView:
// rowHeight for the UITableView is 45.0f
UIImage *image = [self createCellThumbnail: someImage];
UIImageView *thumbView = [[UIImageView alloc] initWithFrame: CGRectMake(150, -5, 55,55)];
thumbView.transform = CGAffineTransformMakeRotation(0.1f);
thumbView.image = image;
cell.clipsToBounds = NO;
cell.contentView.clipsToBounds = NO;
[cell.contentView addSubview: thumbView];
While the image will 'overflow' into the cell below it, the top of the image is always clipped, as demonstrated here:
Does anyone know if what I'm trying to do is possible with the current approach?
Or should I just figure out a way to draw these images onto the UITableView after all the cells are drawn (it's a non-scrollable tableview, so that would work and be fairly easy).
Update:
Have also tried adding the following, to no avail:
cell.opaque = NO;
cell.contentView.opaque = NO;
cell.clearsContextBeforeDrawing = NO;
cell.contentView.clearsContextBeforeDrawing = NO;
cell.clipsToBounds = NO;
cell.contentView.clipsToBounds = NO;
I seems that the tableView renders its cell from bottom to top, so the cells above one cell overlap that one cell. To avoid this, you'd have to set the backgroundColor of all cells to +[UIColor clearColor] so that you won't see those overlap problems.
But setting the backgroundColor to clear in -tableView:cellForRowAtIndexPath: does not make any sense. UIKit does a lot of stuff with the cell before it's drawn, so does it reset the backgroundColor property of the cell.
What we need to do is setting the backgroundColor in a later state. Luckily there is this -[UITableViewDelegate tableView:willDisplayCell:forRowAtIndexPath:] which we can implement like this:
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
cell.backgroundColor = [UIColor clearColor];
}
Now we're setting the backgroundColor just before the cell is drawn an this turns out to be working.
UPDATE:
So I've done some more experimentation and the following solution still works without having to set the background of the cell to transparent, this involved moving the z order of the covered cell. This works with highlighting and selecting of the other cell (via the relevant callbacks), and if the two cell's backgrounds are different colors. Solution is as follows (you can ignore the didHighlight and didSelect methods if they don't matter to you):
(note that "covered row" is the one whose content we are trying to keep visible and In my case its content goes slightly into the row above, which was clipping it)
-(void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 0 && indexPath.row == ROW_ABOVE_COVERED_ROW)
{
NSIndexPath * rowbelow = [NSIndexPath indexPathForRow:indexPath.row+1 inSection:indexPath.section];
UITableViewCell* cell = [tableView cellForRowAtIndexPath:rowbelow];
[cell.superview bringSubviewToFront:cell];
}
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 0 && indexPath.row == ROW_ABOVE_COVERED_ROW)
{
NSIndexPath * rowbelow = [NSIndexPath indexPathForRow:indexPath.row+1 inSection:indexPath.section];
UITableViewCell* cell = [tableView cellForRowAtIndexPath:rowbelow];
[cell.superview bringSubviewToFront:cell];
}
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 0 && indexPath.row == COVERED_ROW)
{
[cell.superview bringSubviewToFront:cell];
cell.contentView.superview.clipsToBounds = NO;
}
}
NOTE: you should also set the background color of your content to clear, or it will adopt the bgcolor of the rest of your cell, and so when you manage to bring your content to the front of the covering cell, it will take the background color with it and leave a nasty looking block in the other cell (in my case my only content was the detailTextLabel and the textLabel):
// in cellForRowAtIndexPath:
[cell setBackgroundColor:[UIColor redColor]]; //using red for debug
cell.detailTextLabel.backgroundColor = [UIColor clearColor];
cell.textLabel.backgroundColor = [UIColor clearColor];
I hope that's helpful to anyone else trying this....
ORIGINAL:
For me the solution was to use:
self.contentView.superview.clipsToBounds = NO;
My cells were already transparent, but my content was still getting clipped. In my case I was using a custom cell which moves it's content up in layoutSubviews. So layoutSubviews for my custom cell wound up as follows:
-(void)layoutSubviews
{
[super layoutSubviews];
self.contentView.frame = CGRectOffset(self.contentView.frame, 0, -11);
self.contentView.superview.clipsToBounds = NO;
}
I don't know if this would work if the cell above was opaque, or if the cells were to highlight when pressed, whether this would cover up my content.
However, I didn't need to make the cell transparent again in the viewWillDisplayCell callback method - doing it in the normal cellForRowAtIndexPath was sufficient
I had this problem and I made sure my custom tableviewcell's main background had clip subviews checked and it solved the problem. This was with a custom tableview cell loaded from a xib though. Not exactly the same but similar situation.
I actually had the opposite just yesterday, I had created a custom table cell and for some reason I got an overflow which I didn't want to have. My solution was to add the following code to my view controller class:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 175;
}
When it matched the height of the table cell there was no overlap; when it was too small there was overlap. Mind you though that I got very quicky behavious so I'm not sure it's a very good idea to do this.