I'm creating an UIViewController with a subview that has the same width as the super view and half the height of the super view.
Here is how it looks in the storyboard:
These are the constraints I added vor the View Punkte:
Plus I added the "Equal Height" constraint.
The constraints work correctly. The subview stays the same when I rotate the device.
But the problem are the frame sizes.
When I print the sizes of both views, that's what Xcode returns (The code is inside ViewDidLoad:
print(self.view.bounds) // returns --> (0.0, 0.0, 375.0, 667.0)
print(viewPunkte.bounds) // returns --> (0.0, 0.0, 600.0, 300.0)
Why is this happening? The width of the viewPunkte is not correct!
What is the solution to this problem?
Thanks.
If you are inspecting the frame of a view during viewDidLoad then you are probably doing so after the views have been initialized but before they have ever completed a layout pass. Your controller's view has not yet been added to the window and you should not assume that the frames of any of your views reflect what their final sizes will be.
Consider why you think you need to inspect view frames at this point in time.
Usually, the size of view controller's view in storyboard is not equal to simulator.It's square in storyboard but iOS devices are not in square shape.
It seems that you run your project in an iPhone/iPhone simulator
therefore:
self.view.bounds = iPhone screen size(pt) = (375.0, 667.0)
and you set up the height and width constraint of your 'viewPunkte', which are equal to the constant 300 & 600.
thats why the size of viewPunkte is constantly equal to (600.0, 300.0)
You can use
-(void) viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
//NSLog dimensions.
}
This should give you the correct dimensions since this event means its view has just laid out its subviews.
This is fired after viewdidload and before viewDidAppear. Orientation change can also fire viewDidLayoutSubview.
Related
I have a single view application (see below layout). The layout was done using iphone x. I have a central UIImageView that is within the safe area along with a custom bottom UIView that has some UIButtons. When I run the application on a iphone 6 plus (which does not have a notch) and run the code below, I get back a frame for the UIImage view that is larger than the screen dimensions AND the frame has a top inset of 44. I do not understand how this is possible?
override func viewDidLoad() {
super.viewDidLoad()
print("self.imgPreViewOutlet.frame: \(self.imgPreViewOutlet.frame)")
print("self.imgPreViewOutlet.bounds: \(self.imgPreViewOutlet.bounds)")
print("UIScreen.main.bounds: \(UIScreen.main.bounds)")
}
Console:
self.imgPreViewOutlet.frame: (0.0, 44.0, 414.0, 758.0)
self.imgPreViewOutlet.bounds: (0.0, 0.0, 414.0, 758.0)
UIScreen.main.bounds: (0.0, 0.0, 414.0, 736.0)
Layout has not yet happened in viewDidLoad. The size you get there is meaningless. Ignore it. If you want to know how big the image view will really be, wait until later in the birth cycle of you view controller, such as viewDidLayoutSubviews.
I am designing an iOS app in a landscape orientation. My typical workflow is to use a XIB with universal layout for each view controller. A few view controllers additional programmatic view setup. For this additional setup, I need access to the XIB's subviews final frames before they are drawn on screen.
Example: I have a XIB with one subview that takes up a portion of its parent view. Here is a print out of the subview's frame in the viewDidLoad, viewWillAppear, and viewDidAppear methods..
viewDidLoad:
- width : 535.0
- height : 600.0
viewWillAppear:
- width : 535.0
- height : 600.0
viewDidAppear:
- width : 671.0
- height : 414.0
origins are all (0,0). The additional view setup needs to be done when the subview's width and height is 671.0, 414, but before it is displayed. It should also be noted that (535,600) is the width and height of the subview in the XIB.
Auto layout will call back to your view controller's viewDidLayoutSubviews. After a pass of the layout engine. This method may be called more than once. By the end of the last call, all of your view controller's subview's frames will be set and pixels will be pushed to the screen.
I'm looking to do the following, see the 2 pictures below.
I have a UICollectionView and a UILabel on top of it (the green area).
I would like, when scrolling down, to decrease the height of the collection and increase the height of the UILabel scrolling up (similar with what safari does on iPhone with the search bar when scrolling up and down).
What I've tried is the following:
func scrollViewDidScroll(scrollView: UIScrollView!) {
collectionView.frame=CGRectMake(0.0, collectionView.frame.origin.y-1, 375, collectionView.frame.height+1);
}
It's starting ok at first, the height is increasing, but suddenly the height of the UICollectionView gets smaller and then starts increasing again. And then it does the same
Here below I've displayed the results of print(collectionView.frame)
Is there a bug in my solution ?
Is there another way to achieve that ? Is something related to constraints ?
Thanks.
C.C.
(0.0, 174.0, 375.0, 493.0)
(0.0, 173.0, 375.0, 494.0)
(0.0, 172.0, 375.0, 495.0)
(0.0, 190.0, 375.0, 477.0)
(0.0, 189.0, 375.0, 498.0)
(0.0, 188.0, 375.0, 499.0)
(0.0, 187.0, 375.0, 500.0)
Add height constraint to your label or collectionView. Create an IBOutlet for that constraint and then change it in scrollViewDidScroll using the contentOffset as suggested by Michal.
The proposed solution in your scrollViewDidScroll is omitting the direction of the scroll - basically you are saying: move the collection view up and increase its size whenever the user scrolls. But you are not saying whether it's up or down. I handle the direction by saving the last scrollView's contentOffset.y and then doing simple if:
if self.lastScrollViewContentOffset > scrollView.contentOffset.y {
// mumbo jumbo when scrolling up
} else {
// mumbo jumbo when scrolling down
}
Also mind that this method is one of two that you should use to make it smooth and continuous. This method is called after the scrolling has happened:
The delegate typically implements this method to obtain the change in content offset from scrollView and draw the affected portion of the content view.
But if you drag only half way you may find yourself in inconsistent state (I know this because I implemented similar thing), so also implement delegate method scrollViewDidEndDragging where you need to bear in mind that it may not decelerate and thus you'll need to add additional animation to make the UI consistent.
How to create ScrollView with AutoLayout in Xcode 6.3. While I create the scroll view it takes 600X 600 screen and doesnt change the view size according to the screen orientation. What is the best waay to acheive the ScrollView with AutoLayout . I have following code inside ViewDidLoad
[mainScrollView addSubview:contentView];
[mainScrollView setContentSize:CGSizeMake(320,800)];
contentView.frame = CGRectMake(0, 0, [Util window_width], 800);
I have following Nib file as shown below
I have got the contentview
UIScrollView is placed over UIViewController
Give the scroll view spacing constraints to all sides of the controller's view, then it will be whatever size the screen is.
You should never just drop a view into a controller without adding your own constraints when you're using the wAny hAny size class; the system will add constraints for you, and they will be origin at {0,0}, and width and height of 600 (assuming that you made the view full size) which doesn't correspond to any actual device.
I'm building an iPad app with views that are split horizontally and animate in from the top and bottom (think of jaws sliding closed and open to appear and disappear respectively).
My problem is the layout of the custom jaws subview is broken only when the view loads in a landscape orientation. (The jaws-view container loads at the proper size, but the subsequent subviews for the top and bottom half are too tall, and going off the screen. They are the correct width though.)
I can start in portrait and then rotate and everything is arranged correctly.
I've tried setting the frame of the new view to the bounds of the original in a bunch of places (as suggested by many answers that didn't work for me, links upon request) but either haven't found the right spot, or need something more.
Do I need to do anything special to get the size to propagate? Is there a point before which I should not do animation? (I'm trying to move the top and bottom in my new view controller's viewDidLoad.)
The solution to this required 2 parts.
The first was described in this answer:
https://stackoverflow.com/a/8574519/1143123
which describes using viewWillAppear method instead of viewDidLoad (called earlier and "incorrect" values for bounds). This solved the problem of the view being layed out properly when loading that view in landscape (and propagated to subsequent rotations).
The second part was that the view could still get messed up if I started animating it and then did a rotation in the meantime. I changed my animation class to only move the center coordinate (as opposed to sliding the frame) which would have been better in the first place, but that didn't solve it. In the end I hardcoded the following in the ViewController for the class exhibiting these issues:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
[super didRotateFromInterfaceOrientation:fromInterfaceOrientation];
// The container view should match the size of the current view
gameView.frame = self.view.bounds;
CGFloat width = self.view.bounds.size.width;
if(roundInProgress) {
gameView.jawsTop.frame = CGRectMake(0, 0, width, self.view.bounds.size.height/2);
gameView.jawsBottom.frame = CGRectMake(0, self.view.bounds.size.height/2, width, self.view.bounds.size.height/2);
} else {
// If round not in progress, game cards should be offscreen
CGFloat height = self.view.bounds.size.height/2;
gameView.jawsTop.frame = CGRectMake(0, -height, width, height);
gameView.jawsBottom.frame = CGRectMake(0, self.view.bounds.size.height, width, height);
}
}
Without seeing your code my guess is that it has to do with the "Autoresize Subviews" property of your parent view and/or the autosizing set-up for your subviews. Try changing that property in Interface Builder to see if that fixes your issue.