Swift UIScrollView - Correct Implementation for On

2019-01-31 20:23发布

问题:

In advance, I apologize as I would say that I'm a beginner with iOS programming.

I want to use UIScrollView because the content to display exceed the height of the screen. Therefore, I would like only a vertical scroll and not a horizontal scrolling.

I'm using the Storyboard to draw the views with AutoLayout.

Here's are the screenshot of my UIViewController with the UIScrollView :

Then I change the Label to a big text like that

override func viewDidLoad() {
    super.viewDidLoad()

    self.label1Label.text = "Seize jours après la chute du président Blaise Compaoré, le Burkina Faso a un nouveau chef d'EtatA l'issue d'ultimes tractions, civils et militaires se sont accordés, lundi 17 novembre, sur le nom du diplomate Michel KafandoSeize jours après la chute du président Blaise Compaoré, le Burkina Faso a un nouveau chef d'EtatA l'issue d'ultimes tractions, civils et militaires se sont accordés, lundi 17 novembre, sur le nom du diplomate Michel Kafando"
    self.label1Label.numberOfLines = 0
    self.label1Label.sizeToFit()

My problem is that if I don't set manually a width for my contentView (inside the UIScrollView), the scrolling is horizontal, not vertical. (Look Screenshot below):

I've tried to set contentSize as I've seen in many google post but without success :

self.scrollView.contentSize = CGSizeMake(400.0, 600.0)

If I set a width manually for my contentview (i.e : 320pts), the scrolling will be vertical (GOOD) but then depending on the iphone size, it won't cover the whole width of the screen as shown in the following screenshot :

The question is : what is the correct implementation to use UIScrollView to have a contentView that respect the autolayout constraint (full screen : 0top - 0bottom - 0left - 0right) and the scrolling to be only vertical.

Thanks a lot for your help!

回答1:

Mike Woelmer shows how to do this correctly with Interface Builder on the Atomic Object blog.

http://spin.atomicobject.com/2014/03/05/uiscrollview-autolayout-ios/

I also have my own code only (no storyboard implementation) on github.

https://github.com/nadthevlad/AutolayotScrollview

You don't want to set the height or width of your content or views. Instead you want to use Autolayouts pins and constraints to set how the scrollview behaves.

  1. Create your UIScrollView *scrollView.

  2. You want to create one UIView *contentView which you will put the rest of your view elements into.

    [self.view addSubview:scrollView];
    [scrollView addSubview:contentView];
    [contentView addSubview:_label1];
    [contentView addSubview:_label2];
    [contentView addSubview:_label3];
    [contentView addSubview:_label4];
    [contentView addSubview:_label5];
    [contentView addSubview:_label6];
    
  3. Pin the 4 edges of scrollView to the 4 edges of self.view

  4. Pin the top and bottom edges of contentView to the top and bottom of scrollView.

  5. This is the tricky part. To set the horizontal sizing, you want the leading (right) and trailing(left) edges of the contentView to be pinned to the leading and trailing edges self.view instead of scrollView. Even though contenView is a sub view of scrollView its horizontal constraints are going to reach outside of the scrollView and connect to self.view.

  6. Pin any other view elements to contentView as you normally would.



回答2:

The trick to permitting a UIScrollView to scroll in only one direction is to make the content size of the UIScrollView for the restricted dimension the same as the size of the UIScrollView's frame in the same dimension. So in this case, scrollview.contentSize.width should equal scrollview.frame.size.width.

With that in mind, try the following:

  1. Ensure you have constraints set up in the same way as described in this answer

  2. Add the following code to your view controller:

    override func viewWillLayoutSubviews()
    {
        super.viewWillLayoutSubviews();
        self.scrollView.contentSize.height = 3000; // Or whatever you want it to be.
    }
    

Personally, I'm really not a fan of Auto Layout. If you are interested in trying this without Auto Layout - ie. just with code instead of constraints - you could turn off Auto Layout for the view controller's view and change your viewWillLayoutSubviews method to look like this:

override func viewWillLayoutSubviews()
{
    super.viewWillLayoutSubviews();

    self.scrollView.frame = self.view.bounds; // Instead of using auto layout
    self.scrollView.contentSize.height = 3000; // Or whatever you want it to be.
}


回答3:

This how I always do it for scrolling vertically from storyboard with constraints :

1-drag a viewcontroller

2-drag a scrollview in the controller's main view with constraints L=0 , T =0 , T =0 and B = 0 to its superview (controller's main view).

3-drag a UIVIew into the scroll view to work as its content view with constraints L-0,T=0,T=0,B=0 to its superview(the scrollview)

  • well here its time for setting Content size of scroll view , which controls scrolling both Horizontally and vertically as follows.

4-for stoping horizontal scrolling , make content view equal width to scrollview with constraint.

5-make height of content view equal hight of controller's view , This is temporary till we fill it with scrollable content .

6-add controls in the content view till finish .

7-and the most important delete the constraint you made in point 5 of the hight of content view and instead of it make constraint from the control on bottom of content view to have bottom alignment to it . This helps in making content view hight starts from first control on top and down till last control (it is all depends on this step).

8-just run and results should be as expected , otherwise please let me know .

Hope this helps!



回答4:

I use this implementation for only horizontal/vertical scrollviews, although it is in Objective-C, I will try to explain the logic if something is unclear to you.

//Getting iDevice's screen width
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenWidth = screenRect.size.width;

//Setting the right content size - only height is being calculated depenging on content.
CGSize contentSize = CGSizeMake(screenWidth, HEIGHT_OF_YOUR_CONTENT);
self.scrollView.contentSize = contentSize;

Now the width of the contentSize property of the scrollview is being attached to the actual width of the device's screen, so the scrollview will be scrolling only in vertical direction.



回答5:

Thanks to @NadtheVlad, I finally saw the light. Some further fiddling taught me that contentView just needs to be pinned to scrollView's Top, Bottom and Width. No need to reference self.view.

With EasyPeasy, this is simply:

scrollView <- Edges()
contentView <- [Top(), Bottom(), Width().like(scrollView)]