UITableView frame size strange behaviour - ios

I try to set frame size to my table view programmatically after viewDidLoad:
[_tableView setFrame:CGRectMake(0, topHeight,
[[UIScreen mainScreen] bounds].size.width,
[[UIScreen mainScreen] bounds].size.height - topHeight)];
Default size is 200x200 with origin Y 100:
Scene hierarchy:
Implementation of UITableView shows when setFrame was called:
#implementation MainTableView
- (void)setFrame:(CGRect)frame {
NSLog(#"setFrame: %f %f", frame.size.width, frame.size.height);
[super setFrame:frame];
}
#end
All is fine but table's frame resizes to default when I press any cell without printing log messages from setFrame. Small explanation video: http://youtu.be/JUW_rHvCS2I
I don't understand why my table size becomes default (200x200) after cell click. Even if I try to set size inside viewWillAppear (after return from cell detail view) it doesn't work.
Any ideas?

I can't really tell why your tableView isn't resizing properly since you haven't provided much code to look around. Though I recommend setting some constraints or resizing rules for the tableView, probably something like this:
http://i.imgur.com/N9fvvIB.png (if not using Auto Layout)
http://i.imgur.com/3Uz8e5e.png (if using Auto Layout)
Now if you really need to make this work only trough code I suggest throwing up some NSLog's containing the tableView's frame width and height before and after setting it up.

Try _tableView.translatesAutoresizingMaskIntoConstraints = NO.

Related

iOS part of viewcontroller goes black when orientation changes

When I change viewcontroller orientation while it's loading on particular orientation, part of the screen goes blank at the bottom.
Steps to reproduce:
Have tableview(Not necessary I think. could be any view) in a view controller
Push a new viewcontroller which also has a tableview(Not necessary I think. could be any view) during
an action
Rotate the screen from one orientation to Another(Portrait to landscape or landscape to portrait).now you will be able to see the dark part.
Press back button to pop the current viewcontroller
Now rotate from one orientation to Another(Portrait to landscape or landscape to portrait).now you will be able to see the dark part here as well.
The bottom part of viewcontroller goes black.
I am able to reproduce 7 out of 10 times.
FYI:
My Viewcontroller has only tableview that's all and all cells has autolayout constraints.
Trying to understand why it happened and I would like to fix it.
More details on reproducing the issue:
Basically you can reproduce this issue only if you hold your device in slanting position and either push or pop a view controller and while the page is trying to load , you have to change the orientation then the issue happens.
(Pun intended.... lol )
In other words ,you have to tilt you device as if you are steering the wheel :).
This issue can only happen if you use your device like a steering wheel :)
In your viewWillTransition method call layoutIfNeeded()
Try to reset the layout of TableView after rotation by using this method,
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
tableView.layoutIfNeeded()
}
or
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
tableView.layoutIfNeeded()
}
I also experienced the same issue.
My view controller had just one tableview and when we tilt , I mean change the orientation during a navigational push or pop this used to happen.
Try setting the frame
in viewDidLayoutSubviews
-(void)viewDidLayoutSubviews{
CGRect screen = [[UIScreen mainScreen] bounds];
CGFloat width = CGRectGetWidth(screen);
CGFloat height = CGRectGetHeight(screen);
CGRect frame = self.tableView.frame;
// To check if there's any mismatch between the sizes of screen and tableview then set the tableview frame same as screen frame.
if (CGRectGetHeight(frame) != height && CGRectGetWidth(frame) != width) {
self.tableView.frame = CGRectMake(0, 0, width, height);
}
}
or try setting the frame in viewWillTransitionToSize
-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator{
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
CGRect screen = [[UIScreen mainScreen] bounds];
CGFloat width = CGRectGetWidth(screen);
CGFloat height = CGRectGetHeight(screen);
CGRect frame = self.tableView.frame;
if (CGRectGetHeight(frame) != height && CGRectGetWidth(frame) != width) {
self.tableView.frame = CGRectMake(0, 0, width, height);
}
}
FYI:
if setting the frame self.tableView.frame = CGRectMake(0, 0, width, height); doesn't work then you could try [self.tableView layoutIfNeeded]
Set frame again in
viewDidLayoutSubviews
In one view controller(Parent the one that pushes new view controller) setting the frame at viewDidLayoutSubviews solves the issue in another view controller(The child view controller , one that's getting pushed) setting the frame at viewWillTransition fixes the problem :) But still I don't know why there's no universal solution to this problem.

Why is my UIWebView frame not resizing properly?

I did this exact same thing with a XIB and it works, but something is wrong with my storyboard version.
Here's my UIWebView Delegate code
#pragma mark - UIWebViewDelegate Protocol Methods
- (void)webViewDidFinishLoad:(UIWebView *)webView {
CGRect frame = webView.frame;
frame.size.height = webView.scrollView.contentSize.height;
_webView.frame = frame;
NSLog(#"Webview Frame height is %f", _webView.frame.size.height);
_scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width, _headerImageView.frame.size.height + webView.frame.size.height);
NSLog(#"scrollview content height is %f", _scrollView.contentSize.height);
}
NSLog is showing proper webview frame height of about 800 points. Scrollview content size is perfect about 1000 points.
My Scrollview is set to have a red background. So you can see here the webview frame is only about 500 points on screen and the rest of the content is getting cut off.
Any ideas? Thanks!
The problem is that auto layout is responsible for both the frame of the web view and the content size of the scroll view. You can set them, and of course if you then read them, you read what you just set; but you're just misleading yourself, because then (outside your method) auto layout comes along and sets them for real, and what you are seeing (as opposed to your meaningless NSLog readings) is the result of auto layout's settings. You need to configure your constraints properly so that auto layout does what you want it to do.
Auto layout wasn't turned on in the .xib file, so you didn't encounter this behavior. But it's turned on in your storyboard.

Dynamically resize UITableView in UIViewController created in Storyboard

In a UIViewController on a storyboard, I have a UITableView that is sized specifically to have two rows in one section with no header or footer, i.e. the height is 88.0f. There are some cases when I want to add a third row. So in viewWillAppear:animated: (and other logical places) I set the frame to be 44.0f logical pixels higher:
CGRect f = self.tableView.frame;
self.tableView.frame = CGRectMake(f.origin.x, f.origin.y, f.size.width, f.size.height + 44.0f);
NSLog(#"%#",NSStringFromCGRect(self.tableView.frame));
Nothing controversial; pretty standard resize code, and yet... It doesn't work! The tableView height doesn't change visually. The NSLog statement reports the height I expect (132.0f). Is this because I'm using Storyboards? I'm not sure why this isn't working.
Set an auto layout constraint for the height of the table view in your storyboard. Then connect the constraint to an outlet in your view controller so you can access the constraint in your code. Have the constraint be set to 88. When you want to change the height of the table view, just change the constraint's constant to 132.
You can modify the frame only after the call to layoutSubviews is made, which occurs after viewWillAppear. After layoutSubviews is called on the UIVIew you can change the dimensions.
As Gavin suggests, if you have the autolayout enabled you can add the constrains to the UITableView via storyboard, connect the height constraint and modify its value as follow:
constraint.constant = 132.0f
Otherwise if you have the autolayout disabled you can simply change the frame updating the height, but putting the code in a different method, for example viewDidLoad:.
recently I'm try to do what you've do. And I got same problem, tableview height won't change. Now I got the solution, you need to call layoutSubviews after change the frame. And it work on me.
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
tableView.frame = CGRectMake(tableView.frame.origin.x, tableView.frame.origin.y, tableView.frame.size.width, tableView.frame.size.height + 44.);
[tableView layoutSubviews];
}
don't place it in viewDidLoad or viewWillAppear: because even layoutSubviews is called, the frame won't change. place it on viewDidAppear:

Incorrect size of label on viewWillAppear

I have following setup
XIB file which has only landscape view. This view is connection to my controller
There is a label on this view which is connected to IBOutlet UILabel* label
This label is configured like this (it occupies the whole width of screen).
I overrided viewWillAppear and do this (to get the size of label).
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
CGRect rect = _labelTitleLand.frame;
}
The strange thing (which I don't understand). That it returns size = (width 768, height 21) when it launched in portrait (on iPad), which is correct.
And it returns size = (width 741 height 21) when it's launched in landscape. Which is weird. I anticipated that it will return width 1024, height 21 for landscape.
I was under impression that at the moment of viewWillAppear, all controls sizes are calculated already.
Update 1
If I check labelTitleLand.frame on viewDidAppear then it returns correct results. However, I don't like this, because I want to do some actions (based on this size) which influence how view will be drawn. In the case, if I will do it on viewDidAppear, as I understand there will be visible redrawing.
The layout of the view hierarchy has to be complete before you will get the actual final frames.
So you should check the frame in viewDidLayoutSubviews, which will still be before the view hierarchy is actually drawn. If you need to make changes here you can without causing any redrawing to occur.
viewWillAppear is too early because this is before your autoresizing masks (and/or autolayout constraints) have had their effect.
This seems a problem related to when a method is actually called at runtime.
I solved similar situation using
[self performSelector:#selector(checkMethod) withObject:nil afterDelay:0.1];
in viewWillAppear, and then:
- (void)checkMethod
{
rect = _labelTitleLand.frame;
}
This gives your app the time needed to set its own frame.
It is not so elegant and it looks like a workaround, but it is very effective.
You can also try to force the frame of the UIView that is container of the UILabel in viewWillAppear like this:
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.view.frame = CGRectMake(0.0f, 0.0f, 1024.0f, 768.0f);
CGRect rect = _labelTitleLand.frame;
}
But the first solution is more reliable and usually no lag is experienced.

How to avoid the resize of the UITableView (rotated) cells after the orientation change?

I am implementing the horizontal UITableView by rotating it by 90 degrees
horizontalShopsTableViewController.view.transform = CGAffineTransformMakeRotation(-M_PI/2);
and then rotating its cells back by 90 degrees:
cell.contentView.transform = CGAffineTransformMakeRotation(M_PI/2);
I want the table to have the flexible width. If I do not set it to be flexible, everything works fine after the orientation change. However if I do, the contents of the cells are misplaced and disappear. The flag "Autoresize Subviews" of the table view is false.
Any ideas what could be the causing problem or what alternatives could be used?
Ok, the problem was that since the width of the tableview was flexible, after the rotation the width of the cells (which is actual the height) were increased too. I overcame the problem by subclassing the UITableView and overriding the layoutSubviews method, so it looks like this now:
- (void)layoutSubviews {
[super layoutSubviews];
for (UIView* child in [self subviews]) {
CGRect frame1 = child.frame;
if ([child isKindOfClass:[UITableViewCell class]]) {
frame1.size.width = 120;
child.frame = frame1;
}
}
}
Anyway, I still don't understand why the uitableview was resizing its cells if I explicitly set the Autoresize Subviews to false.
uuuuh... what are you trying to achieve? the autoresizing system doesn't respect any transforms on views of course. Probably you have to resize it manually.
But can't you do what you want to achieve with a standard scrollview!? It's not the best idea to rotate UI components with transforms, as you are getting other problems.

Resources