Matching subview's width to it's superview using autolayout

10,736

Solution 1

Improving on Rob's answer, as requested.

As Rob already mentioned, UIScrollViews have peculiar behavior under Auto Layout.

What is of interest in this case is the fact that the scrollView total width is determined by using its subviews total width. So while the scrollView already asks the webView for its width, you're telling the webView to also ask the scrollView for its width. That's why it doesn't work. One is asking another, and no one knows the answer. You need another reference view to use as a constraint for the webView, and then the scrollView will also be able to successfully ask about its expected width.

An easy way this could be done: create another view, containerView, and add the scrollView as a subview to that. Then set the proper constraints for containerView. Let's say you wanted the scrollView centered on a viewController, with some padding on the edges. So do it for the containerView:

NSDictionary *dict = NSDictionaryOfVariableBindings(containerView);
[self.view addConstraints:[NSLayoutConstraints constraintsWithVisualFormat:@"H|-(100)-[containerView]-(100)-|" options:0 metrics:0 views:dict];
[self.view addConstraints:[NSLayoutConstraints constraintsWithVisualFormat:@"V|-(100)-[containerView]-(100)-|" options:0 metrics:0 views:dict];

Then you can proceed adding the webView as a subview to the scrollView and setting its width:

NSLayoutConstraint *makeWidthTheSameAsScrollView =[NSLayoutConstraint
                                                       constraintWithItem:self.questionWebView
                                                       attribute:NSLayoutAttributeWidth
                                                       relatedBy:0
                                                       toItem:containerView
                                                       attribute:NSLayoutAttributeWidth
                                                       multiplier:1.0
                                                       constant:0];

[self.view addConstraint:makeWidthTheSameAsScrollView];

This would make the scrollview as large and tall as the webView, and they both would be placed as intended (with the constraints set on containerView).

Solution 2

Scrollviews are a bit strange in how they interact with auto layout. See TN2154 (UIScrollView and Autolayout).

See also UIScrollView doesn't use autolayout constraints.

In general, you need to get the width of the contained view some other way than "the current width of the scrollview" since in auto layout the scrollview's width (i.e. content width) is defined in terms of its content. Thus your current request is circular.

Share:
10,736
drc
Author by

drc

Focused on iOS development

Updated on July 24, 2022

Comments

  • drc
    drc almost 2 years

    Goal:

    Have a UIWebView be the same width as it's superview, which is a UIScrollView, using autolayout constraints.

    Code

    NSLayoutConstraint *makeWidthTheSameAsScrollView =[NSLayoutConstraint
                                                           constraintWithItem:self.questionWebView
                                                           attribute:NSLayoutAttributeWidth
                                                           relatedBy:0
                                                           toItem:self.masterScrollView
                                                           attribute:NSLayoutAttributeWidth
                                                           multiplier:1.0
                                                           constant:0];
    
    [self.view addConstraint:makeWidthTheSameAsScrollView];
    
     NSLog(@"The width of questionWebView *AFTER* adding the constrain is: %f", self.questionWebView.frame.size.width);
     NSLog(@"The width of scrollView *AFTER* adding the constrain is: %f", self.masterScrollView.frame.size.width);
    

    Current Result

    When I log the width of self.questionWebView (the UIWebView), it's width does not change when the autolayout constrain is applied.

    Questions

    • Is this the correct approach?
    • What am I doing wrong?

    p.s I know it is against Apple's recommendations to place a UIWebView in a UIScrollView, however I've turned off the ability to scroll the UIWebView using the property self.questionWebView.userInteractionEnabled = NO;. And currently using a UIWebView is my best strategy for displaying an HTML table.

  • Aloha Silver
    Aloha Silver over 10 years
    An easy strategy would be to add the scrollView as a subview to another view (laid out just like the scrollView would be) and set Auto Layout to use the width of this view to set the webView one.
  • drc
    drc over 10 years
    @AlohaSilver thanks, add this as a separate answer please, I think it's useful broken out as an answer rather than a comment.
  • user14322501
    user14322501 about 10 years
    You can do this in IB also: developer.apple.com/library/ios/documentation/UserExperience‌​/… "Creating Anchored Views Inside a Scroll View"