I have a view controller that consists of two UIViews. One view is the super view and the other is a subview. Both views are the same size 320X568 and have the same origin (0,0). I added constraints to the subview by first setting an aspect ratio to itself, then an equal width ratio to the superview with a multiplier of 1. I then centered the subview horizontally and vertically in the container. When an up drag gesture is recognized, the subview is suppose to move up a certain amount using CGRectOffset. I noticed that the view wasn't ending in the right position, so I removed all the offset code to see what was going on. In viewDidLoad I check the origin.y of both the super view and subview and its 0 - which is correct. However, once the up drag gesture is recognized, I do another NSLog for the y origins and the subview prints -31.5 and the superview prints 64. Not sure how this is happening with all the CGRectOffset commented out. I'm thinking this might have to do with the navigation bar but I'm not sure.
I don't know what the deal is with the CGRectOffset, but I do know what the "problem" is without it. There's no problem! The only thing here is that you are checking the origin.y of the views too soon, namely in viewDidLoad.
Remember, in viewDidLoad nothing has actually happened yet. The view controller has a view but that's all. In particular, the view is not yet in the interface and has not been given its layout yet.
So it's really just a matter of knowing what the events mean. You're assuming that viewDidLoad means the view is in the interface and has its position and size. It doesn't mean anything like that. If you want to know what the view's position is after layout, you need to wait until after layout. Like, viewDidLayoutSubviews is a good place. It means that layout has just occurred!
As for the 64 value, it's just what you would expect. You have pinned your view's top to the top layout guide - which means the bottom of the navigation bar, exactly as you have suggested.
Related
This is what I'm trying to do...
I have one view controller that needs to dynamically display different subviews based on the presence of some data.
Here is a simple mockup. Each colored block represents a unique subview.
Sometimes the green block needs to be at the top, sometimes the green block won't display at all, sometimes the light blue block will be something different, etc.
Each subview has interactive elements, so I've been creating and adding them like so:
Defining a new view controller
Defining its view
Calling addChildViewController and didMoveToParentViewController
Calling addSubview on myNewViewController.view
Using SnapKit to make auto layout constraints to position the view
I want to transition to UIStackView because it seems a good support system for this view because all I need to do is stack its subviews. I'm seeing many conflicting constraint errors and unexpected view frames when trying to add subviews with their own inner auto layout constraints.
Question
Am I setting myself up for failure here by embedding the views of 4-6 view controllers in the view of one view controller?
Also, how do I give the added views properties like minimum heights or content sizes without seeing many breaking constraints with UIStackView? (So they can stack, but one of them is say, 400 tall, and the other is 200 tall)
Answer
You can absolutely do this using UIContainerViews combined with UIStackViews and UIScrollViews, it's a complicated setup so here's a starter project to get you started:
https://github.com/Rnorback/ScrollingStackView
Here's what that project looks like:
You want the containers to have different sizes. In order to do that, simply add height constraints to the containers with Autolayout. If you want to change the height of the scrolling. Then you'll need to change the height constraint of the UIStackView.
Brief Explanation
When creating this setup, you have to make sure the UIStackView distribution setting stays in fill. That way you can set height constraints on UIContainerViews.
When setting up anything in a UIScrollView you have to make sure that the object is pinned to the edges of the scroll view and has a defined width and height, otherwise the scrollview will throw a constriant error. I think of it like the scrollview tries to press in on all sides of your content view and if any side gives, the scrollview won't be able to present it properly.
Hope this helps.
Within a container view, I have a subview constrained to 8 pixels from the top/bottom/left/right of viewController's view. There is a button that adds an (non-autolayout) view inside of it, and another button that causes an (autolayout) view to expand below it. When the view loads, everything is as it should be, but as soon as either of the two buttons are pressed, the view in question shrinks another 8 pixels or so in width.
I've tried calling layoutIfNeeded() at a couple points in the script, but that hasn't worked. Does anybody know what might be going on here? Is there some conflict because I'm mixing autolayout with non-constrained views?
After messing around with it for a couple of hours, I found that changing the way the view was constrained in IB fixed the problem.
I don't understand why this worked, but incase anybody else ever runs into a similar problem, instead of constraining the left/right to container view, try constraining the width of the view to be equal to the container view (minus something if you want) and add a center in container constraint.
I am having a very frustrating issue. I know there are all kinds of issues with UIScrollView in iOS7 and XCode 5. I need to implement a scrollview and there are all kinds of tutorials showing you how to do it by switching off auto layout but that then messes with the rest of the views in my app.
I tried the fix of putting my subviews into a container UIView and placing that in the UIScrollView and setting the scrollview's content size to the size of the contained UIVIew. That didn't work. Now I am working with placing everything in the scrollview and it all works with one exception. When I load the view on the simulator or a device the content view is moved down but somewhere around 60 points or so. See image below.
That white space below the title bar on the right is still the scroll view as I can press and drag within it. Adjusting the contentOffset doesn't do any good as that just scrolls the view down slightly. I have no idea what to do here.
Just a little more info: I setup the scrollview and all the subviews in storyboard and the connected them up. Not sure if that has any bearing on it.
Thanks in advance for any help you can provide.
I think your Scrollview top space constraint have 64 pixels. That's a problem. So, set your top space constraint value to 0.
You need to add the constraints before view displayed then contentsize will be set automatically.
Check UIScrollView's autoresizing mask. It has to be set like this.
I can't figure out how to correctly position subviews in a Navigation Controller.
I am trying to position a view, table and another view.
If I turn off AutoLayout than top view and table are ok but my bottom view is pushed off the screen.
With autolayout I get both the table and bottom view in the wrong place:
I try to set frame in viewDidLoad as follows (calendarPicker is position at the top below navigation bar), I want the configPanel to be on the bottom, I hide bottom bar on Push.
self.eventsTable.frame = CGRectMake(0, CGRectGetMaxY(self.calendarPicker.frame),
self.eventsTable.bounds.size.width,
self.view.bounds.size.height - self.calendarPicker.bounds.size.height
);
self.configPanel.frame = CGRectMake(0, self.view.bounds.size.height,
self.configPanel.bounds.size.width,
self.view.bounds.size.height - self.configPanel.bounds.size.height
);
Should I rely on autolayout? How should I make my constraints?
I believe my problems arise due to autosizing of the table mostly, but given that I am setting its frame size why would it not change? I do not want to remove auto layout since it is used on other views designed in the storyboard and from what I understand it applies to all?
Is there something that I am missing that needs to be done on top of setting the frames of individual controls?
EDIT:
I think my biggest problem is autolayout and inability to size table appropriately. If I add constraint to the bottom view to be 0 from bottom of the view, it will originally appear correctly. However consequently when resizing table and top view, the table will push bottom view down sizing itself to occupy all available space.
I need to force UITableView to be no more than height between the bottom of the top view and lower view, but still not sure how to do this.
Somewhat closer
Removing code for frame change of the table fixes the issue of the bottom view being pushed off. However in this case top view overlapps table when it changes size at the same time not being drawn correctly:
Uncheck autolayout and then set frames of all three subviews.
Or
If you want constraints then you can use NSLayoutConstraint class to add constraint to your subviews.
I recommend against switching off autolayout, especially because you can't do it on a view by view basis. Autolayout is a must if you tend to do i18n or want to make sure your app does well in different screen resolutions/orientation.
Try This!
disable use Autolayout in storyboard. Place your three views on view controller(view1, view2, view3). Next go to size inspector and use autosizing masks for all three views. Check this, which will help you
http://www.raywenderlich.com/50317/beginning-auto-layout-tutorial-in-ios-7-part-1
I have a containing view called containerView which is a UIView. When the app starts, it's just that view. During the course of the app's execution, I want to swap two "full-size" sub views in and out of the main containerView.
My question is, how do I make sure that the sub views fill up the entire containerView regardless of the orientation of the iPad. The containerView is 300 wide, but the height varies based on orientation.
I've tried:
setting the frame of the subview's from viewDidLoad, viewWillAppear, viewDidAppear directly equal to the side of the containerView frame,
creating LayoutConstraints that force the subview to conform to the containerView's proportions from viewDidLoad, viewWillAppear, and viewDidAppear. The question here is when to apply these constraints, and since the view is removed periodically, when to reapply the constraints.
I don't know what the idiomatic approach is and I want my code to be maintainable and reusable. Am i approaching this the wrong way? Is there some other way to make sure a subview fills up its containing view?
Example Code:
https://gist.github.com/Sahasrara/6817105
You should set the frame size in viewDidLayoutSubviews. By then all the autolayout nonsense has occurred.