Unexplained margin in Auto Layout - ios

Pretty simple really. I've got a yellow scrollView that contains a blue view. In the xib, I've set the blue view to totally fill its parent (the scrollView), by matching all their borders with 0 offset:
And yet, here it is at execution:
At this point, I've stripped down the code to its strict minimum to isolate the cause of the error, and I'm left with nothing left in my code. I tried setting translatesAutoresizingMaskIntoConstraints to NO and calling layoutIfNeeded for all views, it doesn't change anything. Do you guys have any idea where this space on the top comes from?

The contentInset is affected by the (height of the) navigation bar.
Try setting self.automaticallyAdjustsScrollViewInsets = NO;
This can also be set in the storyboard with 'Adjust Scroll View Insets'.

Related

UIImageView resizing issue in UIPageViewController

I'm building a new app and wish to have a "Welcome walkthrough" at the beginning wherein I have a storyboard with a series of images presented in a UIPageViewController. I have it loading the images and all of that just fine, however the images are resized whenever they go beyond being the "previous" or "next" ViewController. I am using Swift to develop.
Here is a video of the issue: http://youtu.be/dXcjjT-8Bk0
I have tried all of the different View Modes (Aspect fit, aspect fill, redraw etc.) and they all behave the same.
I am using Auto-Layout + Size Classes as I wish to simplify the development for different screen sizes. The current constraints I have that make the UIImage appear at the right size are:
Align Centre X to Superview
Top Space to Top Layout Guide
Bottom Space to Bottom Layout Guide + Equals: 50
I am currently using Aspect Fit which gives me the correct image (after they have done their 'resizing behaviour'.
Can anyone guide me further as to how to fix this?
From your video, I noticed that your UIImageView is always "resized" at the top, not at the bottom. This is most certainly because of your autolayout constraint you call "Top Space to Top Layout Guide". While your UIImageView's view controller is being transitioned through your scrolling page view controller, it doesn't know where the top layout guide is, so its topLayoutGuide.length is 0. Only after the animation completes does the view controller get a positive value for topLayoutGuide.length. Yes, the page view controller should be a bit smarter than this, but it's not.
You can either stop using the top layout guide and make an autolayout constraint relative to the top of its superview. Or you can continue to use the top layout guide but account for when it's length is 0. You can do this by making an outlet for your storyboard's NSLayoutConstraint and overriding viewWillLayoutSubviews() in your ViewController containing your UIImageViews:
#IBOutlet weak var topSpaceToTLG: NSLayoutConstraint!
var parentTLGlength: CGFloat = 20
override func viewWillLayoutSubviews() {
if self.topLayoutGuide.length == 0 {
// Lengthen the autolayout constraint to where we know the
// top layout guide will be when the transition completes
topSpaceToTLG.constant = parentTLGlength
} else {
topSpaceToTLG.constant = 0
}
}
This will always put the top of your UIImageView at the top layout guide, assuming that the status bar is always 20 points. Before laying out subviews, it will check to see if the top layout guide length is 0 or not and adjusts your autolayout constraint accordingly. After the transition animation completes, layout is triggered again, and the top layout guide length will be the expected value, so the constraint constant can go back to 0. Even better than hardcoding the value is to pass in the parent view controller's exact length during initialization, accounting for any possible changes to the top layout guide like adding a navigation bar.
From the video I think you could solve this by preventing the UIPageViewController from extending under the top bars.
In xcode you can do this using the attribute inspector for the page view controller by deselecting Extend Edges Under Top Bars.
This should prevent it paging in under the status bar I think helping to avoid the switch you see.
I figured out my problem was that when the view controller began animating the Top and Bottom Layout Guides had no height. The right and left margins didn't either. When the view finished animating they all received a height or width and my view resized itself.
I fixed this problem on my project by adding vertical constraints between my objects and their super view instead of to the Top/Bottom Layout Guide. I also had to change my horizontal constraints to ignore the side margins.
The last issue I came across is that I had to account for the status bar myself. It may or may not be there or it could be a double bar, like when you are using Maps.

navigation bar possibly causing UIView offset

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.

UIScrollView offsetting content in contentView

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.

AutoLayout or not? How to position 3 subviews?

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

Remove unwanted ios7 padding

iOS7 adds padding (64px) for the status bar. Therefore when using a Scrollview there is a big camp between the scrollview and the navigation bar. I tried:
self.automaticallyAdjustsScrollViewInsets = NO;
Which does remove the unwanted padding - however the scrollview no longer scrolls.
Is there another way?
* update **
I discovered a quick fix. I was lining up the scrollview and y origin= 64px in the storyboard instead of 0. I put my scroll view to 0px (the navigation bar then covered 64px of my scrollview) and when I ran it on the simulator it was aligned as originally intend ... a bit of a hack tho. I'm looking for a solid solution however.
On your XIB/Storyboard for your view controller, make sure to uncheck the Adjust Scroll View Insets. You may also need to uncheck Under Top Bars and Under Bottom Bars:

Resources