How can I use Autolayout to set constraints on my UIScrollview?

后端 未结 18 1597
别那么骄傲
别那么骄傲 2020-11-28 00:43

I have spent two days trying out the various solutions for Mixed and Pure Autolayout approaches to achieve what was a trivial scrollview setup prior to autolayout, and it\'s

相关标签:
18条回答
  • 2020-11-28 01:41

    Simple Self-Contained Example

    Judging by the high number of votes on the question and the low number of votes on the answers, people are not finding an understandable and quick solution here. Let me try to add one. This project is a self-contained example done completely in the Interface Builder. You should be able to work through it in 10 minutes or less. Then you can apply the concepts you learned to your own project.

    The original question asks about scrolling buttons. Here I just use UIViews but they can represent whatever view you like. I also chose horizontal scrolling because the storyboard screenshots are more compact for this format. The principles are the same for vertical scrolling, though.

    Key concepts

    • The UIScrollView should only use one subview. This is a 'UIView' that serves as content view to hold everything you wish to scroll.
    • Make the content view and the scroll view's parent have equal heights for horizontal scrolling. (Equal widths for vertical scrolling)
    • Make sure that all of the scrollable content has a set width and is pinned on all sides.

    Start a new project

    It can be just a single view application.

    Storyboard

    In this example we will make a horizontal scroll view. Select the View Controller and then choose Freeform in the Size Inspector. Make the width 1,000 and the height 300. This just gives us room on the storyboard to add content that will scroll.

    Add a Scroll View

    Add a UIScrollView and pin all four sides to the root view of the view controller.

    Add a Content View

    Add a UIView as a subview to the scroll view. This is key. Don't try to add lots of subviews to the scroll view. Just add a single UIView. This will be your content view for the other views you want to scroll. Pin the content view to the scroll view on all four sides.

    Equal Heights

    Now in the Document Outline, Command click both the content view and the scroll view's parent view in order to select them both. Then set the heights to be equal (Control drag from the Content View to the Scroll View). This is also key. Because we are scrolling horizontally, the scroll view's content view won't know how high it should be unless we set it in this way.

    Note:

    • If we were making the content scroll vertically, then we would set the content view's width to be equal to the scroll view's parent's width.

    Add content

    Add three UIViews and give them all constraints. I used 8 point margins for everything.

    Constraints:

    • Green view: pin the top, left, and bottom edges. Make the width 400.
    • Red view: pin the top, left, and bottom edges. Make the width 300.
    • Purple view: pin all four edges edges. Make the width whatever the remaining space is (268 in this case).

    Setting the width constraints is also key so that the scroll view knows how wide its content view will be.

    Finished

    That's all. You can run your project now. It should behave like the scrolling image at the top of this answer.

    For vertical scrolling, just swap all the width and height directions in this example (tested and working).

    Further Study

    • iOS: How To Make AutoLayout Work On A ScrollView
    • How to configure a UIScrollView with Auto Layout in Interface Builder
    • YouTube video tutorial: UIScrollView - How to keep your views on screen
    0 讨论(0)
  • 2020-11-28 01:42

    It's hard to see the exact values and setup of your constraints as you've pasted them here, so I'm not sure from looking at your screenshots where you have gone wrong.

    In lieu of an explanation of what's wrong in your setup, I've created a basic sample project with a very similar view hierarchy and constraint setup to the one you describe. The horizontal scrolling works as expected in the sample project, which uses the "Pure AutoLayout" approach that Apple describes in the Technical Note.

    I also had a lot of trouble originally getting Auto Layout to work with UIScrollView. The key to getting it to work is making sure that all of the items in the scroll view, taken together, have constraints that eventually link to all sides of the scroll view and that contribute to the AutoLayout system being able to determine a contentSize for the scroll view that will be bigger than its frame. It looks like you were trying to do that in your code, but maybe you had some superfluous constraints in there that were making the contentSize too small.

    Also of note, as others mentioned, with AutoLayout and UIScrollview, you no longer set the contentSize explicitly. The AutoLayout System calculates the contentSize based on your constraints.

    I also found this ebook chapter to be very helpful in making me understand how all this works. Hope all this helps.

    0 讨论(0)
  • 2020-11-28 01:43

    The contentSize is implicitly set by applying the constraints inside of the UIScrollView.

    For example, is you have a UIScrollView inside of a UIView it will look like this (as I am sure you are aware):

        UIView *containerView               = [[UIView alloc] init];
        UIScrollView *scrollView            = [[UIScrollView alloc] init];
        [containerView addSubview:scrollView];
        containerView.translatesAutoresizingMaskIntoConstraints = NO;
        scrollView.translatesAutoresizingMaskIntoConstraints    = NO;
        NSDictionary *viewsDictionary       = NSDictionaryOfVariableBindings(containerView, scrollView);
    
        [containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[scrollView]|"
                                                                              options:kNilOptions
                                                                              metrics:nil
                                                                                views:viewsDictionary]];
        [containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scrollView]|"
                                                                              options:kNilOptions
                                                                              metrics:nil
    

    That will set the scrollView to fill the size of the containerView (so the containerView will have to be of a certain size).

    You can then adjust the contentSize of the UIScrollView by implicitly setting it to be large enough to hold the buttons like this:

        UIButton *buttonA                   = [[UIButton alloc] init];
        UIButton *buttonB                   = [[UIButton alloc] init];
        UIButton *buttonC                   = [[UIButton alloc] init];
        [scrollView addSubview:buttonA];
        [scrollView addSubview:buttonB];
        [scrollView addSubview:buttonC];
        buttonA.translatesAutoresizingMaskIntoConstraints       = NO;
        buttonB.translatesAutoresizingMaskIntoConstraints       = NO;
        buttonC.translatesAutoresizingMaskIntoConstraints       = NO;
    
        viewsDictionary                     = NSDictionaryOfVariableBindings(scrollView, buttonA, buttonB, buttonC);
    
        [scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[buttonA]-|"
                                                                           options:kNilOptions
                                                                           metrics:nil
                                                                             views:viewsDictionary]];
        [scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[buttonA]-[buttonB]-[buttonC]-|"
                                                                           options:NSLayoutFormatAlignAllBaseline
                                                                           metrics:nil
                                                                             views:viewsDictionary]];
    
    0 讨论(0)
  • 2020-11-28 01:43

    In swift you can use this working solution.

    Contraints

    ScrollView: Leading, Trailing, Top, Bottom = Superview

    ContentView: Leading, Trailing, Top, Bottom = ScrollView. Height fixed/relative to content.

    You can set the width constraint(contentView) to equal scrollviews superview, but select remove remove on build time because you will be adding that constraint programmatically. This is just so the IB doesn't complain with warnings.

    extension UIView {
    
        func setupContentViewForViewWithScroll(contentView vwContent : UIView) {
            //Set constraint for scrollview content
            let constraint = NSLayoutConstraint(item: vwContent, attribute: NSLayoutAttribute.Width, relatedBy: .Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: self.bounds.size.width)
            vwContent.addConstraint(constraint)
            self.layoutSubviews()
        }
    
    }
    

    And in the View Controller viewDidLayoutSubviews i just call this method:

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        self.view.setupContentViewForViewWithScroll(contentView: vwContent)
    }
    
    0 讨论(0)
  • 2020-11-28 01:44

    LOL welcome to the stupidity club. I'm one of the founders. :D

    For VERTICAL scrolling: the only way I could get it to work (iOS 8, Xcode 6 and pure autolayout) was adding the following constraints to my Scroll View (all related to the superview):

    • Equal Widths
    • Equal Heights
    • Center Y Alignment
    • Center X Alignment

    My structure:

      UIView
       - ScrollView
        - Subview
        - Subview
        - Subview
        - Subview
        - ...
    

    This is the final result:

    Demo

    This is the setup:

    Setup Full screen

    And here is the project.

    Hopefully this would save someone from GOING TO SLEEP AT 5 AM. :D

    0 讨论(0)
  • 2020-11-28 01:45

    You should organize your layout like this
    ViewControllerView contains ScrollView, ScrollView contains ContainerView, ContainerView contains 2 Labels

    Then follow 3 steps for make your ScrollView can scroll

    1. Setting ScrollView pin (top/right/bottom/left) to ViewControllerView
      • Setting ContainerView pin (top/right/bottom/left) to ScrollView
      • Set Horizontally in Container (don't set Vertically in Container)
      • Label1 pin (top/right/left) to ContainerView
      • Label1 pin (right/left/bottom) to ContainerView and top to Label1

    HERE is the demo project

    Hope this help

    0 讨论(0)
提交回复
热议问题