I'm using a custom sectionheader class with a tableview, and getting some unexpected behavior after rotation. Here's the use case:
Tap on cell in UITableView
View pushed onto stack.
Rotate the view to landscape.
Rotate back to portrait.
Pop the view.
On the iPhone 3G only, a landscape-sized section header now appears stuck somewhere down the middle of the view (in addition to the portrait-sized section header, which appears, as it should, at the top of the tableview). The extraneous header scrolls with the UITableView cells, and switching away from and back to the view (the UITableView is nested within a UITabBarController) doesn't fix the problem.
I can't reproduce this problem on the iPhone 4, or in the Simulator. It seems that, for some reason, a landscape oriented sectionheaderview is being added to the uitableview after popping the second level view, but why would this be? Note that the same problem is reproduced when the default (and not a custom) header is used. I've also checked whether it's a problem with device orientation being returned incorrectly, and that does not appear to be the case.
Here's the init code for the custom SectionHeaderView class, if it's helpful:
-(id)initWithFrame:(CGRect)frame title:(NSString*)title delegate:(id <SectionHeaderViewDelegate>)aDelegate {
self = [super initWithFrame:frame];
if (self != nil) {
float lineHeight = 0.5f;
// check line sizing for retina/non-retina
if (![Utilities hasRetina])
{
lineHeight = 1.0f;
}
// Set up the tap gesture recognizer.
delegate = aDelegate;
// Create and configure the title label.
CGRect titleLabelFrame = self.bounds;
titleLabelFrame.origin.y -= 12.5;
titleLabel = [[UILabel alloc] initWithFrame:titleLabelFrame];
titleLabel.text = title;
titleLabel.textAlignment = UITextAlignmentCenter;
titleLabel.font = [UIFont fontWithName:#"Georgia" size:15.0];
titleLabel.textColor = [UIColor whiteColor];
titleLabel.backgroundColor = [UIColor clearColor];
[self addSubview:titleLabel];
// add thin white line to top of section header
UIView *topBorder = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, self.bounds.size.width, lineHeight)];
[topBorder setBackgroundColor:[UIColor whiteColor]];
[self addSubview:topBorder];
[topBorder release];
// Set the colors for the gradient layer.
static NSMutableArray *colors = nil;
if (colors == nil) {
colors = [[NSMutableArray alloc] initWithCapacity:3];
UIColor *color = nil;
color = [UIColor colorWithRed:57.0/255.0 green:56.0/255.0 blue:105.0/255.0 alpha:1.0];
[colors addObject:(id)[color CGColor]];
color = [UIColor colorWithRed:54.0/255.0 green:53.0/255.0 blue:95.0/255.0 alpha:1.0];
[colors addObject:(id)[color CGColor]];
color = [UIColor colorWithRed:57.0/255.0 green:56.0/255.0 blue:105.0/255.0 alpha:1.0];
[colors addObject:(id)[color CGColor]];
}
[(CAGradientLayer *)self.layer setColors:colors];
[(CAGradientLayer *)self.layer setLocations:[NSArray arrayWithObjects:[NSNumber numberWithFloat:0.0], [NSNumber numberWithFloat:0.48], [NSNumber numberWithFloat:1.0], nil]];
}
return self;
}
Why would an additional landscape version of the custom SectionHeaderView be added in the portrait view, only on the iPhone 3G?
Thanks in advance for any help.
Still no clue what's causing this problem, but I eventually solved it by adding a check in viewWillAppear to make sure the old header was removed.
Related
Further to this question I asked recently, I was able to get the explanation view appearing in front of the tableview successfully, but I now have a problem whereby the tableview's separator lines are briefly visible underneath my explanation view when the tableview first loads. This is in spite of setting the explanation view's background colour, setting it to opaque and bringing it to the front. It's just a brief flash, but it's noticeable and distracting.
Here is my code (_explanationView is a UIView instance variable that I set to nil in the view controller's dealloc method):
- (void)viewDidLoad
{
[super viewDidLoad];
self.tableView.separatorColor = [UIColor darkGrayColor];
CGRect frame = CGRectMake(50.0f, 120.0f, 220.0f, 155.0f);
_explanationView = [[UIView alloc] initWithFrame:frame];
_explanationView.userInteractionEnabled = NO;
_explanationView.backgroundColor = [UIColor whiteColor];
_explanationView.opaque = YES;
_explanationView.layer.borderColor = [UIColor darkGrayColor].CGColor;
_explanationView.layer.borderWidth = 1.0f;
_explanationView.layer.cornerRadius = 10.0f;
_explanationView.layer.masksToBounds = YES;
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(20.0f, 0.0f, 180.0f, 145.0f)];
label.backgroundColor = [UIColor whiteColor];
label.textColor = [UIColor darkGrayColor];
label.numberOfLines = 0;
label.lineBreakMode = UILineBreakModeWordWrap;
label.font = [UIFont systemFontOfSize:14.0f];
label.text = #"Explanation of this screen...";
[_explanationView addSubview:label];
[self.tableView addSubview:_explanationView];
}
I found that I had to bring the explanation view to the front in the viewDidAppear: method, otherwise the tableview's separator lines are permanently visible underneath.
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self.tableView bringSubviewToFront:_explanationView];
}
What can I do to stop the tableview's separator lines from briefly being visible underneath my custom view?
I found this answer which indicates that handling the order of a custom subview in tableView can be done in the layoutSubviews method.
I have a ViewController with a radial gradient background. Inside that I have a UITableView with cells and sections. Now I want to show the gradient behind the table view as you scroll. The issue is that when the section locks at the top you can see the cells behind the section. I would set the section background color but if I do that it does not match the radial gradient background. Is there anyway to have the cells clip under the sections while keeping the clearColor background?
Simple way to get a transparent section header without creating your own header views.
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section
{
if ([view isKindOfClass:[UITableViewHeaderFooterView class]]) {
UITableViewHeaderFooterView *headerView = (UITableViewHeaderFooterView *)view;
headerView.contentView.backgroundColor = [UIColor clearColor];
headerView.backgroundView.backgroundColor = [UIColor clearColor];
}
}
This piece of code works perfectly fine in iOS 7.
EDIT
I know this is a little late, but along with this you have to add 2 lines making sure the background color (and background color of the background view?) of the uitableview is also clear.
tableView.backgroundColor = [UIColor clearColor];
tableView.backgroundView.backgroundColor = [UIColor clearColor];
if I understand it, you want a completely clear tableview and tableview cell so you can see the background of your view controller.
You can achieve this by setting the tableview as having no background
tableview.backgroundColor = [UIColor clearColor];
tableView.opaque = NO;
tableView.backgroundView = nil;
and also the cell
cell.backgroundColor = [UIColor clearColor]
if you also want the section to be transparent, you can use this method:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
to make a custom view (for example create an image view with a transparent .png for the background)
I hope I understand your question correctly.
edit after clarification
to give the appearance that the cells stop before going underneath the section header:
make a class that is a subclass of uitableview with this ivar:
#interface CustomTableView : UITableView
{
CAGradientLayer* maskLayer;
}
obviously this will create a gradient but if you wanted you could either tweak it or use CALayer and instead of programmatically creating the mask, create a .png with the correct width/height of your section header.
ANYWAY: if you use the CAGradientLayer:
- (id)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:coder];
if (self)
{
[self setupGradients]; //call your method
}
return self;
}
- (void)setupGradients
{
[self addObserver:self forKeyPath:#"contentOffset" options:0 context:nil];
*/ ***** if you choose to use CALayer instead of CAGradient ****** */
//maskLayer = [[CALayer layer] retain];
//maskLayer.contents = (id) [UIImage imageNamed:#"maskLayer.png"].CGImage;
//maskLayer.backgroundColor = [UIColor clearColor].CGColor;
*/ ***** if you choose to use CALayer instead of CAGradient ****** */
maskLayer = [[CAGradientLayer layer] retain];
CGColorRef outerColor = [UIColor colorWithWhite:1.0 alpha:0.0].CGColor;
CGColorRef innerColor = [UIColor colorWithWhite:1.0 alpha:1.0].CGColor;
maskLayer.colors = [NSArray arrayWithObjects:(id)outerColor,
(id)innerColor, (id)innerColor, (id)outerColor, nil];
maskLayer.locations = [NSArray arrayWithObjects:[NSNumber numberWithFloat:0.0],
[NSNumber numberWithFloat:0.0],
[NSNumber numberWithFloat:0.9],
[NSNumber numberWithFloat:1.0], nil]; //this creates a gradient effect. Tweak these numbers for a hard line.
maskLayer.bounds = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
maskLayer.anchorPoint = CGPointZero;
self.layer.mask = maskLayer;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
[CATransaction begin];
[CATransaction setDisableActions:YES];
maskLayer.position = CGPointMake(0, self.contentOffset.y);
[CATransaction commit];
}
then in your view controller:
CustomTableView *_tableView; //ivar
_tableView = [[CustomTableView alloc] initWithFrame:YOUR_FRAME];
The basic idea is a mask, you create a mask shape on the top of your tableview that is the same size as your section header. it will appear that the cells "disappear" behind it. It's a bit tricky, but it will work.
I currently have a UITextView which is contained in a UIViewController using the following code:
UIViewController *container = [[UIViewController alloc] init];
container.view.frame = CGRectMake(0, 0,
[UIScreen mainScreen].bounds.size.width, 1000);
//[UIScreen mainScreen].bounds.size.height
container.view.userInteractionEnabled = YES;
container.view.clipsToBounds = YES;
UIImageView *imgView = [[UIImageView alloc]
initWithImage:[UIImage imageNamed:#"myImage.png"]];
imgView.frame = container.view.frame;
imgView.userInteractionEnabled = YES;
[container.view addSubview:imgView];
[imgView release];
UITextView *textContained = [[UITextView alloc]
initWithFrame:CGRectMake(0, 0, container.view.bounds.size.width, 1000)];
//container.view.bounds.size.height
textContained.font = [UIFont fontWithName:#"Calibri" size:14];
textContained.scrollEnabled = YES;
textContained.editable = NO;
textContained.textColor = [UIColor whiteColor];
textContained.backgroundColor = [UIColor clearColor];
textContained.font = [UIFont boldSystemFontOfSize:14];
textContained.userInteractionEnabled = YES;
textContained.alwaysBounceVertical = YES;
textContained.contentSize = CGSizeMake(container.view.frame.size.width,
container.view.frame.size.height);
I then set my UItextView text property with some text, which extends past the current screen size. I then add my UITextView to my container using the following code.
switch (indexPath.row) {
case 0:
textContained.text = #"LOTS AND LOTS OF TEXT";
[container.view addSubview:textContained];
[self.navigationController pushViewController:container animated:YES];
[textContained release];
break;
default:
break;
}
[container release];
When I test this code, the text appears just fine in the UITextView and everything looks ok. But the problem is when I try to scroll down to see the remainder of the text. Everytime I scroll down the UITextView scrolls back in to its original position. I have tried several ways to get this to work, but I think I need some fresh eyes to see what I'm doing wrong.
Any help is greatly appreciated.
First, you don't want to set the contentSize of a UITextView, since it is determined by the length of text automatically.
Try to make the height of textView smaller. For example:
UITextView *textContained = [[UITextView alloc]
initWithFrame:CGRectMake(0, 0, container.view.bounds.size.width, 50)];
And give it more text, like:
textContained.text = #"LOTS AND LOTS OF TEXT\nLOTS AND LOTS OF TEXT\nLOTS AND LOTS OF TEXT\n\nLOTS AND LOTS OF TEXT\nLOTS AND LOTS OF TEXT\n";
In a model UIViewController I have the following implementation of loadView (everything is created programmatically):
- (void)loadView {
// Add Basic View
UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 540, 620)];
myView.backgroundColor = [UIColor clearColor];
self.view = myView;
[myView release];
// Add NavigationBar
// Add a BG image
// Add Table
UITableView *tbView = [[UITableView alloc] initWithFrame:CGRectMake(30, 80, 480, 250) style:UITableViewStyleGrouped];
tbView.dataSource = self;
tbView.delegate = self;
tbView.scrollEnabled = NO;
tbView.backgroundColor = [UIColor clearColor];
[tbView reloadData];
[self.view addSubview:tbView];
[tbView release];
// some more code
}
As you can see I set backgroundColor to clearColor, yet when I compile and run the code I always see a gray background behind the table:
I don't understand what I am doing wrong (sounds stupid, I know), I used to have the very same code and it worked perfectly fine. I am compiling with iOS SDK 4.2.1
You also need to set your UITableView's backgroundView property to nil on recent (since 3.2) versions of iOS.
As such, adding...
tbView.backgroundView = nil;
...should sort your problems.
That said, if you want to maintain compatibilty with pre-3.2 devices, you should check for the existence of this via the instancesRespondToSelector method before calling it.
Make sure you have the following 3 options set:
tbView.opaque = NO;
tbView.backgroundColor = [UIColor clearColor];
tbView.backgroundView = nil;
try
tbView.backgroundView = nil;
I tried to change from storyboard.
It works fine in
tbView.backgroundColor = .white
I want to add a custom UIImageView to UISearchDisplayController's table view background and set table view's background color to clearColor. Tried a few different approach but couldn't find the right solution. Any idea how to approach this?
Note: I don't want to add to searchDisplayController's searchResultsTableView's view hierarchy, but rather overlay another sibling view below it)
You can set the background image in a similar way you would for your main table, only set it in the searchDisplayControllerDidBeginSearch delegate method. For instance:-
- (void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller {
[controller.searchResultsTableView setDelegate:self];
UIImageView *anImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"gradientBackground.png"]];
controller.searchResultsTableView.backgroundView = anImage;
[anImage release];
controller.searchResultsTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
controller.searchResultsTableView.backgroundColor = [UIColor clearColor]; }
You can also do this wherever you instantiate your UISearchDisplayController. In my app I was doing this in my UITableView viewDidLoad method and was matching the styles between the two tables:
- (void)viewDidLoad
{
[super viewDidLoad];
self.tableView.separatorColor = [UIColor blackColor];
self.tableView.backgroundColor = [UIColor grayColor];
self.tableView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
searchController = [[UISearchDisplayController alloc] initWithSearchBar:searchBar contentsController:self];
searchController.delegate = self;
searchController.searchResultsDataSource = self;
searchController.searchResultsDelegate = self;
searchController.searchResultsTableView.separatorColor = self.tableView.separatorColor;
searchController.searchResultsTableView.backgroundColor = self.tableView.backgroundColor;
searchController.searchResultsTableView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
}