ScrollView is missing constraints - ios

Swift 5/Xcode 12.4
My app uses a UIScrollView to zoom its child UIImageView (which is filled through code). This part works but the ScrollView keeps complaining in XIB that it's missing constraints for the x/y position or width/height.
As you can see, the ScrollView has a top, leading and trailing constraint and the width is set to equal the height. From my understanding it knows its dimensions and position because of these constraints but apparently it's not enough. I do NOT want to center the ScrollView vertically and as the app has to support both iPhones and iPads, I also can't just set a fixed "bottom space to" constraint for the ScrollView.
I already tried to set the ScrollView's width to the ChildView's width and center it horizontally in it but the warning still didn't go away.
I've seen suggestions to put the ScrollView's contents inside another UIView but in my case it's only a single image and if I embed it inside a view, then the zooming breaks.
Why is the ScrollView still missing constraints and how do I fix it (without changing the overall layout of this ViewController)?

A UIImageView (without an image) has no Intrinsic Content Size.
If you're going to be setting its Width and Height constraints via code, but you want to get rid of the IB layout complaints, give the image view a Placeholder:
Edit
If you want the view(s) to be sized in IB, but you're going to change the constraints at run-time, you can either:
Connect the constraint to an #IBOutlet and change the .constant via code (more problematic to change the multiplier if needed, so probably not the way to go)...
Or...
Give the view constraints in IB but set them as Placeholders by checking "Remove at build time":

Related

UIStackView within UIScrollView is cut off

I'm trying to use a UIStackView within a UIScrollView and I was hoping someone could point me in the right direction in creating the right constraints because I can't figure out what the problem is.
These are my constraints and ViewController structure.
So DestCont is a UIView that has a fixed height and ContentCont should take up the rest of the space, which could be (and is) larger than the screen so it should be able to scroll.
When I test it out in the simulator, I have the following problem. (Resized it so it would fit in the 2MB cap)
The green is the Root View and the black color is the ScrollView, as you can see, it cuts off the bottom portion of the ContentCont view.
EDIT
I changed the constraints, removed the fixed UIStackView height, but now, it doesn't show the bottom UIView that's in the UIStackView:
From your screenshot we know that you have set the StackView's height constraint equals to the self.view's height. Then the height is fixed(equal to one screen's height), even though its content view's height may be larger than the screen.
And UIScrollView will calculate its contentSize depending on its content, so in your case its contentSize's height will always be one screen heigt.
Delete this height constraint, let the ContentCont's content decide the height of it. Also please make sure your constrains in your ContentCont are correct.
I ended up with being fine that just my "ContentCont" UIContainerView will scroll and fixed the switching by using the following tutorial: https://spin.atomicobject.com/2015/09/02/switch-container-views/.

Basic Auto Layout - nested width and dynamic height

Simple goal, but it demonstrates situations where Auto Layout gives me a headache. I want to have a stack view with a width of 256pt and a dynamic height based on layout (I shouldn't have to manually specify the height).
Inside it should be an image view sized 64pt x 64pt, which should also be centered horizontally as well as constrained 8pt from the superview's top. Note that the image view isn't the only child, hence why the stack view's height must be sized dynamically.
Auto Layout now tells me there's a conflict between the 256pt width constraint of the stack view and the 64pt width constraint of the image, as well as some mysterious "leading = Image.leading" and "trailing = Image.trailing" conflict which I can't even delete nor find.
Am I missing out something here regarding Auto Layout? I expect all logic to be contained in the interface builder, so no code should be required.
Running Xcode 9.1
Layout image
There is nothing to confuse. iOS clearly telling you the issue.
StackViews take size based on the size of child components (this is called implicit size) unless its been overriden manually as in your case which is 256pt.
Because stackView is just a container for multiple childViews stacked either horizontally or vertically, now because you have added only one imageView to it, it adds the leading and trailing constraint to it which makes absolute sense because you added a single view to the stack of view's , now what should stackView do? stretch childView (in your case imageView) to its own size.
But then you did not allow it because you added width constraint to imageView now when it tries to increase the imageView's width imageView's constraint wont allow it.
Hence it is complaining that there are too many conflicting constraints. Thats all :)
some mysterious "leading = Image.leading" and "trailing =
Image.trailing" conflict which I can't even delete nor find.
You cant delete them because, imageView is the only view inside stackView. Because there is only one child view to stack, stackView will start from left side (leading) to right side (trailing). Because now stackView has its own width it tries to change the width of imageView to reflect the same! But images width constraint prevents it from happening.
What are you trying to achieve with imageView added to stackView. If there is only one view in stackView, adding stackView does not make any sense. Reconsider what you are doing.
Finally, when you have only one childView in stack view, adding horizontal center does not make any sense (no matter vertical/horizontal stackView).

UITextView not visible on UIScrollView

Ok, so what I have is a UIScrollView that is constrained to all four sides of the main view, centered both vertically and horizontally, and set to have equal width and height to the view. All of the subviews that I put on top of the UIScrollView are showing up when I run the app, exactly where I want them to be, but only the UITextView at the bottom is not. It seems like I've tried every combination of constraints but it never appears when I run the app regardless of what I do. Here is a screenshot of the constraints in the interface builder:
And even when I preview the file Main.storyboard before running it looks like this:
But when I actually run the app, the screen is missing the UITextView, even when I alter the constraints in a number of ways:
Any help with this problem will be greatly appreciated! Thanks in advance.
Avoid putting all your subviews directly inside the scrollView. The autolayout will break apart.
You need to :
Add a UIView inside the UIScrollView, with constraints 0-0-0-0 to leading-top-bottom-trailing to the UIScrollView, and put all your subViews inside that UIView.
After that, you need to set the contentSize of your UIScrollView by code.
Also, you can:
add missing constraints to see what is missing.
The left panel in UIStoryBoard (Document Outline), you can press the red arrow showing up to see what is missing or conflicting.
Check out Apple documentation for more details.
If you want your scrollView only scrolls vertically you shouldn't set its height equal to its superView so remove it and just set the width to its superView and then it should calculate the height based on the subViews inside it
I offer you to drag a UIView in your scrollView and set the constraints to its four sides, and name it containerView , then set its width equal to background view and start laying out your views inside it not inside the scrollview :)
If Height of all views in the scrollView is clear, it can infer the scrollView's height
in this case you can set a fixed height to your containerView like 800 to get rid of the red lines and check how it works :)
I have noticed some clues you might have to solve which could probably solve the issue. Since the scrollView is extend by its content's elements, you have to explicitly deal with each element in the scrollView:
For imageView on the top is not well constrained, you need to give it a width or aspect ratio. Fix the imageView issue might solve textview height problem, even it's not still is a good start.
TextView bottom anchor is equal to scrollView bottom anchor, but you have to know textView is also kind of scrollView. So it's not reasonable to constraint each other at same time. Because both of them don't have explicitly height. You can try to type some words in the textView which will at least give it height by its content, then the scrollView can detect the textView bottomAnchor. You might see something then.
Your scrollView's height is equal to view's height is also weird, scrollView shouldn't constraint its height at first. Because it can't be "Scroll"View anymore because it's height is constant. you should let its width equal to view, and let the height be decided by its element's height. Then it will be literally a scrollview.
Hope it helps

dynamic height of of scrollview subviews in autolayout ios

I am creating a UIScrollView from xib, in which 3 view are there 2 UIViews and in middle an UIImageView. when I am setting constraints Xcode asked to set Y position constrains. But the problem is Y position constraint is blocking Scrollview to scroll down and automatically adjusting the views which looks ugly in landscape mode.
when I am delete that constraint it ask to fix height of subview. I searched a lot but I am new in autolayout so not understanding many of solutions. any help would be great.
You have to set all the height constraints in the content view.
But you also want the height of the Content to be proportional to the screen size.
To do this assign the height constraint of the imageview [equal|proportional|a-computation-of] to the view containing the UISCrollView.
It seems weird to skip levels of herarchy when assigning constraints between two views whose are not direct ancestor/sibling of each other but within a scrollview (at least) it is perfectly acceptable.
You are basically telling the scrollview that it's content has a known size and at same time setting this content to adapt dinamically to the screen size (if the constraints of the root uiview are set correctly)
UIView1
|---UIScrollView
|---UIView2
|---UIImageView [heightConstr.constant=UIView1.height-UIView2.height-UIView3.height-margins]
|---UIView3
This is the basic idea, to be done programmatically, then you can explore other solutions.
Unfortunately the constraint system in ios pretty much sucks when it's up to more complex equations involving more views for a single constraint.
UIScrollViewcan be tricky when adding constraints. You should always add a subView that will behave as the content view for your UIScrollView and all your subsequent views will go inside this content view.
UIView1
|---UIScrollView
|---UIContentView
|---UIView2
|---UIImageView
Set your UIScrollViewconstraints as you would normally but set your content view to have leading, trailing, top and bottom to the UIScrollView but also add two more constraints which will be equal width and equal height to the viewController.view but will have a low priority (So that whichever direction your content will increase in, that constraint will break and automatically increase the content size of the scroll view by taking in the inferred height of the content view). Now go on and add constraints on all your subview as you normally would. Which i'm assuming would be:
Your topmost view will have top and leading and trailing to its superView and also a fixed height.
Your bottom view will have leading, trailing and bottom to its superView and also a fixed height.
Your UIImageViewwill have a leading, trailing and top to top most view and bottom to the bottom view.
Edit:
Here is the screenshot just in case (To show the view hierarchy with the content view's constraints in the inspector)

UIScrollViews subviews not resizing themselves on Portrait to Landscape Orientation Change

In my app, I have a hierarchy like Main view -> UIScrollView - > UISearchBar. The search bar covers the whole width of screen. But when it switches to landscape the scrollview adjust itself according to landscape and cover whole screen but its subviews like UISearchBar width remain same as in portrait. Plus I'm using Autolayout and I've correctly set their constraints (Leading and Trailing, width (greater than equal to 320) etc) in storyboard.
Also I know there are several answers for this in SO but almost everyone is saying set width again in willAutororate. But I have around 15 subviews in UIScrollview which I think is not possible to set programatically (as increase LOC) plus I think Autolayout must have some solution to it.
Scrollviews don't play very well with constraints. Here's an approach using constraints and Interface Builder that worked for me for having a vertically scrolling scrollview that doesn't require any manual or content size finagling and works with rotation:
Scrollview in a view controller positioned with constraints
A container (UIView) that is a subview of the scrollview positioned with constraints pinning each edge to the superview
Add all your additional subviews to the container view instead. Use constraints. Exceed the height of the scrollview to get a vertically scrolling scrollview.
There is one trick however to get rotation resizing to work automagically:
You have to add an additional constraint to the container view to match its width to the UIScrollview's width. It's strange that you have to do this, since pinning each side to the scrollview should do the trick, but alas it won't work with rotation if you don't add the additional constraint.
Here's what I mean:
try this :
this problem will solve by constraints only. I created a project and by using correct constraints its working fine for me ,
here I am going to show you how to add correct constraint one by one :
add scrollview and add constraints for scrollview only like in the screenshots :
2. now add search bar and add constraints for search bar too,
here below you can find out complete constraints for scrollview and search together:
You could use UIViewAutoresizing mask (autoresizingMask property) of your subviews.

Resources