4

I have setup a UIScrollView which contains two ViewController's. This is how my viewDidLoad looks like:

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    scrollView.delegate = self

    self.automaticallyAdjustsScrollViewInsets = false

    let allViewController = self.storyboard!.instantiateViewControllerWithIdentifier("All") as! AllViewController;
    let favoritesViewController = self.storyboard!.instantiateViewControllerWithIdentifier("Favorites") as! FavoritesViewController;

    scrollView!.contentSize = CGSizeMake(2*CGRectGetWidth(allViewController.view.frame), CGRectGetHeight(scrollView!.frame));

    let viewControllers = [allViewController, favoritesViewController]

    var idx:Int = 0;

    for viewController in viewControllers {
        addChildViewController(viewController);
        let originX:CGFloat = CGFloat(idx) * CGRectGetWidth(scrollView!.frame);
        viewController.view.frame = CGRectMake(originX, 0, viewController.view.frame.size.width, viewController.view.frame.size.height);
        scrollView!.addSubview(viewController.view)
        viewController.didMoveToParentViewController(self)
        idx++;
    } 

On the iPhone 6 simulator everything works ok, but when I run it on the iPhone 5 simulator there is gap between the controllers when scrolling:

[enter image description here] The scrollView has auto layout set as 0 for leading, trailing, top and bottom.

Adrian
  • 19,440
  • 34
  • 112
  • 219

4 Answers4

2

If you want to set the origins in viewDidLoad: and you definitely know that your scroll view will have the width of your screen, in your calculation logic instead of CGRectGetWidth(scrollView!.frame) use

var bounds = UIScreen.mainScreen().bounds
var width = bounds.size.width

in order to get proper width before your subviews did layout.

Code: Working Github Project

UPD: As someone mentioned here, I unchecked scrollview's Autoresize Subviews property, subclassed UITableViewCell and pushed my commit to github. Check it through the link I provided above. Here you are the results with button aligned to the right:

Results:

enter image description here enter image description here

Reference: The main concepts are described in my SO answer here

Community
  • 1
  • 1
Neil Galiaskarov
  • 5,015
  • 2
  • 27
  • 46
  • Its still not working, now the gap is half the size, and the other half appears after the second view controller...so green -> white(gap) -> purple -> white – Adrian Jul 29 '15 at 18:58
  • Thanks, it is now working. I will award the bounty to you in 12 hours. I have only one final question. My test project its working, but I have a two tableview's instead of viewcontrollers in my real project (UIViewControllers which implements UITableViewDelegate, UITableViewDataSource), and I have a button on the right side of the UITableViewCell, I made this changes over there too, but I still can't see the rght side of the cell, its outside o the scree. Any suggestions why is this happening ? – Adrian Jul 30 '15 at 05:59
  • @Adrian, can try your case in 3-4 hours and will post updated project – Neil Galiaskarov Jul 30 '15 at 07:57
  • @Adrian please see my updated answer and please dont forget to award the bounty :) – Neil Galiaskarov Jul 30 '15 at 13:38
  • Btw, I saw that you were using 4 inch storyboards....if I use 4.7 inch storyboards in your project then I still have my problem, of not seeing the right hand side button. If you have the time, can you update to work with 4.7 storyboards ? I will appreciate it. – Adrian Jul 31 '15 at 19:12
1

You're setting the view controller positions in view did load. At that point, the views will have the dimensions matching the size of the views from your storyboard. I'm assuming you're using 4.7" views in your storyboards. This means that in viewDidLoad, you're setting the second view controller's x position to 375. Set the view controller position in viewWillAppear or didLayoutSubviews to get the correct width of the view (320 on iPhone 5). Note, both of those methods can be called more than once so plan accordingly.

Sean Kladek
  • 4,396
  • 1
  • 23
  • 29
  • I have set the content size of the scrollview inside viewWillAppear, but it behaves the same. And yes I am using 4.7 storyboards – Adrian Jul 29 '15 at 18:44
  • 1
    `viewWillAppear:` is also to early. You should set the frames in `viewDidLayoutSubviews`, or create constraints to lay them out. You can create the constraints in `viewDidLoad`. – rob mayoff Jul 29 '15 at 18:46
  • Even in viewDidLayoutSubviews, still there is a gap. I have set constraints inside the storyboard – Adrian Jul 29 '15 at 18:48
  • What constraints have you set in the storyboard? Are these constraints limiting setting the positioning of the view controllers in the scroll view? – Sean Kladek Jul 29 '15 at 18:52
  • For the scrollview 0 to top/bottom/leading/trailing – Adrian Jul 29 '15 at 18:56
1

If your subviews should always be the size of the scroll view the simplest solution may be to add a custom subclass of UIScrollView that just layouts all subviews in the order they where added like so:

import UIKit

class MyScrollView: UIScrollView {

    override func layoutSubviews() {
        super.layoutSubviews()
        var idx:Int = 0;
        contentSize = CGSizeMake(2*CGRectGetWidth(bounds), CGRectGetHeight(bounds));
        for sview in self.subviews as! [UIView] {
            let originX:CGFloat = CGFloat(idx) * CGRectGetWidth(bounds);
            sview.frame = CGRectMake(originX, 0, CGRectGetWidth(bounds), CGRectGetHeight(bounds));
            idx++
        }
    }

}

You can then simplify viewDidLoad to

override func viewDidLoad() {
    super.viewDidLoad()

    self.automaticallyAdjustsScrollViewInsets = false

    let allViewController = self.storyboard!.instantiateViewControllerWithIdentifier("All") as! AllViewController;
    let favoritesViewController = self.storyboard!.instantiateViewControllerWithIdentifier("Favorites") as! FavoritesViewController;

    for viewController in [allViewController, favoritesViewController] {
        addChildViewController(viewController);
        scrollView!.addSubview(viewController.view)
        viewController.didMoveToParentViewController(self)
    }
}
Stefan
  • 1,496
  • 1
  • 13
  • 26
  • Yes, this must be needed too. – Adrian Jul 29 '15 at 19:23
  • Changed suggestion to disable layout of subviews to manually layout subviews in a custom subclass of UIScrollView. Will handle rotataton and size changes to to in call status bar, size changes in iOS 9 multitasking etc – Stefan Jul 29 '15 at 20:12
0

Add two subviews in your scrollview as placeholders, and add constraints betwen them and scrollview, and make two @IBOutlet to placeholders.
In viewDidLoad just set scrollView size, add childViewControlers and their views add to placeholders

iamandrewluca
  • 3,411
  • 1
  • 31
  • 38