Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIScrollview with Autolayout Content Size in Landscape

I'm trying to show a simple settings screen in my app and I'm using Autolayout. Since my app supports landscape, and the settings controls don't quite fit vertically when the phone is landscape, I added a UIScrollview.

It seems that the combination of UIScrollview and Autolayout is a common question here and elsewhere. I've read a few articles on it, and from what it can tell, it seems that a good way to go for what I'm trying to do is to put my various controls within a view, like a "contentView" with constraints aligned in that view. Then have that contentView be the sole subview of the UIScrollView. I have the contentView with constraints tied to the edges of the UIScrollView.

UINavigationView -> UIScrollview -> contentView (UIView) -> Control Subviews

xib

It works fine in portrait, even if I add content in my contentView that requires scrolling to see, but when I go to landscape, it doesn't let me scroll down far enough. It's like the content size gets reset to the frame of the visible area (or the frame of the navigation controller superview) when I rotate.

simulator

I'm wondering if I need to check for rotation and then set the content size again at that time? If so, is there a way to get that size dynamically from the view (contentView)?

Thanks for any help you can offer! Jim

like image 734
Jim Avatar asked Mar 05 '14 18:03

Jim


People also ask

What is content layout guide frame layout guide?

The Frame Layout guide relates to the position (x, y) and size (width, height) of the scrollview itself, relative to the superview it was placed in. The Content Layout guide relates to the size of the scrollable content area inside the scroll view.

How do I remove content layout guide?

Simply uncheck the Content Layout Guides. This option is found under the Size Inspector tab in storyboard. NOTE: This option is found under the Size Inspector tab in storyboard.

What is ContentInsetAdjustmentBehavior?

Discussion. This property specifies how the safe area insets are used to modify the content area of the scroll view. The default value of this property is UIScrollView. ContentInsetAdjustmentBehavior. automatic .


1 Answers

There are two components to having auto layout properly handle scroll views:

  1. Constraints for scroll view's subviews: The contentSize of the scroll view will be dictated by the constraints of the scroll view's subviews. Thus, you need to have a bottom constraint for the last control in the scroll view (i.e. second switch) to its superview (i.e. the scroll view). It looks like you do have this. These constraints for subviews of the scroll view will automatically adjust the scroll view's contentSize as needed.

    By the way, the constant for this second switch's bottom constraint will generally default to some largish value corresponding to how it was laid out in portrait. You may want to select and edit this bottom constraint for this last control and change it so that it's the "standard" value.

    enter image description here

  2. Constraints for the scroll view itself: You need to make sure you have the bottom constraint for the scroll view, itself, to its superview (and make sure you do not have a height constraint on the scroll view). This will adjust the frame of the scroll view upon screen rotation. I wonder if this might be missing in your project.

    You can confirm this by running your app in the debugger, hitting "pause" button:

    enter image description here

    and then at the (lldb) prompt, type po [[UIWindow keyWindow] recursiveDescription], and you should see something like:

    (lldb) po [[UIWindow keyWindow] recursiveDescription]
    <UIWindow: 0x8b97ff0; frame = (0 0; 320 480); autoresize = W+H; gestureRecognizers = <NSArray: 0x8b98450>; layer = <UIWindowLayer: 0x8b97af0>>
       | <UIView: 0x8b9a830; frame = (0 0; 320 480); transform = [0, -1, 1, 0, 0, 0]; autoresize = RM+BM; layer = <CALayer: 0x8b9a240>>
       |    | <UIScrollView: 0x8b9aa50; frame = (0 0; 480 320); clipsToBounds = YES; autoresize = RM+TM; gestureRecognizers = <NSArray: 0x8b9a6c0>; layer = <CALayer: 0x8b9a130>; contentOffset: {0, 0}>
       |    |    | <UILabel: 0x8b9ade0; frame = (20 20; 63 21); text = 'Settings'; clipsToBounds = YES; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x8b9aec0>>
       |    |    | <UILabel: 0x8b9d590; frame = (20 49; 51 21); text = 'View 1'; clipsToBounds = YES; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x8b9d6b0>>
       |    |    | <UILabel: 0x8b9db70; frame = (408 49; 51 21); text = 'View 2'; clipsToBounds = YES; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x8b9dc10>>
       |    |    | <UIView: 0x8b9de60; frame = (335 78; 124 53); autoresize = RM+BM; layer = <CALayer: 0x8b9dec0>>
       |    |    | <UIView: 0x8b9e000; frame = (20 78; 284 53); autoresize = RM+BM; layer = <CALayer: 0x8b9e060>>
       |    |    | <UILabel: 0x8b9e250; frame = (20 139; 59 21); text = 'Slider 1'; clipsToBounds = YES; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x8b9e2f0>>
       |    |    | <UISlider: 0x8b9e460; frame = (18 238; 444 34); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x8b9e5c0>; value: 0.500000>
       |    |    |    | <UIView: 0x8ace410; frame = (2 16; 440 2); userInteractionEnabled = NO; layer = <CALayer: 0x8ace470>>
       |    |    |    |    | <UIView: 0x8ace610; frame = (221 0; 219 2); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x8ace670>>
       |    |    |    |    |    | <UIView: 0x8ace6e0; frame = (-221 0; 440 2); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x8ace740>>
       |    |    |    |    |    |    | <CAGradientLayer: 0x8ace7b0> (layer)
       |    |    |    |    | <UIView: 0x8ace7e0; frame = (0 0; 221 2); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x8ace840>>
       |    |    |    | <UIImageView: 0x8ace9d0; frame = (207 1; 31 31); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x8acea60>>
       |    |    |    |    | <UIImageView: 0x8ace8b0; frame = (-13 -6.5; 57 43.5); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x8ace940>>
       |    |    | <UISlider: 0x8b9e850; frame = (17 168; 444 34); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x8b9e930>; value: 0.500000>
       |    |    |    | <UIView: 0x8ba5430; frame = (2 16; 440 2); userInteractionEnabled = NO; layer = <CALayer: 0x8ba5490>>
       |    |    |    |    | <UIView: 0x8acc190; frame = (221 0; 219 2); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x8acae30>>
       |    |    |    |    |    | <UIView: 0x8acc3f0; frame = (-221 0; 440 2); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x8ac84d0>>
       |    |    |    |    |    |    | <CAGradientLayer: 0x8accb90> (layer)
       |    |    |    |    | <UIView: 0x8acdf50; frame = (0 0; 221 2); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x8acdfb0>>
       |    |    |    | <UIImageView: 0x8ace070; frame = (207 1; 31 31); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x8ace100>>
       |    |    |    |    | <UIImageView: 0x8acdfe0; frame = (-13 -6.5; 57 43.5); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x8acdc80>>
       |    |    | <UILabel: 0x8b9e9c0; frame = (20 209; 59 21); text = 'Slider 2'; clipsToBounds = YES; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x8b9ea60>>
       |    |    | <UISwitch: 0x8b9ece0; frame = (411 279; 51 31); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x8b9edd0>>
       |    |    |    | <_UISwitchInternalViewNeueStyle1: 0x8b9f0c0; frame = (0 0; 51 31); gestureRecognizers = <NSArray: 0x8b723f0>; layer = <CALayer: 0x8b9f1c0>>
       |    |    |    |    | <UIView: 0x8b9f750; frame = (35.5 0; 15.5 31); clipsToBounds = YES; layer = <CALayer: 0x8b9f7b0>>
       |    |    |    |    |    | <UIView: 0x8b9f3b0; frame = (-35.5 0; 51 31); layer = <CALayer: 0x8b9f410>>
       |    |    |    |    | <UIView: 0x8b9f6c0; frame = (0 0; 35.5 31); clipsToBounds = YES; layer = <CALayer: 0x8b9f720>>
       |    |    |    |    |    | <UIView: 0x8b9f440; frame = (0 0; 51 31); layer = <CALayer: 0x8b9f4a0>>
       |    |    |    |    | <UIView: 0x8ba11e0; frame = (0 0; 51 31); layer = <CALayer: 0x8ba1240>>
       |    |    |    |    |    | <UIImageView: 0x8ba0f10; frame = (39 16; 0 0); alpha = 0; userInteractionEnabled = NO; layer = <CALayer: 0x8ba10f0>>
       |    |    |    |    |    | <UIImageView: 0x8ba1120; frame = (12 16; 0 0); userInteractionEnabled = NO; layer = <CALayer: 0x8ba11b0>>
       |    |    |    |    | <UIImageView: 0x8b9fab0; frame = (7 -6; 57 43.5); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x8ba0a40>>
       |    |    | <UISwitch: 0x8b974b0; frame = (411 318; 51 31); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x8b75570>>
       |    |    |    | <_UISwitchInternalViewNeueStyle1: 0x8b7d6a0; frame = (0 0; 51 31); gestureRecognizers = <NSArray: 0x8b845e0>; layer = <CALayer: 0x8b78750>>
       |    |    |    |    | <UIView: 0x8b7df70; frame = (35.5 0; 15.5 31); clipsToBounds = YES; layer = <CALayer: 0x8b7be00>>
       |    |    |    |    |    | <UIView: 0x8b72410; frame = (-35.5 0; 51 31); layer = <CALayer: 0x8b7a660>>
       |    |    |    |    | <UIView: 0x8b7ba80; frame = (0 0; 35.5 31); clipsToBounds = YES; layer = <CALayer: 0x8b7bd00>>
       |    |    |    |    |    | <UIView: 0x8b78dd0; frame = (0 0; 51 31); layer = <CALayer: 0x8b7ba20>>
       |    |    |    |    | <UIView: 0x8b81580; frame = (0 0; 51 31); layer = <CALayer: 0x8b77ee0>>
       |    |    |    |    |    | <UIImageView: 0x8b97880; frame = (39 16; 0 0); alpha = 0; userInteractionEnabled = NO; layer = <CALayer: 0x8b7e1a0>>
       |    |    |    |    |    | <UIImageView: 0x8b77460; frame = (12 16; 0 0); userInteractionEnabled = NO; layer = <CALayer: 0x8b7e350>>
       |    |    |    |    | <UIImageView: 0x8b80670; frame = (7 -6; 57 43.5); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x8b80700>>
       |    |    | <UILabel: 0x8b97cf0; frame = (335 284; 67 21); text = 'Switch 1'; clipsToBounds = YES; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x8b808b0>>
       |    |    | <UILabel: 0x8b79d60; frame = (335 323; 67 21); text = 'Switch 2'; clipsToBounds = YES; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x8b77b90>>
       |    |    | <UIImageView: 0x8ac44f0; frame = (476 473; 3 7); alpha = 0; opaque = NO; autoresize = LM; userInteractionEnabled = NO; layer = <CALayer: 0x8a89130>>
       |    |    | <UIImageView: 0x8ac2be0; frame = (313 316; 7 3); alpha = 0; opaque = NO; autoresize = TM; userInteractionEnabled = NO; layer = <CALayer: 0x8ac2c70>>
       |    | <_UILayoutGuide: 0x8b9cb20; frame = (0 0; 0 20); hidden = YES; layer = <CALayer: 0x8b9e5f0>>
       |    | <_UILayoutGuide: 0x8ac4440; frame = (0 320; 0 0); hidden = YES; layer = <CALayer: 0x8a90370>>
    

    Check the frame of the UIScrollView (e.g. the above is for landscape on iPhone), and make sure it corresponds to the size of screen. If you haven't defined the constraints between the scroll view and its superview, this frame may be incorrect.

like image 101
Rob Avatar answered Nov 14 '22 20:11

Rob