Strange Behaviour of Selected UITableViewCell in iOS7 - ios

I am porting my application to iOS 7 and having some strange behaviour with my tableViews. When I select a cell, the separators disappear for no apparent reason. Not only that, but the background image for the selected state also shifts about 1 pixel upward, even though its frame does not indicate this. I have none of these issues with iOS 6 or older operating systems.
I define my table view the following way:
statisticsTableView = [[UITableView alloc] initWithFrame:CGRectMake(170.0f, 0.0f, 150.0f, window.size.height) style:UITableViewStylePlain];
statisticsTableView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"background.png"]];
statisticsTableView.separatorColor = [UIColor darkGrayColor];
//statisticsTableView.separatorInset = UIEdgeInsetsZero; // <- Makes app crash in iOS6 or older
statisticsTableView.showsHorizontalScrollIndicator = NO;
statisticsTableView.delegate = self;
statisticsTableView.dataSource = self;
The cell is sub-classed and the relevant parts are the following (both regular and selected bacground images are the exact same size and appear correct in iOS6 or older, it is only iOS 7 where the selected BG image appears slightly higher):
UIView *backgroundView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 150.0f, 70.0f)];
backgroundView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"cell_background_corp.png"]];
self.backgroundView = backgroundView;
UIView *backgroundView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 150.0f, 70.0f)];
backgroundView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"cell_background_corp_selected.png"]];
self.selectedBackgroundView = backgroundView;
Now, I do know that other people had already asked this question (or, at least part of it), but none of the answers there worked for me. For further reference, I tried these "solutions" and they did NOT work:
Putting this into my didSelectrowAtIndexPath made my cells deselect.
But, I need my selected cell to stay selected, and besides
it looked really awkward with the blinking as swithces between states:
[self.tableView deselectRowAtIndexPath:indexPath animated:NO];
[self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
The other one:
Putting this into the heightForRowAtIndexPath delegate method
as a return value did absolutely nothing:
ceilf(rowHeight);
And finally:
This was my attempt to fix the background image position bug. I modified
the way I added the selected background view in the subclassed tableView cell,
but it did not do squat:
UIView *backgroundView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 150.0f, 70.0f)];
if (iOSVersion >= 7.0f)
{
backgroundView.frame = CGRectMake(0.0f, 1.0f, 150.0f, 70.0f);
}
backgroundView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"cell_background_corp_selected.png"]];
self.selectedBackgroundView = backgroundView;

I had a similar problem and what fixed it for me was to override layoutSubviews in the UITableViewCell subclass like this:
- (void)layoutSubviews
{
[super layoutSubviews];
self.selectedBackgroundView.frame = self.backgroundView.frame;
}
The important thing is to have the [super layoutSubviews]call first.
By the way, I think the default behavior is intended in iOS7. If you look at the Apple Mail app, you see that the separator line also disappears when selecting a cell and that the active background is drawn where the separator line used to be.

Related

TableView starts in the wrong position initially

This issue has come about as I update an app from iOS 7 to iOS 8. My tableview starts in the wrong position initially. Once you touch it or scroll it. The tableview scrolls into the correct position and works as intended.
The table view is embedded within a UIPageViewController.
UITableView *tableView = (id) [self.view viewWithTag:5];
[tableView registerClass:[BroadcastCell class] forCellReuseIdentifier:CellBroadcastTableIdentifier];
[tableView registerClass:[BroadcastHeaderCell class] forCellReuseIdentifier:CellBroadcastHeaderTableIdentifier];
[tableView setSeparatorInset:UIEdgeInsetsZero];
tableView.tableHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 64.0f)];
tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 0.0f)];
[tableView setDelegate:self];
[tableView setDataSource:self];
tableView.backgroundColor = [UIColor clearColor];
tableView.opaque = NO;
tableView.backgroundView = nil;
tableView.rowHeight = UITableViewAutomaticDimension;
tableView.estimatedRowHeight = UITableViewAutomaticDimension;
Screenshot can be found - https://pbs.twimg.com/media/Byh_5eIIQAA06ok.png:large
I had the same issue. After much effort I found out that in the previous view I was using
[self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:#"title-bar-bg.png"] forBarMetrics:UIBarMetricsDefault];
I changed it to
[[UINavigationBar appearance] setBackgroundImage:[UIImage imageNamed:#"title-bar-bg.png"] forBarMetrics:UIBarMetricsDefault];
and the problem was solved.
Select your View Controller and Deselect property 'Adjust Scroll View Insets' on the storyboard (under View Controller section).
OR
Add following lines
self.automaticallyAdjustsScrollViewInsets = NO;

Setting frame for background colour of Selected tableviewCell working fine in iOS 7 but not in iOS 6

I want to set frame for background colour of selected tableviewCell. I am using the following code.
UIView * cellBackgroundView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
cellBackgroundView.backgroundColor = [UIColor clearColor];
UIView * selectedCellColor = [[UIView alloc] initWithFrame:CGRectMake(5, 0, 300, 44)];
selectedCellColor.backgroundColor = [UIColor colorWithRed:50.0/255.0 green:50.0/255.0 blue:50.0/255.0 alpha:1.0];
[cellBackgroundView addSubview:selectedCellColor];
cell.selectedBackgroundView = cellBackgroundView;
Which is working fine in iOS7. Even Tableview selection also not working in iOS6.
Following code working fine in Both iOS6 and iOS 7. But here i am not able to set frame for background colour of selected tableViewCell.
UIView *selectedCellColor = [[UIView alloc] init];
[selectedCellColor setFrame:CGRectMake(0, 0, 320, 44)];
selectedCellColor.backgroundColor = [UIColor colorWithRed:50.0/255.0
green:50.0/255.0
blue:50.0/255.0
alpha:1.0];
cell.selectedBackgroundView=selectedCellColor;
In cellForRowAtIndexPath:, call dequeueReusableCellWithIdentifier:forIndexPath: (not simply dequeueReusableCellWithIdentifier:. The reason is that now your cell is the correct size. Do not hard-code the cell size; get it as the bounds of the cell you are handed.
Now draw a UIImage in that size, constructing your frame-like drawing (the image itself is clear to begin with). Put it in a UIImageView and set the cell's selected background view to that image view.
This will work in iOS 6 and iOS 7.
Example (color and size arbitrary, just for illustration purposes):
UIGraphicsBeginImageContextWithOptions(cell.bounds.size, NO, 0);
// change this color as you like
[[UIColor redColor] setFill];
// fiddle with this size as you like
[[UIBezierPath bezierPathWithRect:CGRectMake(10,10,300,25)] fill];
UIImage* im = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageView* iv = [[UIImageView alloc] initWithImage:im];
cell.selectedBackgroundView = iv;
EDIT
Try this instead:
[cell.contentView setBackgroundColor:[UIColor redColor]];
UIView *selectedBG = [[UIView alloc]initWithFrame:cell.contentView.frame];
[selectedBG setBackgroundColor:[UIColor greenColor]];
[cell.selectedBackgroundView addSubview:selectedBG];

Black 1px line appearing between selected cells of a clear table

Prior to Xcode 5.1 this problem didn't exist for me but now when building my app with 5.1/5.1.1 I'm seeing black horizontal lines appear when my table cells are selected. Both the table view and cells have clear backgrounds and nothing has changed in the code from the time it was working just fine.
In the viewDidLoad method I set the following tableView parameters:
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
self.tableView.backgroundColor = [UIColor clearColor];
self.view.backgroundColor = [UIColor clearColor];
In the cellForRowAtIndexPath method:
ListViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"ListViewCell"];
if (cell == nil) {
cell = [[ListViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"ListViewCell"];
}
return cell;
}
I'm using a UITableViewCell subclass which has the following in awakeFromNib:
UIView *bkgView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height)];
bkgView.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;
bkgView.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.4f];
self.selectedBackgroundView = bkgView;
This code worked fine when building in version of Xcode < 5.1 but now I'm seeing different results. Occurs with both Plain and Grouped styles.
[self.tableView setSeparatorColor:[UIColor clearColor]];

How to get rid of the table cell's selectionStyle but still recieve setSelected/setHighlighted calls

I've tried the method presented here, and everything works except that I cannot make the selectedBackgroundView transparent, it stays white. In my custom UITableViewCell class I have:
-(void)awakeFromNib {
UIView *bkgView = [[UIView alloc]initWithFrame:self.frame];
bkgView.alpha = 0.5;
bkgView.backgroundColor = [UIColor clearColor];
self.selectedBackgroundView = bkgView;
}
I've also called [self setNeedsDisplay]; in the setSelected method.
What I want is to remove the blue highlight (from UITableViewCellSelectionStyleBlue
, I don't want to set this to UITableViewCellSelectionNone as it will disable the setHighlight/Selected calls) and still have the highlight/select methods called. I'm so very nearly there, it's just that the selectedBackgorundView remains white! If I set it to redColor or blueColor, it will appear as red or blue, but when I put clearColor, it shows as white. I thought about setting the background with colorWithPatternImage using a transparent PNG image, but I'd like to avoid this.
I prefer to try and figure this out as it's a lot cleaner to rely on these two method calls, and I also want to retain the use of the disclosure indicator which becomes white when selected, which will otherwise stay dark if I use UITableViewCellSelectionNone.
I'd recommend using tableView:willSelectRowAtIndexPath: and returning nil.
That way you still get notified when a Cell is going to be selected. However, it won't actually get selected, and from there you can manage selection yourself without having to deal with the control's default styling.
you use the selectedBackgroundView to override the blue
in viewForRow: method:
UIView *v = [[UIView alloc] initWithFrame:CGRectZero];
v.backgroundColor = [UIColor clearColor];
cell.selectedBackgroundView = v;
Set the background view and the selectedBackgroundView:
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
view.backgroundColor = [UIColor whiteColor];
self.backgroundView = view;
view = [[UIView alloc] initWithFrame:CGRectZero];
view.backgroundColor = [UIColor clearColor];
self.selectedBackgroundView = view;
Then override - (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated
- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated
{
[super setHighlighted:highlighted animated:animated];
self.backgroundView.hidden = highlighted;
}

How to get the header view of a grouped table view?

I want to get all the views of a grouped table view to change the label color and to set the background color.
I found the answer, it's not possible to get the header view of a table view section. But you can implement the delegate tableView:viewForHeaderInSection: to recreate the header view and the label. The following code will give you the same header view and the exact label.
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
NSString *sectionTitle = [self tableView:tableView titleForHeaderInSection:section];
if (sectionTitle == nil) {
return nil;
}
// Create label with section title
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(20.0f, 5.5f, 300.0f, 30.0f)];
label.backgroundColor = [UIColor clearColor];
label.font = [UIFont boldSystemFontOfSize:16.5];
label.shadowColor = [UIColor whiteColor];
label.shadowOffset = CGSizeMake(0.0, 1.0);
label.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth;
label.text = sectionTitle;
// Create header view and add label as a subview
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, self.view.frame.size.width, 44.0f)];
view.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth;
[view addSubview:label];
return view;
}
That's great you figured out your solution.
A couple of suggestions:
Don't hardcode the CGRect for the width of your frame, but rather use self.view.size.width for the width (e.g. in case you're in landscape orientation or if Apple ever introduces an iPhone with a different screen size);
You probably want to use autoresizingMask for both the label and the view that holds the label, so that they'll resize as the screen orientation changes, or make sure you invoke [self.tableview reloadData] on orientation changes; and
This is obviously a single line label ... if that works for you great, otherwise you'd want to use sizeWithFont:constrainedToSize:lineBreakMode to determine the height, both for creating the label/view as well as responding to tableView:heightForHeaderInSection:.
You also need to add the textColor:
label.textColor = [UIColor colorWithRed:0.265 green:0.294 blue:0.367 alpha:1.000];

Resources