UITableViewCell background color problem - objective-c

I subclassed UITableViewCell to set a cell background color to a color I need:
.h
#interface DataViewCustomCell : UITableViewCell {
UIColor* cellColor;
UIColor* standardColor;
}
- (void) setCellColor: (UIColor*)color;
#end
.m
#implementation DataViewCustomCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
}
return self;
}
- (void) setCellColor: (UIColor*)color
{
cellColor = color;
}
- (void) spreadBackgroundColor: (UIView*)that withColor: (UIColor*)bkColor
{
NSEnumerator *enumerator = [that.subviews objectEnumerator];
id anObject;
while (anObject = [enumerator nextObject]) {
if([anObject isKindOfClass: [UIView class]])
{
((UIView*)anObject).backgroundColor = bkColor;
[self spreadBackgroundColor:anObject withColor:bkColor];
}
}
}
- (void) layoutSubviews {
[super layoutSubviews]; // layouts the cell as UITableViewCellStyleValue2 would normally look like
if(!self.selected && NULL != cellColor)
{
[self spreadBackgroundColor:self withColor:cellColor];
}
}
- (void)dealloc
{
[super dealloc];
}
#end
When I call setCellColor with the color I want, all goes well, but when I haven't found a way to set the original color back: when I set [UIColor clearColor] with UITableViewStylePlain style the results is not good-looking.
How can I achieve a good result, without a missing cell separator line?

I was having a similar problem and found edo42's answer. However I was then having an issue with the background behind the text in the cell not displaying the background color I set. I believe this is due to the style: UITableViewCellStyleSubtitle.
In case others stumble upon this question, I believe the better solution for this is found in this question:
BackgroundColor of UITableViewCellStyleSubtitle labels?
BackgroundColor of UITableViewCellStyleSubtitle labels?
Answer reprinted here:
To change the background color of the table view cell, you'll need to set it in tableView:willDisplayCell:forRowAtIndexPath: rather than tableView:cellForRowAtIndexPath: otherwise it won't have any effect, for example:
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
cell.backgroundColor = [UIColor whiteColor];
}

Finally, I solved it by myself. I used the following code in - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath instead of subclassing:
UIView *bg = [[UIView alloc] initWithFrame:cell.frame];
bg.backgroundColor = [UIColor greenColor]; //The color you want
cell.backgroundView = bg;
cell.textLabel.backgroundColor = bg.backgroundColor;
[bg release];

why don't before you set the new cell color, capture the old cell color in a UIColor variable.
try
UIColor *originalColor = anObject.backgroundColor;
then later when you want to change back to that just change the cell color to originalColor.

I find it best to adjust the color from within the custom cell's .m file, rather than the tableViewController. Seems more intuitive, and it's slightly easier. Just adjust the color as necessary in the methods:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
and
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
Note: make sure you call the super of these methods too at the end of the call, e.g. if you want to make your cell green on touch:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
self.backgroundColor = [UIColor greenColor];
[super touchesBegan:touches withEvent:event];
}
Also, in my experience, it's not worth adjusting the color in touchesEnded, because your cell often won't adjust in-time for quick selections by the user.

you should always provide changes for cell in willDisplayCell:forRowAtIndex instead of cellForRowAtIndex method , as per Apple Documentation
This Works !!

Change the color in the following delegate method:
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
if (...){
cell.backgroundColor = [UIColor blueColor];
} else {
cell.backgroundColor = [UIColor whiteColor];
}
}

Related

UITableViewCell setSelected method not getting called

I am on iOS7 and have a UITableViewCell subclass for my UITableView with static cells. I am overriding the setSelected method in the implementation.
For some reason, the method only gets called when the table loads but doesn't get called when the cell is actually tapped and selected.
What am I doing wrong here? How do I get it to work?
#implementation StudentMenuMultipleOptionsTableViewCell
- (void)setSelected:(BOOL)selected {
[super setSelected:selected];
if (selected) {
UIView *view = [UIView new];
view.backgroundColor = [UIColor colorWithRed:0.542 green:0.788 blue:0.060 alpha:1.000];
self.selectedBackgroundView = view;
}
else {
for (UIView *view in self.subviews) {
if ([view isKindOfClass:[BlackBackgroundSelectedButton class]]) {
BlackBackgroundSelectedButton *button = (BlackBackgroundSelectedButton *)view;
button.selected = NO;
[button setWhite];
}
}
}
}
#end
The problem was that I was using the setSelected method. The method that needs to be used for the newer iOS versions is:
- (void)setSelected:(BOOL)selected animated:(BOOL)animated;

cellForRowAtIndexPath does not fire. What am i missing?

I am trying to achieve this:
but i get this:
I have a view cotroller with a view table on it
This is the interface:
#interface LoginViewController : UIViewController<UITableViewDataSource, UITableViewDelegate>
#property (weak, nonatomic) IBOutlet UITableView *tblCredentials;
#end
This is the implementation:
#interface LoginViewController ()
#end
#implementation LoginViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
-(void)viewWillAppear:(BOOL)animated
{
self.tblCredentials.delegate=self;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 2;
}
// Row display. Implementers should *always* try to reuse cells by setting each cell's reuseIdentifier and querying for available reusable cells with dequeueReusableCellWithIdentifier:
// Cell gets various attributes set automatically based on table (separators) and data source (accessory views, editing controls)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
UITextField *textField = [[UITextField alloc] init];
textField.enablesReturnKeyAutomatically = YES;
textField.autocorrectionType = UITextAutocorrectionTypeNo;
textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
CGRect cellBounds = cell.bounds;
CGFloat textFieldBorder = 10.f;
CGRect aRect = CGRectMake(textFieldBorder, 9.f, CGRectGetWidth(cellBounds)-(2*textFieldBorder), 31.f );
textField.frame = aRect;
if(indexPath.row==0)
{
textField.placeholder = #"Username";
textField.returnKeyType = UIReturnKeyNext;
textField.autocapitalizationType = UITextAutocapitalizationTypeWords;
}
else
{
textField.placeholder = #"Password";
textField.returnKeyType = UIReturnKeyDone;
textField.secureTextEntry = YES;
}
[cell.contentView addSubview:textField];
return cell;
}
#end
I put a breakpoint on the in the cellForRowAtIndexPath and it doesn't stop there, so those text fields don't get rendered.
What am I missing?
PS: Is this a bad approach to achieve the goal? (those two grouped text fields)
LE: I am using stroyboard with no xib files
In viewDidLoad, you must set the delegate and call [self.tblCredentials reloadData] in order for the table view to actually "load its data"
You need to create a Custom Table View cell. have a look at this github link.
You're setting the delegate of the table view, but not the datasource, which is where the number of rows etc. comes from.
You're also setting the delegate a bit late in the cycle. Since this is in a xib, why not set the delegate and datasource in the xib instead of in code? If you declare that your view controller conforms to the delegate and data source properties in the header, you will be able to make the connection in IB. If you insist on setting it in code, it should be in viewDidLoad.
Set delegate and dataSource in -viewDidLoad and put [self.tblCredentials reloadData] in -viewWillAppear:.
- (void)viewDidLoad
{
[super viewDidLoad];
self.tblCredentials.delegate=self;
self.tblCredentials.dataSource=self;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated]; // BTW, it's better to call super's -viewWillAppear: here, according to apple's documentation.
[self.tblCredentials reloadData];
}

Made Custom UITableViewCell -- Now UITableView Is Not Scrolling

Created an empty xib.
Created a class that overrides UITableViewCell (UserCell).
Put in a custom pieces of logic that simply format some strings for display and connected the two labels in IB.
My view controller owns an UITableView. I've set the view controller as the data source.
Here's how I go about populating it with my custom cells.
(did: http://www.highoncoding.com/Videos/823_Creating_a_Custom_UITableViewCell.aspx)
-(UserCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UserCell* cell = [tableView dequeueReusableCellWithIdentifier:#"Users Table"];
if (!cell) {
NSArray* topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"UserCell" owner:nil options:nil];
for (id currentObject in topLevelObjects) {
if ([currentObject isKindOfClass:[UserCell class]]) {
cell = (UserCell*) currentObject;
break;
}
}
}
[cell setUserNameText:[[[_userDataManager getUsers] objectAtIndex:indexPath.row] name ]];
[cell setNumberLabelText:indexPath.row];
return cell;
}
For some reason, I am not able to scroll. In viewDidLoad: I'm printing scrollEnabled on my table view. It's "1".
Haven't had this trouble until I tried putting in a custom UITableViewCell. :(
Thanks SO for any advice! :D
EDIT: Custom cell code.
#import "UserCell.h"
#implementation UserCell
#synthesize textLabel, numberLabel;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
-(void) setNumberLabelText:(NSInteger)text {
self.numberLabel.text = [[NSString alloc] initWithFormat:#"# %d", text];
}
-(void) setUserNameText:(NSString*)text {
self.userNameLabel.text = text;
}
#end
Closing this question as answered (I'm a derp sometimes)
I haven't done much iOS stuff using a trackpad. Seems like I was expecting two finger scrolling to "scroll" on the simulator. It does not!
A heads up for anyone else having this issue.

Sizing a Custom UITableViewCell and included UIImageView based on Image Size

I am trying to customize the UITableViewCell below for an iPhone app in a grouped table view. What I would like to do is have the image width take up the whole cell minus padding (280) and the height variable based on the image size.
Currently I am using SDWebImage to asynchronously download remote images. This may not be the correct thing to do in this case. I am also having trouble figuring out how to give the custom cell the image on initialization. The image URL is stored in self.beerPhoto in the DetailViewController.
I have searched for this a number of ways and have not found exactly what I am looking for. The closest was this: How to scale a UIImageView proportionally, but this method seems to require the cell to have the image at initialization, as I tried to make this code work but setting the image after initialization left a blank cell.
The current code includes constants I set to approximate an image in portrait orientation. In reality some of the images are portrait and some are landscape orientation.
Please let me know if there's anything additional you need to know.
Header for custom UITableViewCell:
#import <UIKit/UIKit.h>
#interface BeerDetailHead : UITableViewCell {
UILabel *beerName;
UIImageView *beerImage;
}
#property(nonatomic, retain)UILabel *beerName;
#property(nonatomic, retain)UIImageView *beerImage;
#end
Relevant portion of implementation for custom UITableViewCell
#import "BeerDetailHead.h"
#implementation BeerDetailHead
#synthesize beerName, beerImage;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
//beerName = [[UILabel alloc]init];
//beerName.textAlignment = UITextAlignmentLeft;
//beerName.font = [UIFont systemFontOfSize:14];
beerImage = [[UIImageView alloc]init];
//[self.contentView addSubview:beerName];
[self.contentView addSubview:beerImage];
}
return self;
}
- (void)layoutSubviews {
[super layoutSubviews];
CGRect contentRect = self.contentView.bounds;
CGFloat boundsX = contentRect.origin.x;
CGRect frame;
frame= CGRectMake(boundsX+10 ,10, 280, 375);
beerImage.frame = frame;
}
DetailViewController's cellForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *SimpleTableIdentifier = #"SimpleTableIdentifier";
NSArray *listData =[self.tableContents objectForKey:
[self.sortedKeys objectAtIndex:[indexPath section]]];
NSLog(#"listData = %#", listData);
NSUInteger row = [indexPath row];
if ([self.sortedKeys objectAtIndex:[indexPath section]] == #"header"){
static NSString *headerTableIdentifier = #"HeaderTableIdentifier";
BeerDetailHead * headerCell = (BeerDetailHead*)[tableView
dequeueReusableCellWithIdentifier: headerTableIdentifier];
if(headerCell == nil) {
headerCell = [[[BeerDetailHead alloc] initWithFrame:CGRectZero reuseIdentifier:headerTableIdentifier] autorelease];
}
headerCell.beerName.text = [listData objectAtIndex:row];
[headerCell.beerImage setImageWithURL:[NSURL URLWithString:self.beerPhoto]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
//NSLog(#"frame = %#", headerCell.beerImage.frame);
return headerCell;
}
else{
//use standard UITableViewCell
}
}
Implement tableView:heightForRowAtIndexPath: delegate method and return calculated height for each row from this method.
After loading each image call reloadData on your tableView OR if you want to animate changes call:
[self.tableView beginUpdates];
[self.tableView endUpdates];
Also, you might want to combine several sequence height updates into one. I would use I little delay to perform this:
// triggerUpdates calls the above code
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(triggerUpdates) object:nil];
[self performSelector:#selector(triggerUpdates) withObject:nil afterDelay:0.1];

Set background color of UITableViewCell

I have looked around to find a solution for setting the background color of the accessoryView to the same background color as the cellĀ“s contentView.
cell.contentView.backgroundColor = [UIColor colorWithRed:178/255.f green:14/255.f blue:12/255.f alpha:0.05];
cell.accessoryView.backgroundColor =[UIColor colorWithRed:178/255.f green:14/255.f blue:12/255.f alpha:0.05];
There is a solution that works but only let me use one color for all cells.
cell.contentView.superView.backgroundColor = [UIColor redColor];
Is the only solution to not use the accessoryView and use an image instead?
Thanks!
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
cell.backgroundColor = [UIColor greenColor];
}
Using this UITableViewDelegate method, you can set the color of cells to different colors. Note that Apple explicitly advise you to make changes to the backgroundColor property within the tableView:willDisplayCell:ForRowAtIndexPath: method in the docs, which state:
If you want to change the background color of a cell, do so in the tableView:willDisplayCell:forRowAtIndexPath: method of your table view delegate
Indeed, in iOS 6, changes to the property from anywhere else (like the tableView:cellForRowAtIndexPath: method) would have no effect at all. That no longer seems to be the case in iOS 7, but Apple's advice to modify the property from within tableView:willDisplayCell:ForRowAtIndexPath: remains (without any explanation).
For alternating colors, do something like this example:
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row % 2) {
cell.backgroundColor = [UIColor yellowColor];
} else {
cell.backgroundColor = [UIColor redColor];
}
}
I struggled with this one for a little while too and resorted to creating a custom image with the accessory. But I just found this solution that works well and doesn't require a custom image. The trick is to change the cell's backgroundView color not the backgroundColor.
UIView *myView = [[UIView alloc] init];
if (indexPath.row % 2) {
myView.backgroundColor = [UIColor whiteColor];
} else {
myView.backgroundColor = [UIColor blackColor];
}
cell.backgroundView = myView;
No need to change the accessoryView or contentView background colors. They'll follow automatically.
Note for 2014. Very typically you wold use -(void)setSelected:(BOOL)selected animated:(BOOL)animated
So, you'd have a custom cell class, and you'd set the colours for the normal/selected like this...
HappyCell.h
#interface HappyCell : UITableViewCell
#property (strong, nonatomic) IBOutlet UILabel *mainLabel;
etc...
#end
HappyCell.m
#implementation HappyCell
-(id)initWithStyle:(UITableViewCellStyle)style
reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self)
{
}
return self;
}
-(void)awakeFromNib
{
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
if(selected)
{
self.backgroundColor = [UIColor redColor];
.. other setup for selected cell
}
else
{
self.backgroundColor = [UIColor yellowColor];
.. other setup for normal unselected cell
}
}
#end
// to help beginners.......
// in your table view class, you'd be doing this...
-(NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
return yourDataArray.count;
}
-(UITableViewCell *)tableView:(UITableView *)tv
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger thisRow = indexPath.row;
ContentsCell *cell = [tv
dequeueReusableCellWithIdentifier:#"cellName"
forIndexPath:indexPath];
// "cellName" must be typed in on the cell, the storyboard
// it's the "identifier", NOT NOT NOT the restorationID
[cell setupForNumber: thisRow];
cell.mainLabel.text = yourDataArray[ thisRow ][#"whatever"];
cell.otherLabel.text = yourDataArray[ thisRow ][#"whatever"];
return cell;
}
hope it helps someone.
This worked for me:
cell.contentView.backgroundColor = [UIColor darkGreyColor];
For all lines with the same color
cell.backgroundColor = [UIColor colorWithRed:6.0/255.0 green:122.0/255.0 blue:145.0/255.0 alpha:1.0f];
For 2 colors
cell.backgroundColor = [UIColor colorWithRed:6.0/255.0 green:122.0/255.0 blue:145.0/255.0 alpha:1.0f];
if ((cell.backgroundColor = (indexPath.row % 2 == 0 ? [UIColor colorWithRed:6.0/255.0 green:122.0/255.0 blue:145.0/255.0 alpha:1.0f] : [UIColor colorWithRed:2.0/255.0 green:68.0/255.0 blue:80.0/255.0 alpha:1.0f]))){
cell.textLabel.textColor = [UIColor whiteColor];
}
For anyone else who might stumble on this and wants to set their UITableViewCell background to a pattern or texture rather than a solid color, you can do so like this:
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
cell.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:#"pattern.png"]];
}
The best option to have different backgrounds and what not would probably be to make your own TableViewCell implementation, in there you can put the logic to show whatever you want based on content or index etc.