How can I stop my custom UITableViewCell backgroundImage from being stretchable? - iphone

If I create a background image for my table cell in the init method of my UITableViewCell subclass, the image comes out exactly how I drew it, and tableView:heightForRowAtIndexPath: simply adds a gap around it.
But if instead I create the background image in my tableView's tableView:cellForRowAtIndexPath: method and set it, changing the cell height will now stretch the image.
I need to create the background views in the cellForRowAtIndexPath method, as the background changes for different rows. How can I make my image's size fixed again?

Have you tried setting the contentMode to UIViewContentModeCenter for the backgroundView of the cell?
put it here
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
cell.backgroundView.contentMode = UIViewContentModeCenter;
}

You could create something with:
UIView *cellBackView = [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
<insert image>;
cell.backgroundView = cellBackView;
My guess is the backgroundView gets strechted automatically, but you could make sure the image isn't stretched on that view by setting a width and height. This way, you can do whatever you like with that view.

Related

Accessing -willDisplayCell method of moreNavigationController's UITableView

After setting the backgroundView of UITableView in moreNavigationController like so...
UITableView *moreTableView = (UITableView *)tabBarController.moreNavigationController.topViewController.view;
[moreTableView setBackgroundView:[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"bg.png"]]];
...the cells of that UITableView changed their backgroundColor from white to clear (transparent). I've tried setting it back to white with the following lines of code...
for (UITableViewCell *cell in [moreTableView visibleCells]) {
[cell setBackgroundColor:[UIColor whiteColor]];
}
...but unfortunately this does not work, so I guess the only solution would be to set that backgroundColor in the -willDisplayCell: method. Can anyone tell me how to access that method? Any help would be greatly appreciated.
If you have a custom cell then the back ground colour of the cell can be set in a subclass of UITabeViewCell, otherwise you should try to add this logic to the tableView:cellForRowAtIndexPath: method of the UITableView's datasource.
What you are doing in your loop will only effect the visible cells, since they will be reused and if the background is being set to clear dynamically then you'll always have your background overridden.

use table view or A view and three Subview or use labels

i am a new Programmer....so i wants to know... what i use (table view,
or view and three subviews, or i use labels for it)
for generate this view on button click.... i do everything programatically...
CGRect cgRct = CGRectMake(0.0, 0.0, 480, 320); //define size and position of view
myView = [[UIView alloc] initWithFrame:cgRct]; //initilize the view
UITableView *table = [[UITableView alloc]initWithFrame:CGRectMake(4,80,312,325) style:UITableViewStylePlain];
[table setDataSource:self];
[table setDelegate:self];
i am confused...:(
thanks in advance
It's a TableView with 3 different kind of subclassed UITableViewCells. This is alot of work so I can't just give you the code to do this. Instead I'll give a summary on which steps to take.
In short, to replicate this you'll need to:
Make 3 different UITableViewCell subclasses.
For exmaple the first contains 7 UILabels and an UIImageView.
Make a UITableView class which loads these 3 cells. Basicly like this,
(UITableViewCell*) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row == 0) return cell1;
else if (indexPath.row == 1) return cell2;
else return cell3;
}
Set variable rowHeights via this method:
(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
Set the tableview properties to have a UIImage as background + set border color. Also note that the tableviewstyle is grouped.
Alternatively you could create some images in photoshop and add the labels. Much easier but not very dynamic at all.
Depends on what you wanna get. If the view is fixed size is a lot easyer have it as subview, with proper background image, labels, buttons...
But if you can have more than the shown 3 "rows" table view with different custom cells is probably more flexible.

uitableviewcell background

I have a UItableView (grouped style). I wanted to customize it so that it appears like a "Stick it" or a "Post it" with a yellow background interface.
Hence is added the following code
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UIView *backgroundView = [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
backgroundView.backgroundColor = [UIColor yellowColor];
cell.backgroundView = backgroundView;
cell.textLabel.backgroundColor=[UIColor yellowColor];
}
This actually worked. I was able to achieve the yellow background, but the separator line is missing. Can some1 help me out ?
Is this the best way to do it? Or should i create an image for the cell and use it as the backgroundView?
Actually, none of the above answers are (I believe) correct. According to the doco:
Note: If you want to change the background color of a cell (by setting the background color of a cell via the backgroundColor property declared by UIView) you must do it in the tableView:willDisplayCell:forRowAtIndexPath: method of the delegate and not in tableView:cellForRowAtIndexPath: of the data source. Changes to the background colors of cells in a group-style table view has an effect in iOS 3.0 that is different than previous versions of the operating system. It now affects the area inside the rounded rectangle instead of the area outside of it.
So rather than call setBackgroundColor in tableView:cellForRowAtIndexPath:, you should be doing so in tableView:willDisplayCell:forRowAtIndexPath::
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
ShoppingList *object = (ShoppingList*)[self.fetchedResultsController objectAtIndexPath:indexPath];
if ([object isComplete] == YES) {
[cell setBackgroundColor:[UIColor greenColor]];
} else {
[cell setBackgroundColor:[UIColor clearColor]];
}
}
This I've found works perfectly, and fits in with the way the rest of the table cell rendering works. There's no need for any background views to be added or anything.
I'm actually surprised that worked to set the background color. The proper method to setting a UITableViewCell background is:
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
cell.backgroundColor = [UIColor yellowColor];
}
Also, I notice you don't have any reuse code in your cellForRowAtIndexPath method. I'm hoping you just didn't paste this in, but that's kind of a big no-no. Table View Programming Guide
Outdated.
Why are you creating a custom background view? If you only want to achieve a yellow color you can customize your color by using UIColor colorWithRed: green: blue: alpha: to create your own color and just add it to cell setBackgroundColor:UIColor. It seems like the seperator is being completely overwritten if you add a background view in grouped table view. If you still want to have a custom UIView as your background, I suggest adding a custom tableViewCell that looks like your seperator. You can regulate this in cellForRowAtIndexPath.
Working code for my first suggestion:
[cell setBackgroundColor:[UIColor yellowColor]];
Does this work for you to put inside "cellForRowAtIndexPath"?
....................
if (cell == nil) {
....................
cell.backgroundColor = [UIColor yellowColor];
....................
tableView.backgroundColor=[UIColor clearColor];
}
Set the separatorStyle of the tableview to UITableViewCellSeparatorStyleSingleLine.
Should be something like below.
myTableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;

Adding a subview larger than cellHeight to a UITableViewCell?

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.

UITableViewCell / UISegmentedControl border issue

I'm trying to get a UISegmentedControl in a group UITableViewCell much like in the wifi settings in the Setting Application. The problem I'm having is I'm getting a double border. I get one border for the UISegmentedControl and one for the UITableViewCell.
I'm guessing I need to remove the border from the UITableViewCell. How can I go about doing that?
I just noticed this is still getting answers. As it happens I've had to do this for another project and since I asked this question I've learned a lot more about iPhone dev. Here is how I solved it recently. It's all about making the frame the correct size. This should do it for a standard table.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"CellIdentifier"];
if(cell == nil)
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"CellIdentifier"] autorelease];
UISegmentedControl *segmentedControl = [[UISegmentedControl alloc] initWithFrame:CGRectMake(-1.0f, -1.0f, 302.0f, 46.0f)];
[cell.contentView addSubview:segmentedControl];
In the case of the Wi-Fi settings, I suspect what they've done is made the "Forget this Network" button, the "IP Address" label, and the "DHCP/BootP/Static" segmented control all part of the table's header view. If you need to do this in the middle of your table (as opposed to at the top or bottom, for which you'd use the tableHeaderView and tableFooterView properties respectively), I'd suggest using the delegate methods -tableView:viewForHeaderInSection: with -tableView:heightForHeaderInSection, or the corresponding Footer variants. With any of those, you'd set up a custom view for that "section" of your table view (using either a clear background color or [UIColor groupTableBackgroundColor]), containing a label and a segmented control arranged so that they match up with the rest of the table sections.
Using the technique in this post to remove the background opacity of the UITableViewCell worked more easily for me to get only the UISegmentedControl to show in the table row.
I've got slightly further with this. So far I've subclassed UITableViewCell. I created a nib with a UISegmentedControl in it and I set the UITableViewCell background alpha to 0. It still doesn't look quite right, but it's better than before.
My solution is to allow the segmented control to resize to fit, and to hide the table view's background in tableView:willDisplayCell:forRowAtIndexPath:.
This yields results identical to the "Settings.app > WiFi > Your Network > IP Address" Segmented Control without hard-coding any layout metrics:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
}
UISegmentedControl *control = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:#"One", #"Two", #"Three", nil]];
control.segmentedControlStyle = UISegmentedControlStylePlain;
control.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
control.frame = cell.contentView.bounds;
[cell.contentView addSubview:control];
[control release];
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
cell.backgroundView.alpha = 0.0;
}
The trick appears to be to size the UISegmentedControl to the size of the backgroundView of the control, not the contentView. I was able to do it programmatically by doing the following:
// Size to cover the entire background
self.contentView.frame = self.backgroundView.frame;
self.myControl.frame = self.contentView.bounds;
Note that if you are using an accessory, you need to account for the accessoryView as well.
The reason is that the view hierarchy is as follows:
self (the UITableViewCell or subclass)
backgroundView
contentView
(your controls go here)
accessoryView
In portrait layout, the backgroundView's frame is {{9, 0}, {302, 44}}, whereas the contentView's frame is slightly smaller, at {{10, 1}, {300, 42}}. This gives the cell its 1px "border" when the table style is grouped. You have to resize both the contentView and your control to get the appropriate size.
(NOTE: While Apple actually has several examples of a UISegmentedControl in the UICatalog sample code project in the SDK, they effectively "cheat" by using a UIViewController and setting the main view's background color to the table background color.)