Why do my controls get squished inside a scroll view? - ios

I'm building an iOS app and every time I use a scroll view and put other views and controls inside of it this happens:
How do I prevent this from happening? I tried putting the scroll view in a UIView and putting a UIView inside a scroll view and putting other controls inside of the nested views but the same thing still happens. Any ideas on how to fix this?

After you add something inside scrollView, it doesn't know what width and height it will have. Thus, it is unable to correctly display its subviews.
There are some major solutions:
You need to specify correct sizes AND distances both vertically and horizontally.
E.g. scrollView will have 1 label. Then you should specify something like this:
label 1:
leading = 20, trailing = 20, width = 100 (this will solve horizontal dimension)
top = 20, height = 100, bottom = 20 (this will solve vertical dimension)
Of course, labels are self-sizing. So if you specify the text/font/number of lines, you don't need to set fixed width and height.
You can add some view (if your layout allows that) which will take the whole width of the screen. In this case you set leading and trailing to 0, and instead of setting fixed width (which varies on different screen sizes), you need to center that view horizontally inside the scrollView.
This will solve the horizontal dimension.

Instead of using constraints use the autoresizing feature. The controls resize depending on the way they were placed on screen and what the settings on the Autoresizing is.
Autoresizing

Related

Design UIView so that it can dynamically change its height based on the content height

In a XIB file I have a CustomView related to a class with the same name.
The view content is quite simple.
There are a vertical stackview and inside the stackview there are two labels. The stackview is vertically aligned to the view that contains it:
The first label (title) contains a static text (always a few characters).
The second label (subtitle) can have variable length text.
I add this CustomView with other similar views as a subview of a Content View, as it was a “row”.
for i in 0...aViews.count {
var v = CustomView(frame: CGRect(x: 0, y: _y, width: 320, height: 100))
v.labelText = "my long label text ..."
contentView.addSubview(v)
// ...
}
As you can imagine, the title label should have a fixed position (top and left), that is, there cannot be a row with the title starting at 10 points and another at 14.
I must admit I naively thought the position of the label would have been automatically managed by the same fact that I aligned vertically the stackview. I was wrong and I noticed no problem at all, until they told me the second label, the subtitle, could contain more than one line.
I added lines to the label directly in the storyboard, and found out that:
the container of the stackview doesn’t change its height based on the height of its content;
the position of the “fixed” elements is maybe vertically centered but not fixed;
What I need is the following:
the labels should be “grouped” and aligned vertically: there should be the same amount of space from the top of the first label to the upper border of the container and from the bottom of the second label to the bottom border;
when the second label has to display more than one line, the container view should change its height accordingly;
Is this possible? How should I design my view?
OK - looking at your project, you're not far off... just a couple key items.
In your CustomView.xib, you had no constraint between Fixed Label and Date Label. The result is that the Date Label grows up from the bottom of the view, with nothing to stop it.
Also in your CustomView.xib, you had the Fixed Label constrained to the trailing edge... I assume you want it left-aligned with Date Label
When creating your CustomViews, you were setting a height constraint of 100 -- which defeats the purpose of allowing the content to determine the size.
In CustomView class, you had contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight] commented out. That line should be there.
In your view controller, you added a height constraint to contentView with a low priority. Best option is to make that a Placeholder constraint (double-click the constraint, and select the Placeholder checkbox). That way the constraint is removed at run-time, but is there during design (and Storyboard doesn't complain).
You were doing a few other un-necessary things - likely you were trying different stuff to get it to work.
The view setup (adding your views) is best done in viewDidLoad() -- definitely not in viewDidLayoutSubviews()
I'm guessing that, in your CustomView, instead of an explicit width of 200 you probably want to constrain the Date Label leading and trailing, allowing it to horizontally stretch based on the device width... but I left it at 200.
If you can follow that information, you should be able to fix the issue(s). But, I put the project up as a GitHub repo for you, so you can get it in a "working" state, and so you can see the changes.
Here's the link to the repo: https://github.com/DonMag/ATester2
Here is the result:
And scrolled up a bit:
I think you are mixing absolute positioning of outer views (i.e. manually setting frames) and using autolayout constraints for their inner components, and wrongly expect the dynamic autolayout part to somehow "reach all the way up" to the outer views. For autolayout to do that, you'll need to use autolayout all the way up, including the way CustomViews are positioned in your contentView.
If for whatever reason you do not want to use a TableView or CollectionView for this you could also, for example, try adding your CustomViews as arranged subviews to a vertical stackview that has top/bottom/leading/trailing constraints to contentView, then replace the "Align Center Y" constraint of your CustomView with "Align Top" and "Align Bottom" constraints to actually allow your labels to "push" from the inside if they need more vertical space.
Edit here's a quick sketch to illustrate that setup:
Edit 2 here are a couple of screenshots to clarify further. With a basic layout like this:
the result will look like this at runtime:
Note that the UIStackViews use the "Equal Spacing" Distribution in this example. If you want to create and add your CustomViews programmatically, use the StackView's func addArrangedSubview(_ view: UIView).
Good luck!

ios - How to auto-resize my view in storyboard? swift 3

I try to auto-resize my view with auto-layout contraints, but I have some errors of Y-position missing. I can't understand what is wrong, I attached my Y-position to the top of the view.
Thanks for your help, here is the screenshot:
The problem is that you don't set a fixed height but, if you can, ALWAYS AVOID to put a fixed height for a view. For an app that can fit all screen is better to use different techniques.
If don't want to set a fixed height on your view, you have two possible options:
Give to the view a bottom constraint. You should also set the distance between the bottom of your view and the screen (or another object below your view).
Use stackview. If you place your views into a stack view you will be able to autoresize the width and height of your views according to the screen dimension.
You must give a height for the view or construct it's subviews in a way that gives it a height by hooking constraints properly from top to bottom
when you have a y position error it means top, bottom and height issue
and when x it means leading , trailing and width issue
IF you want to create dynamic view drag a vertical UIStackView and give it a height and in runtime add items to it
self.myStackView.addArrangedSubview(lbl)

AutoLayout : Relative scaling of views

I want to achieve consistent views across different screens. My layout constraints works on small screens perfectly but it scrambles on large screens.
I have made a view(Red Border indicating that view)and pin it in to the main super view. Then I have made sub views and put it inside that view. I have pinned the the top bottom trailing and leading edge of the layout which contains button of the it's parent view (Red Border indicating that view). The view containing button is looking like this in small screen (iPhone 5)
while it's looking in big screens like this (iPhone 6 and above)
I want this layout to have the same relative height in all the screens like the other views. How can I achieve this?
I guess you can use UIView that contains a button inside and set bottom,lead,trailing,top constraints for the UIView. Then you can set height constraint of that UIView and set multiplier values to have relative height to its superView(=Red box). Finally, you can set constraints for your button inside the UIView whatever you want. If you know how to use StackView, I recommend you to use it because it is easy and simple solution. Here is very good tutorial about StackView.
If height is constant for subview except that button view the layout will be like what you mentioned in the first image .If you kept height as constant for that button view the problem will be solved

AutoLayout Equal Heights hides Subviews

I have a UIView buttonView and gave it an equal heights constraint to the super UIView with a 0.4 multiplier. The frame is adjusted correctly but the subviews of buttonView are not visible. However, when I click on the position where the buttons are supposed to be then the actions triggers.
This does not happen when I change the buttonViews constraint to be a fixed height.
I can get more into details if you want but has anyone run into something similar?
EDIT
There should be two buttons where the white space underneath the label is. When I click on the white space the timer runs but the button is not visible.
I took a look at the project and the issue I saw in a couple places was that auto layout and manual frame transformations are both used, which can be tricky. A couple specific things I saw that you will probably need to modify in order for the view to adapt and render correctly at different sizes / orientations:
1) The CustomAudioLearn view loads a view from a xib and adds it as a subview. However, it does not set constraints on this subview to make sure that the subview always hugs the edges of the parent view. So changing the size of the CustomAudioLearn view through auto layout in the storyboard results in the the xib-based subview always staying the same size. You should either add constraints to the subview or override layoutSubviews() in CustomAudioLearn and include self.customView.frame = self.bounds and self.customViw.layoutIfNeeded() in there. Also, I would suggest removing the line self.customView.translatesAutoresizingMaskIntoConstraints = false
2) Similarly, the RecordButtonView sets its corner radius on awakeFromNib(), but after layout happens, that's no longer the right radius. So you should again consider overriding layoutSubviews() or similar location to adjust the radius every time the layout is updated.
3) Lastly, the superview of the RecordButtonView in the storyboard is set to a height constraint of 70 with a priority of 1000. If you want the RecordButtonView to expand for the space available, you should reduce the priority of that height constraint so that the proportional width of the RecrodButtonView and the 1:1 aspect ratio take priority in determining the height of the superview. Otherwise, it will always be 70 points, or there will be conflicting constraints.
The problem was that I set the rounded corners to half of my frame's width. The radius got so big that it completely hide the view. I changed it so that after the bounds are set I change the corner radius. Sorry for confusion but thanks for any help!

Simple scroll view constraints change?

I created a scroll view in Xcode that works awesome because of this video.
https://www.youtube.com/watch?v=3PIm8-lKAYw
When I was messing around after I made it I found out that if I clicked on the scroll view and went to Show the Size Inspector or the fifth button on the right hand side of the screen I had the option to make a constraint called Top Space change in value that caused the scroll view to become bigger and smaller. I decided to see if I could find a way to change the constraint programmatically by simply using dot notation and the equaling it to an int value that I wanted.
So what I'm trying to figure out is there a simple way to change these constraints values programmatically that change the scroll view constraints values?
Without actually following that tutorial (and there being no code in your question) I'm going to make a few assumptions.
Yes, it is possible to change the scroll view's content size by manipulating constraints in your code. If you are creating the constraints in a xib or storyboard, you will need to make sure they are hooked up to IBOutlets so that you can access them in your code.
If you have 2 views arranged vertically that affect the vertical content size of your scroll view, increasing the space between these views would also increase the vertical size of your scrollview's content size. The following would increase the space between 2 views by 20 (assuming a multiplier of 1) and subsequently increase the scrollview's vertical space by the same amount.
// This is a vertical space constraint created in your xib or storyboard between 2 views that drive the content size of your scrollview
someVerticalSpaceConstraint.constant += 20;

Resources