4

I have a UIScrollView with a UIView as a subview. The UIView has a bunch of data entry fields arranged vertically - essentially just a fixed format data entry Form.

I want to keep the UIView's vertical size and adjust its horizontal size to match the size of the UIScrollView which changes depending on the orientation of the device. Note that this is all placed in the Detail view of a UISplitViewController.

So the user will have to scroll vertically but not horizontally as all the text fields on the UIView should resize themselves to fit horizontally on the screen.

Currently if I resize the UIView by changing the frame width to match the UIScrollView's frame width then the UIView subviews (the text fields) don't resize themselves according to the constraints setup in IB. The UIView just seems to get clipped. There is no horizontal scrolling so this aspect is working correctly.

I have autoresize subviews set on UIView and on UIScrollView.

Any tips on what to do here ? Also where would I put code to resize the UIView if the device orientation changes ?

Additional information.

I created the UIView in IB as a separate view in the same NIB as the DetailViewController containing the UIScrollView. Because it is much taller than the UIScrollView the only way I can find for creating it in IB is if I set it up as a separate view of the desired width and height. I then create an IBOutlet and add this view as a subview to UIScrollView in the viewDidLoad method. This all seems to work find with the views all displaying correctly, with the exception that the UIView subviews are not resized horizontally.

Any suggestions on what I may be doing wrong here?

Julian
  • 9,299
  • 5
  • 48
  • 65
Duncan Groenewald
  • 8,496
  • 6
  • 41
  • 76
  • What are the constraints setup? This should be doable with just auto-layout. – Rakesh Jul 10 '13 at 06:45
  • You would think but clearly I am missing something. As Rakesh below points out constraints between UISCrollView and UIView (its Subview) are not setup because UIView is not inside UIScrollView in IB. I thought I could just resize the UIView by changing its frame to match the width of the UIScrollView but the UIView does not resize its Subviews if I simply use UIView.frame = newFrame. – Duncan Groenewald Jul 10 '13 at 10:49
  • Perhaps I need to disable auto-layout as per Rakesh' comment below. I'll try these suggestions and let you know how I go. – Duncan Groenewald Jul 10 '13 at 10:51
  • Rakesh and me , both are the same person. :D Anyway instead of setting the frame manually (if you go that way you would have to use the layoutSubviews to position the subviews also), why don't you set the UIView also using constraints (programmatically) or just use the other way that I mentioned in the answer? – Rakesh Jul 10 '13 at 10:55
  • I have updated the answer with another option also. Check it out. – Rakesh Jul 10 '13 at 11:01
  • OK I have got it working now. I turned of autoLayout and that just messed up everything because it all needed to be manually positioned - thats too much work. Turning it back on then I found that all constraints had been removed. So I started by adding the following to the viewDidLoad [self.scrollView addSubview:self.contentView]; self.scrollView.contentSize = self.contentView.frame.size; self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth; self.contentView.autoresizesSubviews = YES; – Duncan Groenewald Jul 10 '13 at 23:01

2 Answers2

3

Since you are using not putting the view inside scrollview directly from the xib, the IB doesn't provide the options to give constraints that has anything to do with superview. You might have to add the constraints programatically.See here.

EDIT:

Also try using the below on the view (haven't tried, should work according to documentation, but not sure with auto-layout):

self.view.autoresizesSubviews = YES;

Or if you don't want to use auto layout at all then the earlier method of setting the view to expand (horizontal/vertical) in the size inspector would do. For this you have to disable auto-layout. Select xib-> File Inspector -> Uncheck auto-layout checkbox

Community
  • 1
  • 1
Rakesh
  • 3,370
  • 2
  • 23
  • 41
  • 1
    Mmm.. I just realised its not quite working 100%. UIScrollView is still scrolling horizontally even though the UIView inside it is correctly sized to match the width. Seems that when I set the UIScrollView.contentSize its remembering this and no adjusting to any resizing of the UIView inside. If I remove this line of code then the n no scrolling occurs vertically or horizontally (presumably because contentSize is zero. I assume therefor that UIScrollView does not automatically work out its contentSize based on the size of its Subviews ? – Duncan Groenewald Jul 11 '13 at 00:06
  • OK I had to add the following code to the viewWillLayoutSubviews to reset the UIScrollView.contentSize. CGRect frame = self.contentView.frame; frame.size.width = self.view.frame.size.width; self.scrollView.contentSize = frame.size; – Duncan Groenewald Jul 11 '13 at 00:21
  • Cool. I guess you would have to set the size of contentView separately. Check these questions, it might help you. http://stackoverflow.com/questions/16441808/uiscrollview-with-ios-auto-layout-constraints-wrong-size-for-subviews and http://stackoverflow.com/questions/15034413/uiscrollview-and-constraints-issue – Rakesh Jul 11 '13 at 05:42
  • No it seems the contentView now gets sized correctly automatically. That is it gets made the same width as scrollView and the height stays the same. Still I am puzzled that the scrollView.contentSize is not automatically set to be the size of the Subviews. Is this documented behaviour ? – Duncan Groenewald Jul 11 '13 at 09:58
  • Thanks those other questions/answers help confirm my understanding of how things work. – Duncan Groenewald Jul 11 '13 at 10:05
  • OK, I think i just found out the correct way to do what I am trying to do so i figured I would leave a note here. – Duncan Groenewald Jul 12 '13 at 01:31
3

OK after more discovery I think I have found the right way to do what I am trying to do so i thought I should leave a note regarding this. Remember I am trying to create a scrollable form that resizes its width but not its height so the user only has to scroll up and down to access fields.

  1. To create a large fixed size form that requires scrolling on the device make sure you set the ViewController size to Freeform in IB. Then you can create the view to be whatever size you want in IB and at runtime it will resize to the devices size.
  2. Place the UIScrollView (I call it the scrollView) in the main view and pin it left and right and top and bottom (i.e set constraints using IB)
  3. Place a UIView (I call it the contentView) in scrollView and make it the same size as the scrollView and also pin it on all sides to its superview (the scrollView)
  4. Now add all the labels and text fields are required to the contentView and make sure you add vertical constraints from top to bottom and left to right so that autolayout can figure out the width and height in order to calculate the scrollView.contentSize
  5. Set the contentView width constraint as a fixed size to make it look reasonable in IB. Bear in mind we want the width of contentView to always match the scrollView width so the user does not have to scroll sideways, only up and down. We will set the proper width in code at runtime as I have not found any way of doing this in IB only. Perhaps setting priorities on constraints might achieve this but I think UIScrollView won't do this for you.
  6. Now add a property the ViewController.h file and connect this to the contentView width constrain you created in 5) above.

    @property (weak, nonatomic) IBOutlet NSLayoutConstraint *contentViewWidth;
    
  7. Finally create a viewDidLayoutSubviews method in ViewController and add the following code to set the contentView width to be the same as the scrollView width.

    - (void)viewDidLayoutSubviews
    {
        self.contentViewWidth.constant = self.scrollView.frame.size.width;
    
        [self.view layoutSubviews];
    }
    
  8. If things don't resize properly check all your constraints are correctly set. IB seems to do some things that seem strange to me. But finally I have it working with what appears to be minimum coding.

  9. You can also resize vertically in the same way as long as you set the constraint priority on subviews in contentView to be lower than 1,000. Also set a greater than or equal to size with a high priority if you don't want it smaller than a certain size.

If anyone can figure out how to set the contentView such that it resizes its width to match the scrollView using only IB constraints I would love to know how.

Duncan Groenewald
  • 8,496
  • 6
  • 41
  • 76