iphone - Draw a line in UITableViewCell when background view is set - iphone

I have written drawRect as follows.
-(void)drawRect:(CGRect)rect
{
[super drawRect:rect];
CGContextRef cxt = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(cxt, 2.0);
CGContextSetStrokeColorWithColor(cxt, [UIColor redColor].CGColor);
CGContextMoveToPoint(cxt, 250.0 , 0.0);
CGContextAddLineToPoint(cxt, 250.0, 50.0);
CGContextStrokePath(cxt);
}
It draws red line. But When I set background view to cell line disappears. I have set view as follow.
UIView *view = [[UIView alloc] initWithFrame:cell.frame];
view.backgroundColor = [UIColor grayColor];
cell.backgroundView = view;
What is the problem? How backgrond view hides the line?
Please help

I guess you are in a UITableViewCell?
You should not overwrite drawRect of the cell itself. Instead put your drawing code in a custom backgroundView, or in a custom view within the contentView hierarchy. (depends on your planned result, probably backgroundView is correct for you)
The line is gone, because the backgroundView is a subview of the TableViewCell, so it is on top of the cell itself. (You can see this, if you use [UIColor colorWithWhite:0.0 alpha:0.5] as backgroundColor of your backgroundView.) There are many views on a UITableViewCell, it looks somewhat like this:
UITableViewCell
> BackgroundView
> (EditControl)
> ContentView
> (AccessoryView)

Agree with jaydee3 that you should not override UITableViewCell's drawRect, instead make your custom view class extending from UIView, extend drawRect there and do all the framing and coloring thing there, then set an instance of that view as your cell background view, its much better approach

When u already drawn background of that,u can't set background Color or image again for that cell.It overlays on what u drawn.

Related

drawRect doesn't reflect changes made to layer

The UITableView I am using has a custom UItableViewCell. This custom cell has a subview (an UIView subclass) to it. I use the drawRect of the custom UIView subclass to place all the text to be displayed by the cell.
And in the drawRect (of UIView subclass) I do the following
/*
// This piece of code is called when setNeedsDisplay is called
*/
- (void)drawRect:(CGRect)rect
{
self.layer.cornerRadius = 10.0f;
self.layer.backgroundColor = [[UIColor orangeColor] CGColor];
self.layer.borderColor = [[UIColor lightGrayColor] CGColor];
self.layer.borderWidth = 3.0f;
}
However my custom cell is a black square like this
But I do see the intended behavior if I select the row. Like shown below
Whats going on ?
Your drawRect: method does not draw anything; the code that you put in there belongs in your initWithFrame: implementation.
You should manipulate the layer configuration in the initializer; in your drawRect: you should call functions of your CGContextRef based on the state of the view. For example, to draw some text you would use CGContextShowTextAtPoint, to draw some lines you would use CGContextAddLineToPoint, and so on.
See this question for information on the relationship between drawRect: and the CALayer of your UIView.
Try to set self.layer.masksToBounds = YES and (maybe) self.opaque = NO during your UIView's (the one where drawRect is overridden) initialization. (see this question)
Try to disable the selection highlight of the cell by using
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
You are doing one mistake:
Please go to the view in side the UItableViewCell and check the background color it may be black or something others, Reset it to clear color then check your result,

Changing color of small portion of UIView?

I have a UIView whose color is black and opacity is 0.9 or something like that. What I want to do is to fill the UIView with black portion, but a specified rectangular area should not get black. i.e. that particular rectangular area remains with clear color...
Any kind of help will be appreciated.
regards,
Imran
You can subclass UIView and override - (void)drawRect:(CGRect)rect
And do something of the following (untested, but used something similar myself);
- (void)drawRect:(CGRect)rect {
// fill the whole UIView with a color
[[UIColor colorWithRed:1 green:1 blue:1 0.9] setFill];
UIRectFill( rect );
// draw a rect
CGRect rectIntersection = CGRectIntersection(theRectIWantToDrawIn, rect);
[[UIColor clearColor] setFill];
UIRectFill( rectIntersection );
}
The code above draws a black view with a simulated clearColor hole in it at a certain position. You could, of course, alter this behavior to your liking.
This is quite fast.
UPDATE: Do note that I set the UIView on which I want to draw the rect to UIClear color (I added it to a xib and set those properties there) and unchecked 'Opaque'. That should make the hole see-through.
UPDATE 2: My answer was based on this answer (credit where credit is due): iPhone - Draw transparent rectangle on UIView to reveal view beneath
Add another view (subview) to that area. And set its to your desired color. Thats the easy solution with your current requirements.
Or you can use some quartz core functions.
You can create a small UIView in the main view by custom and set background clear color
UIView *View1 = [[UIView alloc] initWithFrame:CGRectMake(128.0f, 50.0f, 34.0f, 34.0f)];
[View1 setBackgroundColor:[UIColor clearColor]];
[self.view addSubview:View1];
[View1 release];

selectedBackgroundView on UITableViewCell gets applied to all views in cell

I have a table cell being displayed that shows a users image, name and some text. The user's image is 50x50, but I want a border around it so I set the view to center the image and set the frame to 52x52 and then set the background color of that view to my border color. That shows a 1 pixel border around the image.
I also want to show a 30 pixel wide border on the right of the cell when the cell is selected. I've tried to do that by creating a UIView the size of the cell's frame, then adding a subview to that view with a UIView the width and background color I would like. I then set that view to the selectedBackgroundView of the cell.
The problem here is that the cell's selectedBackgroundView gets applied to the background of all views inside the cell. So when I select a cell, the images "border" gets set to the cell's selected background color, the other 30px "border" I'm adding gets changed to that background color also.
Code inside my cellForRowAtIndexPath:
cell = (UserCellView *) currentObject;
UIView *c = [[UIView alloc ] initWithFrame:CGRectMake(0, 0, 30, cell.frame.size.height)];
c.backgroundColor = [[UIColor alloc] initWithRed:64/255.0 green:64/255.0 blue:64/255.0 alpha:1.0];
UIView *v = [[UIView alloc ] initWithFrame:cell.frame];
v.backgroundColor = [[UIColor alloc] initWithRed:35/255.0 green:35/255.0 blue:35/255.0 alpha:1.0];
[v addSubview:c];
cell.selectedBackgroundView = v;
[c release];
[v release];
I'll assume that you haven't actually tested what's going on to form your analysis that it "gets applied to the background of all views inside the cell".
I did something like this:
#interface TestView : UIView {
}
#end
#implementation TestView
-(void)setBackgroundColor:(UIColor*)c {
// Breakpoint here.
NSLog("setBackgroundColor: %#",c);
[super setBackgroundColor:c];
}
#end
...
UIView * v = [[[UIView alloc] initWithFrame:(CGRect){{0,0},{20,20}}] autorelease];
v.backgroundColor = [UIColor magentaColor];
UIView * v2 = [[[TestView alloc] initWithFrame:(CGRect){{5,5},{10,10}}] autorelease];
v2.backgroundColor = [UIColor yellowColor];
[v addSubview:v2];
cell.selectedBackgroundView = v;
The end result is that -setBackgroundColor: is called from -[UITableViewCell _setOpaque:forSubview:] when the view is selected, with something like UIDeviceWhiteColorSpace 0 0 (i.e. [UIColor clearColor]).
Or, in other words, the background colour of some of the subviews are set to [UIColor clearColor] while the cell is selected, allowing selectedBackgroundView to show through. I think this happens because a common optimization is to give textLabel/detailTextLabel the table's background colour (e.g. white) so it draws faster, but this means the background colour has to be reset when the cell is selected.
The easiest fix is to use an image instead: a 1-by-1-pixel image of the correct colour in a UIImageView will work, if a bit messy. (I had this problem when drawing custom separator lines with 1-pixel-high UIViews, so I just included the separator into the background image.)
An alternative fix is to use a CALayer instead: Add a 52x52 sublayer to the UIImageView's layer, and set the sublayer's background colour. I'm pretty sure UITableViewCell simply walks the view hierarchy, so it should ignore custom layers. (The big disadvantage with layers is that they don't auto-size, which made them unsuitable for my purposes, and means the 30px right border won't auto-size.)
A workaround is to subclass the relevant views and ignore -setBackgroundColor: if it's equal to [UIColor clearColor].
A simple but obnoxious-to-maintain solution is to override setSelected:animated: and setHighlighted:animated: with implementations re-setting the various backgrounds you want. Something along the lines of:
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
self.childView.backgroundColor = [UIColor blueColor]; // whichever you want
}
First add this to your file
#import <QuartzCore/QuartzCore.h>
Then turn your view into an image with...
UIView *rowView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 1.0, 60.0)];
rowView.backgroundColor = [UIColor colorWithRed:35/255.0 green:35/255.0 blue:35/255.0 alpha:1.0];
UIGraphicsBeginImageContext(rowView.bounds.size);
[rowView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *yourImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Then instead of adding a UIView to your cell, just add a UIImageView with "yourImage".
A simple solution if the affected view can be a custom subclass is to override -setBackgroundColor:
- (void)setBackgroundColor:(UIColor *)color
{
// Ignore requests and do nothing
}
Thus UITableViewCell's attempt to set the colour will go ignored. Code in the custom view which really does want to set the background colour needs to call super:
- (void)setColor:(UIColor *)color
{
[super setBackgroundColor:color];
}
(or could probably message the underlying CALayer directly)
you will need to customize the contentView of the cells and handle the delegate tableView:cellForRowAtIndexPath
See Posting Here

How do I fill the background color of a UITableViewCell?

How do I fill the background color of a UITableViewCell? I tried this code but it didn't work.
cell.backgroundColor = [UIColor redColor];
Try setting a backgroundView for UITableViewCell :
UIView *bgView = [[UIView alloc] init];
bgView.backgroundColor = [UIColor redColor];
cell.backgroundView = bgView;
// release object
[bgView release];
You can change the selection background view of UITableViewCell the same way.
cell.selectedBackgroundView = bgView;
Setting the background color though UITableViewCell's backgroundColor property only works in a Grouped table view. So if your table view is in the Plain style then it won't work.
You can of course set the background color of the UITableView's contentView. But then you probably have to do some additional work as the other subview (text labels and accessory views) have their own idea of background colors.
Take a look at the following snippet from the UITableViewCell documentation.
http://developer.apple.com/library/ios/#documentation/uikit/reference/UITableViewCell_Class/Reference/Reference.html
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.
That should solve your problem.

Light gray background in "bounce area" of a UITableView

Apple's iPhone apps such as Music and Contants use a search bar in a UITableView. When you scroll down so that the search bar moves down, the empty space above the scroll view's contents has a light gray background color (see screenshot).
(Notice that the search bar has a slightly darker edge line at its top. This is not there for the default UISearchBar, but subclassing should take care of that.)
I tried setting the background color of the UITableView, but that affects the rows as well. Does anyone know how to achieve this effect? Am I going to have to override implement drawRect: or is there a built in way?
Setting transparencies is bad for performance. What you want is the gray area above the search bar, but it should still be white beyond the end of the list.
You can add a subview to your UITableView that lives above the content instead.
CGRect frame = self.list.bounds;
frame.origin.y = -frame.size.height;
UIView* grayView = [[UIView alloc] initWithFrame:frame];
grayView.backgroundColor = [UIColor grayColor];
[self.listView addSubview:grayView];
[grayView release];
You could add more fancy stuff to the view if you like, perhaps a fade, or a divider line without subclassing UISearchBar.
This is one of my very favorite tricks.
UIView *topview = [[[UIView alloc] initWithFrame:CGRectMake(0,-480,320,480)] autorelease];
topview.backgroundColor = [UIColor colorWithRed:226.0/255.0 green:231.0/255.0 blue:238.0/255.0 alpha:1];
[self.tableView addSubview:topview];
Basically you're creating a big view the size of the screen and placing it "above" the content area. You'll never be able to scroll up past it.
And don't worry about the memory impact of a UIView that's 320x480 pixels, it won't consume any significant memory because the CALayer doesn't have any meaningful content.
NOTE: Why is this answer relevant when the "accepted" answer is so much simpler? Why not just set the backgroundView on the table view? It's because, in the case of the Contacts app as shown in the original question, the area "above" the table view has a different background color (light blue) than the area "below" the table view (white). This technique allows you to have two different colors above and below the table view, which cannot be accomplished by a simple background.
EDIT 1/2018: As Tom in the comments pointed out, this answer is quite old and assumes that all iOS devices have the same screen size (seems crazy but it was the case in 2009 when I answered this). The concept I present here still works, but you should use UIScreen.main.bounds to figure out the actual screen size, or you could get into some fancy auto layout stuff (suggestions welcome). I don't recommend using tableView.bounds as in another answer, because typically in viewDidLoad the size of your views is not necessarily the size that they will become after the controller resizes them. Sometimes they start out as 0x0!
To extend on HusseinB's suggestion:
Swift 3
let bgView = UIView()
bgView.backgroundColor = UIColor.white
self.tableView.backgroundView = bgView
Objective C
UIView *bgView = [UIView new];
bgView.backgroundColor = [UIColor whiteColor];
[self.tableView setBackgroundView:bgView];
As of iOS 7, you can tinker this by changing the tableview background view.
[self.tableView setBackgroundView:view];
make the view's background colour the same as your parent view colour.
This code works in Swift fot UITableView:
var frame = self.tableView.bounds
frame.origin.y = -frame.size.height
frame.size.height = frame.size.height
frame.size.width = UIScreen.mainScreen().bounds.size.width
let blueView = UIView(frame: frame)
blueView.backgroundColor = UIColor.headerBlueColor()
self.tableView.addSubview(blueView)
In Swift (tested on iOS9)
let backView = UIView(frame: self.tableView.bounds)
backView.backgroundColor = UIColor.clearColor() // or whatever color
self.tableView.backgroundView = backView
EASIEST SOLUTION
The easiest way to create different colors in the bottom and in the top of a bouncing area of a table view is to set the key tableHeaderBackgroundColor of the table view. Doing this way you set the top color. I'm not sure, but maybe there is another key for the footer, take a look. If you don't find anything, you just have to set the background of the table view with the color that you want to show in the bottom. Above you can see an example code:
self.table.setValue(UIColor.blue , forKey: "tableHeaderBackgroundColor")
Hope it help you. If yes, let other people know about this easy way giving an up in the answer :)
I've only found one way to do this. You have to set the backgroundColor of the UITableView to be transparent, set the backgroundColor of the cell's contentView to whatever colour you want the actual cells to be, then crucially you have to get the light grey colour to appear behind the UITableView. That last step you can do by either setting the backgroundColour of the UIWindow, or of whatever is containing or your tableViewController.
So, assuming you have a view controller that is derived from UITableViewController, insert these lines in the -(void)viewDidLoad method:-
// sets the background of the table to be transparent
self.tableView.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.0];
// assuming we are inside a navigation or tab controller, set the background
self.parentViewController.view.backgroundColor = [UIColor lightGrayColor];
Then inside the part of tableView:cellForRowAtIndexPath: that creates new cells, add:-
// set an opaque background for the cells
cell.contentView.backgroundColor = [UIColor whiteColor];
I just encountered this issue myself and found a solution.
Cause
I used Spark Inspector to examine the layout of the table view - which really helped.
Thing is, that in this scenario the UITableView has 3 subviews:
UITableViewWrapperView
UIView - With backgroundColor set to light gray color
UISearchBar
While you swipe the tableview content downwards, the second subview height is dynamically increasing to fill the space between the UITableViewWrapperView and the UITableView frame origin.
Solution
Setting the backgroundColor or backgroundView property won't effect the 2nd subview.
What you need to do is find the second view and change its color, like so:
if (_tableView.subviews.count > 1) {
_tableView.subviews[1].backgroundColor = THE_TARGET_COLOR;
}
In my case I needed all views to be white so I used the following which is less prone to future changes of UITableView view hierarchy by Apple:
for (UIView *subview in _tableView.subviews) {
subview.backgroundColor = [UIColor whiteColor];
}
I will give you the best way to do this.
First set the background color of the table view to the one you want in interface builder.
Then respond to the UITableView delegate tableView:willDisplayCell:ForIndexPath: method
like this
- (void)tableView:(UITableView*)tableView willDisplayCell:(UITableViewCelll*)cell forIndexPath:(NSINdexPath*)indexPath
{
[cell setBackgroundColor:[UIColor whiteColor]];
}
Another Method is :
in ViewDidLoad method (or anywhere you like) set the tableView background color to clear color like this:
self.tableView.backgroundColor = [UIColor clearColor];
and then set the superview color to white
self.tableView.superview.backgroundColor = [UIColor whiteColor];
I don't think you want to override drawRect. Most likely what you're seeing is the background colour of another view or the window, which lies "behind" (i.e. is a superview of) the table view. There's usually a fairly complex layers of UIViews in Apple's UI widgets. Explore the view hierarchy in GDB, look at [myView superview] and then [someSuperView subviews] and try manipulating their BG colours in the debugger to see if you can find which one it is. However, if you implement a fix this way, be warned that it may not be future compatible.
You might also try setting the BG colour of one of the views behind the tableview in Interface Builder (or of the window itself).
If you are using a tableviewcell, you can set the view background to be opaque white. Then use
self.tableView.backgroundColor = [UIColor grayColor];
in the view did load method.
I'm sure that that is [UITableView backgroundColor].
You have affected rows, because rows have backgroundColor == clear (or semi-transparent).
So, If you'll make rows non-trasparent, all will work fine.
This will be solution.
I followed the tip outlined by Peylow, for a UITableView, by simply adding a subview. My only change from the code was to grab a color a bit closer to the one used in Apple apps, plus I got it a bit closer to Apple's look of having a line above the UISearchbar by reducing the frame origin y coordinate by one pixel:
frame.origin.y = -frame.size.height - 1
For anyone who's wondering how to do the same for the bottom bounce area:
First add a subview with your desired background color to your table view's background view:
self.bottomView = [[UIView alloc] initWithFrame:CGRectOffset(self.tableView.frame, 0, self.tableView.frame.size.height)];
self.bottomView.backgroundColor = whateverColorYouLike;
[self.tableView.backgroundView addSubview:self.bottomView];
And then in your table view's delegate:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGRect frame = self.bottomView.frame;
frame.origin.y = self.tableView.contentSize.height - self.tableView.contentOffset.y;
self.bottomView.frame = frame;
}
In my case the solution was to create a headerview for the table and assign a color, it solved the black background in bounce area in my apps when in dark mode. I did the same to its tableFooterView.
table.tableHeaderView = UIView()
table.tableHeaderView!.backgroundColor = UIColor.white