Height of contentView of UIScrollView based on inside content using Storyboard
Asked Answered
N

5

19

I'm actually facing difficulties to make my UIScrollView fully responsive using only storyboard constraints.

Here is my hierarchy :

> - UIViewController
>  - UIView
>   - UIScrollView
>    - contentView
>     - module1View
>     - module2View
>     - module3View

All the modules are used to display charts. I want them to be responsive. I want their width to be 100% of the screen and their height is defined by a ratio added using constraint. The modules are displayed next to each other like news in a newsfeed.

My question is : How do you set the contentView height equal to the sum of all the modules (module 1 + 2 + 3) ?

In other word I want to achieve :

  • Top of contentView = top of module 1
  • Top of module 2 = bottom of module 1
  • Top of module 2 = bottom of module 2
  • Bottom of contentView = bottom of module 3

To managed to do that I follow some tutorial found on internet. Here are the steps I followed :

  1. Setting UIScrollView contraints to define its place and position.
  2. Setting UIScrollView top, bottom, left and right spacing to nearest neighbour to 0.
  3. Setting the constraint between modules to "stack" them one on an other.
  4. (I'M BLOCKED HERE) Setting the bottom of the contentView to the bottom of module 3 to allow the UIScrollview to scroll until the end content.

I tried to force the height of UIScrollView : It works but it's not responsive. As the height of the module is calculated through a ratio, depending on the device, the height "module 1 + 2 + 3" while change.

I tried to add a constraint from module 3 to contentView to set the bottom of module 3 = bottom of contentView. All the constraints turn red with warning everywhere.

Do you have any idea to how to set height of contentView based on a responsive content ? (Like "wrap-content in a way).

Thanks in advance for you help !

Nickel answered 20/7, 2016 at 15:47 Comment(3)
once you set the height of the modules based on their ratio, you should be able to calculate the height for the contentViewMidrash
I tried to add : mainContentView.frame = CGRectMake(0, 0, self.view.width, module1View.height+module2View.height+module3View.height); in ViewDidLoad and viewWillAppear, none of them workedNickel
when do you set the frame of the modules? you need to set the mainContentView frame after the module frames are set... what type of object are the modules?Midrash
F
59

I've been able to get dynamic scroll views working entirely from storyboards, no code, with the following steps:

1) In the storyboard, add a scroll view and constrain its edges to the edges of the main view or in whatever way is appropriate

2) Inside the scroll view, add a plain old UIView as a container. Constrain it to all 4 edges of the scroll view, BUT ALSO add an equal width constraint relative to scroll view, and an equal height constraint to the scroll view

3) Very important: set a low priority for the equal height constraint, e.g. 250.

4) inside the container view you added in step 2, add your 3 modules. Constrain the top edge of the first module to the top of the container view, constrain the bottom edge of the last module to the bottom of the container view, and constrain all the in-between modules to the preceding module in the chain. This should give you your chain of unbroken vertical constraints inside the container view. You will also need to add whatever appropriate x positioning / width setting constraints to each module.

5) Build and run! Your scroll view content size should automatically be equal to the total height of all modules plus the spacing between them, and changing the module contents dynamically will update the scroll view content size via auto layout rather than requiring explicit code to calculate and update.

Finkle answered 20/7, 2016 at 21:0 Comment(10)
The low priority for the equal height constraint did the trick! Thanks a lot!Appearance
I have been using Scrollview for a while but Didn't know about point 3. Thanks a lot.Bogan
This solution was not directly working for me, I had to set the content view constraint to the ScrollView's parent and not directly to the ScrollView. Check my answer for details.Nadiya
Holy cow, this is incredible! Thank you!Haematogenous
One of the best solutions I have ever seen on stack overflow :-)Hardner
For me, "constrain the bottom edge of the last module to the bottom of the container view" is the key. However, in my storyboard, I have items that bleed off the bottom edge of the storyboard. any suggestions?Actinomycin
@Actinomycin The same solution still works for that case, but you may want to temporarily increase the size of the view controller / scene on the storyboard to be at least as tall as all the content in the scroll view. If you select the view controller, then select the layout tab in the inspector, and change the option from "Fixed" to "Freeform", you can set the height of the scene / view controller to 2000 or whatever you need. Set up your constraints following the above steps, then switch back to "Fixed". Your items will bleed off the edge and be clipped, but will work correctly at runtime!Finkle
This was exactly what I was thinking and ended up doing. Thanks for confirming.Actinomycin
Step 3 was a great idea! Thanks!Mithras
for me, I have a fixed height for my content view it was scrolling fine, the problem is when I expand the view inside the content view, the content view didn't expanding because it have a fixed height, when I do the step 2 and make the height of the content view equal to the scrollview, it is not scrolling anymore, I'm stuck in here for like a week, please help me, thanks!Byplay
N
1

For me, Daniel's solution was very helpful but not working. Here are the updated steps :

1) In the storyboard, add a scroll view and constrain its edges to the edges of the main view or in whatever way is appropriate

2) Inside the scroll view, add a plain old UIView as a container. Constrain it to all 4 edges of the scroll view, BUT ALSO add an equal width constraint relative to scroll view's parent (highest view), and an equal height constraint to the scroll view's parent

3) Very important: set a low priority for the equal height constraint, e.g. 250.

Nadiya answered 7/11, 2017 at 3:34 Comment(0)
J
0

Try to define height of the modules runtime and add auto layout constraint for modules programmatically.

 #define kDeviceHeight                   [UIScreen mainScreen].bounds.size.height
 #define kDeviceWidth                    [UIScreen mainScreen].bounds.size.width

    - (void)viewDidLoad {

        [super viewDidLoad];
        [self setScrollViewHeight];

    }

    -(void)setScrollViewHeight{

        float module1_Height,module2_Height,module3_Height;// Calculate the height of modules over here and assign it to respective variables
        float viewVerticalSpacing = 5; // Provides space between two views
        float YAxis = 0;
        module1View.frame = CGRectMake(0, 0, kDeviceWidth, module1_Height);

        YAxis = YAxis + module1_Height + viewVerticalSpacing;
        module2View.frame = CGRectMake(0, YAxis, kDeviceWidth, module2_Height);

        YAxis = YAxis + module2_Height + viewVerticalSpacing;
        module3View.frame = CGRectMake(0, YAxis, kDeviceWidth, module3_Height);

        float scrollView_height = YAxis + module3_Height + viewVerticalSpacing;
        scroll_view.contentSize = CGSizeMake(kDeviceWidth, scrollView_height);
        scroll_view.frame = CGRectMake(0, 0, kDeviceWidth, kDeviceHeight);
    }
Janijania answered 20/7, 2016 at 20:22 Comment(0)
D
0

I got mine working by not setting the content view's height equal to anything.

Drouin answered 28/5, 2019 at 13:7 Comment(0)
E
0

For me, the recommended solution did not work. I had to modify it a bit:

  1. Do all the steps from the recommended solution.
  2. Set ScrollView height to 0 and give this a low priority.
  3. Set the bottom-space-constraint of the parent of the scrollView to low priority.

I think my solution will only work if the parent view of the scrollview is not the root content view.

Earreach answered 16/6, 2021 at 20:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.