UILabel shadow from custom cell selected color - iphone

I'm loading a custom nib file to customize the cells of a UITableView. The custom nib has a UILabel that is referenced from the main view by tag. I would like to know if it is possible to change the shadow color of the UILabel when the cell is selected to a different color so it doesn't look like in the screenshot.

I prefer to make the shadow color change inside the TableCell code to not pollute the delegate. You can override this method to handle it:
- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animate
{
UIColor * newShadow = highlighted ? [UIColor clearColor] : [UIColor whiteColor];
nameLabel.shadowColor = newShadow;
[super setHighlighted:highlighted animated:animate];
}

You could change the label's shadow color in -tableView:willSelectRowAtIndexPath: in the delegate. For instance:
-(NSIndexPath*)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell* cell = [tableView cellForRowAtIndexPath:indexPath];
cell.textLabel.shadowColor = [UIColor greenColor];
return indexPath;
}
-(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell* cell = [tableView cellForRowAtIndexPath:indexPath];
cell.textLabel.shadowColor = [UIColor redColor];
}

I had the same issue and none of the above solutions quite worked for me - I didn't want to subclass UITableViewCell and also had some tricky selected/highlighted state changes done programmatically, which did not play well with the solutions above.
MySolution:
What I did in the end is to use a second UILabel underneath the primary UILabel to act as a shadow. For that 'shadow' UILabel you can set the 'Highlighted Color' to 'Clear Color'.
Obviously you have to update the shadow label each time you update the primary label. Not a big price to pay in many cases.
Hope that helps!

The simple answer, at least for the example shown above, is to not display the shadow in the first place. Since you can't see the white-on-white anyway, set the shadowColor to -clearColor.
If you actually need a shadow though, overriding the -setHighlighted method is the best solution. It keeps the code with the cell, which I think is better than trying to handle it from the table view.

Related

Altering the background color of cell.accessoryView and cell.editingAccessoryView

Whenever I add an accessoryView to my UITableViewCell, it doesn't carry the background color across? I'm setting a UISwitch as my accessoryView, and the color I have set in the cell.backgroundColor property only effects the contentView and not the accessoryView.
I have tried everything to set them to the same value. I tried to set the cell.backgroundView.backgroundColor and the cell.accessoryView.backgroundColor properties to the color I want but nothing is working. I also tried creating a subview inside contentView, which solved the backgroundColor problem (by avoiding it), but it creates the problem, where the switch sits on top of the cell.textLabel when the text is too long.
Is there are way I can modify the background color of the accessoryView without creating a subview in contentView, or to alter the length of the cell.textLabel without subclassing UITableViewCell?
Upon reading the documentation (a novel idea), I found the article, "A Closer Look at Table-View Cells". It helped me understand the composition of the cells, and I found my answer...
cells look like this...
Since the cell.accessoryView is a sister view to cell.contentView I had to ask the cell.contentView for its superview, and then I was able to change the background color for both views at once. Here's what the code looks like...
// Cell Formatting
cell.contentView.superview.backgroundColor = [UIColor greenColor];
I know it's really simple, but I'm a newbie and it took me ages to slow down and read the doc. Hopefully, this helps some other folks out there!
- (void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
cell.backgroundColor = [UIColor yellowColor];
}
UIView *myView = [[UIView alloc] initWithFrame:cell.frame];
myView.backgroundColor = [UIColor colorWithRed:214.00/255.00 green:233.00/255.00 blue:247.00/255.00 alpha:1.0];
cell.backgroundView = myView;
[myView release];
If you want to blend the accessory view background color with the background color of the cell, in iOS8 and Swift this worked like a charm in the tableView(_, cellForRowAtIndexPath:) method:
let color = cell.contentView.backgroundColor
cell.backgroundColor = color
#Zak, first of all thanks for bringing to my attention the details of the cell layout. Very helpful!
I would just like to point out that the following code:
self.backgroundColor = [UIColor colorWithPatternImage: [UIImage imageNamed:#"cell_background.png"]];
worked for me. The result was a background image stretching over whole cell. AccessoryTypeView didn't cover it! Important part is to put this code into layoutSubviews method of your custom cell class and not into cellForRowAtIndexPath found in TableViewController class. In my case I defined a class CustomCell and inside of it I have defined labels, image views etc.
NOTE:The following code wasn't working:
cell.contentView.backgroundColor = [UIColor colorWithPatternImage: [UIImage imageNamed:#"cell_background.png"]];
when put inside tableView:(UITableView *)tableView cellForRowAtIndexPat method. It was giving me the background covering the cell but AccessoryTypeView was above it...

UITableViewCellSeparatorStyleNone does not hide blue separator line when selecting in UITableView

Before describing the problem, let me first point out that this is a distinct issue from this question.
The Problem
This screenshot was taken with a break set at tableView:didSelectRowAtIndexPath:, and as you can see in the simulator (far right of the image), there's a single-pixel blue line at the bottom of the selected cell. This is not the design asked for by the client, nor is it how this app used to behave: there should be no separator, even on selection.
How I Got Here
I'd initially designed this table view using custom UITableViewCell classes with corresponding nib (.xib) files and had no trouble with selections: the separator was hidden as desired. Predictably, scrolling was sluggish due to all the overhead from the view hierarchy, so I reworked the custom cells to use Loren Brichter's fast scrolling solution. Now scrolling is much faster, but I can't get rid of the separator for the life of me.
What I've tried
At the time of the screenshot above...
the table view has "Separator [None]" in IB.
the UIViewController that contains the table view has this line in viewDid Load: self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
As you can see in the screenshot, I inserted some unused lines to prove that separatorStyle is set as desired. Other testing confirms that tableView and self.tableView are equivalent pointers at that same breakpoint.
I've also tried setting tableView.separatorColor to black and to clear, all with the same result: the cells look right until a selection is made.
Manjunath: Here's the code I'm using to draw alternate backgrounds depending on whether the cell's been touched or not. You can see the difference—which is less subtle when animated—in the screenshot.
if(self.highlighted) {
textColor = [UIColor blackColor];
UIImage *bg = [UIImage imageNamed:#"image-cell-background_highlighted.png"];
[bg drawAtPoint:CGPointMake(0.0, 1.0)];
}
else {
UIImage *bg = [UIImage imageNamed:#"image-cell-background.png"];
[bg drawAtPoint:CGPointMake(0.0, 0.0)];
}
This gets called in UIImageCell.m in drawContentView:, a method inherited from Mr. Brichter's ABTableViewCell super class.
Chris,
Delving into ABTableViewCell, I see:
- (void)setFrame:(CGRect)f
{
[super setFrame:f];
CGRect b = [self bounds];
b.size.height -= 1; // leave room for the seperator line
[contentView setFrame:b];
}
Since the height of the cell is one pixel shorter than the actual cell, when the cell gets selected, that one-pixel line will bleed through in the color of the selection color. It may look like it's the separator, but it is actually the selection color.
To test, try to change that line above to be two pixels or more shorter to see what happens.
Update:
By making this change to the FastScrollingExample project's -rootViewController:
- (void)viewDidLoad
{
self.title = #"Fast Scrolling Example";
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
[super viewDidLoad];
}
and commenting out:
// if(self.selected)
// {
// backgroundColor = [UIColor clearColor];
// textColor = [UIColor whiteColor];
// }
//
in -drawContentView to mimic what would happen if you didn't have the selection color showing through, then I get a screen shot like this:
alt text http://files.me.com/mahboud/7k656q
Look familiar?
How would you get around this? If you don't need to select cells, then disable cell selection. Otherwise, if you are selecting cells, then you should make the rect larger so the default selection color doesn't show through when you paint with your own selection color in -drawConentRect.
Try this:
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = NSLocalizedString(#"Cell",#"");
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (nil == cell)
{
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
return cell;
}

How can I add a UIImage to a grouped UITableView?

I have a grouped UITableView that has 3 sections. I would like to show a UIImage with some text next to it (not a cell), but I am not sure how I can go about doing that? The image and text need to match the background of the pinstripes.
A UITableView has a backgroundView property that it uses to display the pinstripes for the grouped style. You can either replace the background view or add to it. If you replace it, you lose the pinstripes.
[myTable.backgroundImage addSubview:myImage];
[myTable.backgroundImage addSubview:myLabel];
You don't have to define a custom cell, you can use a standard UITableViewCell. It has properties for text and an image. Assign the image to the imageView property, put the text in the textLabel property.
Depending on the size of your image and your desired placement, you can use the imageView property of the UITableViewCell. Essentially, your cellForRowAtIndexPath will look like this:
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//Normal cell setup
cell.imageView.image = myImage;
cell.textLabel.text = imageDescription;
return cell;
}
That will create a cell with an image at the left edge with text after it in the middle/right edge
[self.tableView addSubview:myImageView];
[Self.tableView sendSubviewToBack:myImageView];
Or
self.tableView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:"myimage.png"]];
Use Photoshop to place something on top of an image of the pinstripes.

How can I set the background color of a cell in UITableView on iphone?

How can I set the background color of a cell in UITableView?
Thanks.
I know this is an old post, but I am sure some people are still looking for help. You can use this to set the background color of an individiual cell, which works at first:
-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath {
[cell setBackgroundColor:[UIColor lightGrayColor]];
However, once you start scrolling, the iphone will reuse cells, which jumbles different background colors (if you are trying to alternate them). You need to invoke the tableView:willDisplayCell:forRowAtIndexPath. This way, the background color gets set before the reuse identfier is loaded. You can do it like this:
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
cell.backgroundColor = ([indexPath row]%2)?[UIColor lightGrayColor]:[UIColor whiteColor];
}
The last line is just a condensed if/else statement. Good luck!
Update
Apparently the existing UITableViewCell framework makes it very difficult to change the background color of a cell and have it work well through all its state changes (editing mode, etc.).
A solution has been posted at this SO question, and it's being billed on several forums as "the only solution approved by Apple engineers." It involves subclassing UITableViewCell and adding a custom view for the subclassed cell's backgroundView property.
Original post - this solution doesn't work fully, but may still be useful in some situations
If you already have the UITableViewCell object, just alter its contentView's backgroundColor property.
If you need to create UITableViewCells with a custom background color, the process is a bit longer. First, you'll want to create a data source for your UITableView - this can be any object that implements the UITableViewDataSource protocol.
In that object, you need to implement the tableView:cellForRowAtIndexPath: method, which returns a UITableViewCell when given an NSIndexPath for the location of the cell within the table. When you create that cell, you'll want to change the backgroundColor property of its contentView.
Don't forget to set the dataSource property of the UITableView to your data source object.
For more info, you can read these API docs:
UITableViewDataSource - tableView:cellForRowAtIndexPath
UITableViewCell - contentView
UIView - backgroundColor
UITableView - dataSource
Note that registration as an Apple developer is required for all three of these links.
The backgroundView is all the way on the bottom. It's the one that shows the rounded corners and the edges. What you want is the contentView which is on top of the backgroundView. It covers the usually white area of the cell.
The version I wrote will work in iPhone 3.0 or higher and fallback to a white background otherwise.
In your viewDidLoad method of the UITableViewController we add the following:
self.view.backgroundColor=[UIColor clearColor];
// Also consider adding this line below:
//self.tableView.separatorColor=[UIColor clearColor];
When you are creating your cells (in my code this is my tableView:cellForRowAtIndexPath:) add the following code:
cell.backgroundColor=[UIColor colorWithPatternImage:[UIImage imageNamed:#"code_bg.png"]];
float version = [[[UIDevice currentDevice] systemVersion] floatValue];
if (version >= 3.0)
{
[[cell textLabel] setBackgroundColor:[UIColor clearColor]];
}
This works perfectly for me:
NSEnumerator *enumerator = [cell.subviews objectEnumerator];
id anObject;
while (anObject = [enumerator nextObject]) {
if( [anObject isKindOfClass: [ UIView class] ] )
((UIView*)anObject).backgroundColor = [UIColor lightGrayColor];
}
You may set the backgroundColor of the backgroundView. If the backgroundView does not exists, you can create one for it.
if (!tableView.backgroundView) {
tableView.backgroundView = [[UIView alloc] initWithFrame:tableView.bounds];
}
tableView.backgroundView.backgroundColor = [UIColor theMostFancyColorInTheUniverse];
If you want to set the background of a cell to an image then use this code:
// Assign our own background image for the cell
UIImage *background = [UIImage imageNamed:#"image.png"];
UIImageView *cellBackgroundView = [[UIImageView alloc] initWithImage:background];
cellBackgroundView.image = background;
cell.backgroundView = cellBackgroundView;

After moving a UITableView row, then selecting it, it only turns blue at the edges

I have a UITableView with reorderable rows and I'm using the standard UITableViewCell.text property to display text. When I tap Edit, move a row, tap Done, then tap the row, the built-in UILabel turns completely white (text and background) and opaque, and the blue shade to the cell doesn't show behind it. What gives? Is there something I should be doing that I'm not? I have a hacky fix, but I want the real McCoy.
Here is how to reproduce it:
Starting with the standard "Navigation-Based Application" template in the iPhone OS 2.2.1 SDK:
Open RootViewController.m
Uncomment viewDidLoad, and enable the Edit button:
- (void)viewDidLoad {
[super viewDidLoad];
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
Specify that the table has a few cells:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 4;
}
In tableView:cellForRowAtIndexPath:, add a line to set the text property of a cell, and therefore to use the built-in UILabel subview:
// Set up the cell...
cell.text = #"Test";
To enable reordering, uncomment tableView:moveRowAtIndexPath:toIndexPath:. The default implementation is blank, which is fine in this case since the template doesn't include a data model.
Configure the project for the Simulator, OS 2.2.1, Build and Go. When the app comes up, tap Edit, then slide any row to a new position, tap Done, and then tap each row one at a time. Usually a tap will select a row, turn it blue, and turn its text white. But a tap on the row that you just moved does that and leaves the UILabel's background color as white. The result is a confusing white open space with blue strips on the edges. Oddly enough, after the first bogus tap, another tap appears to correct the problem.
So far I have found a hack that fixes it, but I'm not happy with it. It works by ensuring that the built-in UILabel is non-opaque and that it has no background color, immediately upon selection.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// hacky bugfix: when a row is reordered and then selected, the UILabel displays all crappy
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
for (UIView *view in cell.contentView.subviews) {
if ([[view class] isSubclassOfClass:[UILabel class]]) {
((UILabel *) view).backgroundColor = nil;
view.opaque = NO;
}
}
// regular stuff: only flash the selection, don't leave it blue forever
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
This appears to work, but I don't expect it to be a good idea forever. What is the Right Way to fix this?
This looks like a bug in UITableView's rendering, and you should file a Radar bug report on it. It's like the cells don't get refreshed properly after the move.
One way to work around this for now is to not use the built-in label, but roll your own in the cell:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
CGRect frame = cell.contentView.bounds;
frame.origin.x = frame.origin.x + 10.0f;
UILabel *textLabel = [[UILabel alloc] initWithFrame:frame];
[textLabel setAutoresizingMask:UIViewAutoresizingFlexibleRightMargin];
textLabel.tag = 1;
textLabel.textAlignment = UITextAlignmentLeft;
textLabel.backgroundColor = [UIColor clearColor];
textLabel.textColor = [UIColor blackColor];
textLabel.font = [UIFont boldSystemFontOfSize:20.0];
textLabel.numberOfLines = 1;
textLabel.highlightedTextColor = [UIColor whiteColor];
[cell.contentView addSubview:textLabel];
[textLabel release];
}
UILabel *textLabel = (UILabel *)[cell viewWithTag:1];
textLabel.text = #"Test";
return cell;
}
I tried this, and it doesn't exhibit the same sort of white blank rectangle you see with the built-in label. However, adding another non-opaque view to the table cell might not be the best for overall rendering performance.
I don't know how major of a glitch this is, because Apple doesn't want you to persist a selection highlight on a table row (they've been enforcing this lately during the review process). You're supposed to place a checkmark or move on to the next level in the navigation hierarchy with a selection, at which point this white box would only be on the screen for a fraction of a second.
The trick in the solution from Brad appears to be:
textLabel.backgroundColor = [UIColor clearColor];
If you leave the background as the default you still get the problem even when you roll your own cells UITableViewCells.
The reason I left it as the default is because the documentation says it is less computationally costly to use opaque backgrounds. Ideally I wouldn't want to use [UIColor clearColor] to fix this bug.
Maybe a completely custom painted cell would somehow fix it. I haven't tried those before though.
Does anyone else have a solution for this?
Thanks for the info, I was searching how to erase the background color from a UILabel.
I used the following line:
textLabel.backgroundColor = [UIColor clearColor];
and worked perfectly!!!
thanks
Alejandra :)
Selections aren't meant to be shown for extended periods! (We got knocked on this for several of our apps)
??? That means Apple would not approve their own Calendar app on iPhone! When you go to edit the start and end times of the event, the start time is selected indefinitely, it only changes once the user taps to the next field.