UITableView change background color of specific cell - ios

I want to change the color of a UITableView cell. I have this code but it doesn't work. Can someone explain to me why and what I should change?
[_myTableView cellForRowAtIndexPath : [NSIndexPath indexPathForItem:myIndexAsInt inSection:0]].contentView.backgroundColor = [UIColor greenColor];

To change the color of a standard UITableViewCell you need to do that by overriding the UITableViewDelegate method tableView:willDispayCell:forRowAtIndexPath: like so:
- (void)tableView:(UITableView *)tableView willDispayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
cell.contentView.backgroundColor = color;
}
If your cell has custom content you might want to have a slightly different implementation.

to set the 3rd cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
if (indexPath.row == 2)
{
cell.contentView.backgroundColor = [UIColor redColor];
}
return cell;
}

The line of code itself is ok syntacticaly.
Some things cannot be verified from my side. Please put a breakpoint on that line and run it.
0) By putting a breakpoint there, and seeing the system stop there, you actually check that that line is executed.
1) If step 0 was ok, check that you actually have an instance of table view (it must NOT be nil, maybe if you are using nibs, you forgot to create an IBoutlet).
2) Make sure the tableView has proper delegate and datasource. (usually the ViewController where those things you mention are handled...)
3) check that you are passing a proper type and proper value for the myIndexAsInt argument. It should be of NSInteger type and should be equal 2.
4) If all 3 above are ok, perhaps you are calling it from a wrong place.
Let us know how it went.

You can have an variable to hold the index position. So after your didSelectRowAtIndexPath delegate called just set the index position in that variable and reload the table. Use a condition in cellForRowAtIndexPath datasource method to check for index position and now set the background colour for that specific cell.
in .h file:
NSInteger indexPos;
in didSelectRowAtIndexPath delegate:
indexPos = indexPath.row;
in cellForRowAtIndexPath:
if (indexPath.row == indexPos) {
cell.backgroundColor = [UIColor colorWithRed:255/255.0f green:255/255.0f blue:255/255.0f alpha:1.0f];
} else {
cell.backgroundColor = [UIColor colorWithRed:0/255.0f green:0/255.0f blue:0/255.0f alpha:1.0f];
}

Related

Update label properties of table view cell dependant upon data

So I have a custom table view cell which I have designed in its own xib, containing a few labels and images.
I'm trying to update the background colour of one of these labels depending upon the text given to the label & give it rounded edges.
I'm trying this for the edges with the following code, however it does not work and i'm not sure where this code needs to be for it to update each cell as it scrolls.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CardCell";
CardTableViewCell *cell = (CardTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
//cell = [[CardTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"CardCell"];
cell = [[[NSBundle mainBundle]loadNibNamed:#"CardCell" owner:self options:nil]objectAtIndex:0];
}
// Configure the cell...
NSManagedObject *card = [self.cards objectAtIndex:indexPath.row];
[cell.cardName setText:[card valueForKey:#"name"]];
[cell.type setText:[card valueForKey:#"attribute"]];
[cell.attack setText:[card valueForKey:#"attack"]];
[cell.defense setText:[card valueForKey:#"defense"]];
[cell.species setText:[card valueForKey:#"species"]];
[cell.starLevel setText:[card valueForKey:#"stars"]];
cell.type.layer.cornerRadius = cell.type.bounds.size.height / 8;
UIImage *cardImage = [UIImage imageWithData:[card valueForKey:#"thumb"]];
[cell.cardImage setImage:cardImage];
return (UITableViewCell *)cell;
}
The text and card image display correctly.
The cell has no frame in cellForRowAtIndexPath, therefore the corner radius is not set.
In this case, you should set the corner radius in willDisplayCell.
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
if (yourCellShouldHaveRoundedCorners) {
cell.layer.cornerRadius = cell.bounds.size.height / 8;
}
}
The background color of the label should work in cellForRowAtIndexPath.
Also, I see that you set a lot of properties on the cell in cellForRowAtIndexPath (i.e. type, attack, defense and so on). Since you already have a custom cell, it would be better to create an NSManagedObject property on the cell, and set all these properties on the setter of this object.
This way, you will only have to call cell.managedObject = card and the setter will furher set the other properties.
This approach is more model-oriented and it can save you some code duplication.
Try to use fixed number as cell.type.bounds.size.height won't render to a correct value in cellForRowAt
cell.type.layer.cornerRadius = 10 ;
cell.type.clipsToBounds = YES;
OR add this to cell class
-(void)layoutSubviews
{
self.type.layer.cornerRadius = self.type.bounds.size.height / 8;
}
Regarding color it will work perfectly in cellForRowAt like that
if(yourLogic)
{
cell.type.backgroundColor = [UIColor redColor];
}
else
{
cell.type.backgroundColor = [UIColor greenColor];
}

Tableview Cell requires two taps to reveal the view

I had a problem with table view didSelect method and prepareForSegue. I used SWRevealController in my app. While selecting cell it reveals the view. Sometimes it not worked properly. It takes two taps to reveal the view. A few months back I used old reveal view frame which contains perform block action. Its worked perfectly.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
for (int i=0; i<6; i++)
{
UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
if (i == indexPath.row)
{
cell.contentView.backgroundColor = [UIColor colorWithRed:KColorRedSelected green:KColorGreenSelected blue:KColorBlueSelected alpha:1];
}
else
{
cell.contentView.backgroundColor = [UIColor colorWithRed:KColorRed green:KColorGreen blue:KColorBlue alpha:1];
}
}
}
Add this code inside of didSelectRowAtIndexPath and didDeselectRowAtIndexPath functions
dispatch_async(dispatch_get_main_queue(), ^{
//Write code what you need
});
That works for me.
The problem is with this line
[self tableView:tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
You are calling the delegate method, which dequeues a reusable cell (I assume, since it's standard behavior). You do not want to dequeue a reusable cell, you want to do something with a cell that is currently displayed at indexPath. To do that use method from UITableView
[tableView cellForRowAtIndexPath:indexPath];
The full code
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// grab the selected cell and give it selected color
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.contentView.backgroundColor = [UIColor colorWithRed:KColorRedSelected green:KColorGreenSelected blue:KColorBlueSelected alpha:1];
}
- (void)tableView:(UITableView*)tableView didDeselectRowAtIndexPath:(NSIndexPath*)indexPath
{
// grab the deselected cell (if it's still visible) and give it deselected color
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.contentView.backgroundColor = [UIColor colorWithRed:KColorRed green:KColorGreen blue:KColorBlue alpha:1];
}
You will also need to set appropriate color in UITableViewDelegate method cellForRowAtIndexPath, since the color you once set will stay in the cell when it's reused.
This s completely wrong method to get clicked cell
UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
And don't use for loop as well. instead of this you should use
UITableViewCell *cell = [tableView cellForIndexPath:indexPath];
to get correct cell.

How to revert back the changes made in UITableViewCell

I have a custom UITableViewCell named as Hobbies.
Everything is working fine.Except one UIIssue.
When user taps on any cell I want to change the text colour of that particular Cell .And when user select another I want the previous selected cell should return to its original state.
Currently I am able to change the colour on Cell select but not able to revert it back when user selects another.
Here is the code I am using to change the textColor of a particular cell:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
HobbiesCell *cell = (HobbiesCell*)[tableView cellForRowAtIndexPath:indexPath];
cell.dateLabel.textColor = [UIColor colorWithWhite:255 alpha:0.5f];
}
How can I revert It back when user selects another cell.
You can create an object of UITableViewCell say previousCell and assign it each time you select one. This will be your last selected cell and you can assign it the default color each time you click a new cell.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
HobbiesCell *cell = (HobbiesCell*)[tableView cellForRowAtIndexPath:indexPath];
previousCell.dateLabel.textColor = [UIColor blackColor]; //Assuming that this is the color you want to go back
cell.dateLabel.textColor = [UIColor colorWithWhite:255 alpha:0.5f];
previousCell = cell;
}
declare this variable
int selectedIndex;
in your cellForRowAtIndexPath
if(indexPath.row == selectedIndex)
{
cell.dateLabel.textColor = [UIColor colorWithWhite:255 alpha:0.5f];
}
else
{
cell.dateLabel.textColor = [UIColor colorWithWhite:0 alpha:0.5f];//your default cell color
}
and in your didSelectRowAtIndex
selectedIndex = indexPath.row;
[tableView reloadData];
You should always keep in mind that the cells are reusable, so the one you change will be used as is for displaying other rows when you scroll.
Instead, you should keep an array of your own models that keep the data (in your case color information) and use the cells only for displaying it.
To revert the color simply keep a reference to the latest NSIndexPath.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
MyRowModel *prevRowModel = [self.rowModels objectAtIndex:self.lastIndexPath.row];
prevRowModel.color = [UIColor colorWithWhite:255 alpha:1f];
MyRowModel *rowModel = [self.rowModels objectAtIndex:indexPath.row];
rowModel.color = [UIColor colorWithWhite:255 alpha:0.5f];
[self.tableView reloadRowsAtIndexPaths:#[indexPath, self.lastIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
self.lastIndexPath = indexPath;
}
If you go for reload the tableview then try this .
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// reload the table
[tableView reloadData];
HobbiesCell *cell = (HobbiesCell*)[tableView cellForRowAtIndexPath:indexPath];
previousCell.dateLabel.textColor = [UIColor colorWithWhite:255 alpha:0.5f]; // color insert which you want to insert
}
hope it helps you without adding varible.
Try cell.textLabel.highlightedTextColor.
if (cell == nil) {
........
/* your cell initiation code */
........
cell.textLabel.textColor = [UIColor whiteColor];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.textLabel.highlightedTextColor = [UIColor orangeColor];
}
You need to maintain a reference to the currently selected indexPath. Something like...
#property (nonatomic, strong) NSIndexPath *currentHobby;
Then in your didSelectRowAtIndexPath: method insert this...
if(_currentHobby && ![_currentHobby isEqual:indexPath]) {
HobbiesCell *currentCell = [tableView cellForRowAtIndexPath:_currentHobby];
currentCell.dateLabel.textColor = [UIColor originalColor];
}
_currentHobby = indexPath;
Then in your cellForRowAtIndexPath: make sure you include...
if([indexPath isEqual:_currentHobby]) {
cell.dateLabel.textColor = [UIColor selectedColor];
} else {
cell.dateLabel.textColor = [UIColor originalColor];
}

Weird Custom UITableViewCell behavior

I got a really weird problem with a custom UITableViewCell. Btw, i am using an UIViewController. So, i crafted the cell in Storyboard (like in the image bellow) and i set it's class to my custom UITableViewCell class. Then I created all the IBOutlets and IBActions in the custom cell class.
My cellForRowAtIndexPath method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"Cell";
PostTableViewCell *cell = (PostTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
cell = [[PostTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
[cell setCellContentWithPost:[PostsArray objectAtIndex:indexPath.row]];
return cell;
}
My custom UITableViewCell class:
#import "PostTableViewCell.h"
#implementation PostTableViewCell
- (void)setCellContentWithPost:(SDPost*)post {
self.alpha = 0.f;
self.postTitleLabel.text = post.title;
[self.thumbnailImageView sd_setImageWithURL:[NSURL URLWithString:post.thumbnailURL] placeholderImage:nil options:SDWebImageHandleCookies];
[UIView animateWithDuration:0.35 animations:^{
self.alpha = 1.0f;
}];
}
-(void)awakeFromNib{
self.postTitleLabel.textColor = [UIColor whiteColor];
self.postTitleLabel.font = [UIFont fontWithName:#"Montserrat-Regular" size:16.5];
self.readingTimeView.backgroundColor = [UIColor colorWithRed:0.33 green:0.74 blue:0.15 alpha:1];
self.readingTimeView.layer.cornerRadius = 4;
self.readingTimeLabel.textColor = [UIColor whiteColor];
self.readingTimeLabel.font = [UIFont fontWithName:#"Montserrat-Bold" size:11.75];
self.commentsCountView.backgroundColor = [UIColor colorWithRed:0.74 green:0.19 blue:0.4 alpha:1];
self.commentsCountView.layer.cornerRadius = 4;
self.commentsCountLabel.textColor = [UIColor whiteColor];
self.commentsCountLabel.font = [UIFont fontWithName:#"Montserrat-Bold" size:11.75];
}
I tried to style the cell from the initWithStyle method of the UITableViewCell, but for some reason it never gets called, so i ended up doing this in awakeFromNib.
So, the problem is: I think i am doing something wrong, because as you can see in this GIF (https://dl.dropboxusercontent.com/s/6crcjbmitr5fmk7/Untitled%20%281%29.gif?m=), the heart button it get's automatically turned on/off as i scroll through the cells.
Can anyone of you guys help me fix this ? Thanks a lot!
Each time the cell is displayed it takes value from your PostsArray array. So when you click on the heart, you should update its corresponding object in the array.
That happens because you have the same CellIdentifier for all your cells, which is fine in this case if you are very careful on how you are handling the "heart" element.
You should have a way to determine which elements on the cell have been "liked". As I suppose you need to know on which elements your user pressed the heart button.
When initialising/reusing your cell you need to be sure that the heart button is set properly to "red/on" or "white/off".
For instance :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"Cell";
PostTableViewCell *cell = (PostTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[PostTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
[cell setHeartState:[[AnArray objectAtIndex:indexPath.row] hasBeenLikedByUser]]
[cell setCellContentWithPost:[PostsArray objectAtIndex:indexPath.row]];
return cell;
}
It is just a quick draft.
Hope that helps
I managed to solve this by checking if the hearth should be filled or not. I stored the post id using NSUserDefaults and in setCellContentWithPost i added an if statement that checks if the cell's post is favorited.
Thanks for interest guys!

UIButton gets created twice on cell reload

I have a UIButton inside a UITableViewCell. When the app is first launched, it works as expected, where I created it's frame.
When I scroll pass the cell which holds the button, it creates a second instance of the button slightly below the button.
Here's a video to illustrate my problem: http://pixori.al/DJ1k
Here's the code for the UITableViewCell and also how I populate the cells.
Not sure why it's behaving like this.
#pragma mark - UITableViewDataSource
// 3 sections, (1 = mistarOverview) (2 = hourlyForecast) (3 = dailyForecast)
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 3;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (section == 0) {
return MAX(6,6) + 1; //TODO add getNumberOfClasses for people with 7 or 8 classes
} else if (section == 1) {
return MIN([[MAManager sharedManager].hourlyForecast count], 6) + 1;
} else {
return MIN([[MAManager sharedManager].dailyForecast count], 6) + 1;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"CellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Redefine layout variables in method from `viewDidLoad`
CGFloat inset = 20; // For padding
if (! cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
}
// Sets up attributes of each cell
cell.selectionStyle = UITableViewCellSelectionStyleNone; //TODO none
cell.backgroundColor = [UIColor colorWithWhite:0 alpha:0.2];
cell.textLabel.textColor = [UIColor whiteColor];
cell.detailTextLabel.textColor = [UIColor whiteColor];
QBFlatButton* loginButton = nil;
if (indexPath.section == 0) {
if (indexPath.row == 0) {
[self configureHeaderCell:cell title:#"Grades"];
if ([cell.textLabel.text isEqual: #"Grades"] && (!loginButton) && (indexPath.row == 0) && (indexPath.section == 0)) {
UIView *cellView = cell.contentView;
CGRect loginButtonFrame = CGRectMake((cellView.frame.size.width - (80 + inset)), 18, 80, (cellView.frame.size.height));
loginButton = [[QBFlatButton alloc] initWithFrame:loginButtonFrame];
[loginButton addTarget:self action:#selector(loginButtonWasPressed)forControlEvents:UIControlEventTouchUpInside];
loginButton.faceColor = [UIColor grayColor];
loginButton.sideColor = [UIColor clearColor];
loginButton.radius = 6.0;
loginButton.margin = 4.0;
loginButton.depth = 3.0;
loginButton.alpha = 0.3;
loginButton.titleLabel.font = [UIFont fontWithName:#"HelveticaNeue-Light" size:20];
[loginButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[loginButton setTitle:#"Login" forState:UIControlStateNormal];
[cellView addSubview:loginButton];
}
} else {
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
cell.textLabel.text = [NSString stringWithFormat:#"Period %ld A+", (long)indexPath.row];
cell.detailTextLabel.text = #"Class name";
//TODO get grades and config using method (TB Created)
}
} else if (indexPath.section == 1) {
if (indexPath.row == 0) {
[self configureHeaderCell:cell title:#"Hourly Forecast"];
}
else {
// Get hourly weather and configure using method
MACondition *weather = [MAManager sharedManager].hourlyForecast[indexPath.row - 1];
[self configureHourlyCell:cell weather:weather];
}
}
else if (indexPath.section == 2) {
if (indexPath.row == 0) {
[self configureHeaderCell:cell title:#"Daily Forecast"];
}
else if (indexPath.section == 2) {
// Get daily weather and configure using method
MACondition *weather = [MAManager sharedManager].dailyForecast[indexPath.row - 1];
[self configureDailyCell:cell weather:weather];
}
}
return cell;
}
Implement the following UITableView Delegate Method
-(void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
//In here, check the index path. When you have the cell that contains the button, pop it out from there by using [button removeFromSuperView];
}
Your problem occurs when you dequeue the cell. Since the cell is being reused, it already has the button and you're simply re-adding it again. This will solve your issue. However, I'd recommend you create a subclass for the UITableViewCell, and in it's prepareForReuse method, pop the button out. Up to you. Both will work.
Table view cells are not just deallocated then they move out of visible area. They are stored for reusing and then returned in tableView dequeueReusableCellWithIdentifier:CellIdentifier];
So you need to clean your cells after using or before reusing. There are several ways:
1.Add tag to your button when you create it
loginButton.tag = SOME_TAG;
just after
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
search for view with this tag
loginButton = [cell viewWithTag:SOME_TAG];
if loginButton != nil you can reuse it or remove from cell and then create a new one.
2.Implement UITableViewDelegate method
-(void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
and erase login button inside it.
3.Create custom UITableViewCellclass and implement prepareForReuse method.
You're adding the button every time you return a cell in this method. If you scroll the cell off the screen and back on, this method is called again for the same index path, and you will add the button again.
You declare the variable, do nothing with it, then check if it is nil. It will always be nil, so you always add the button.
A quick and dirty solution is to give the button a tag, then check for its existence using viewWithTag:.
A better solution is to make a custom cell subclass, and set one-time properties like this in the init method. Your cell contents seem very different for each section as well, so use different reuse identifiers for each section, and possibly a different cell subclass. Clearing out sub views is expensive and could hurt your scrolling performance.
When you run your project first time then cellForRowAtIndexPath is called.....
Then whenever you scroll tableView it again calls cellForRowAtIndexPath and reload data automatically..
So you have to take CellIdentifier as unique for each cell.
you have to remove static keyword from
static NSString *CellIdentifier = #"CellIdentifier";
now you have
NSString *CellIdentifier = #"CellIdentifier";
only this things
Now you have to write like below
NSString *CellIdentifier = [NSString stringWithFormat:#"%#",indexPath];
Now Enjoy.....

Resources