user1019042 user1019042 - 7 months ago 47
Swift Question

How to fix AutoLayout for my ScrollView?

I have a view controller that has a UIView(ParentView) and then UIScrollview(ScrollView). The ParentView is anchored to the leading, trailing, top and bottom of the ViewController. The ScrollView is anchored to the leading, trailing, top and bottom of the ParentView. The structure is like this:

-UIView
--ParentView
---ScrollView


Then I created a xib file that has an image and a label. The xib will be added dynamically to the ScrollView. The xib frame height and width are equal to the ScrollView height and width.

When I run the simulator on iphone 6 plus the scroll works perfectly; the width of the xib is exactly the width of the screen. But when i run the simulator with iphone 6, the width of the xib is the same size of the screen, there is an extra space when scrolling to the next item. What should I do to removed it!?

This is a screen shot for iphone 6 plus

enter image description here

This is a screen shot for iphone 6. Notice the extra space of the second screen
enter image description here

And here is my code:

import UIKit
class ViewController: UIViewController {
@IBOutlet weak var ParentView: UIView!
@IBOutlet weak var ScrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let photos = ["joe", "john"]
let userNames = ["joe", "john"]
self.ScrollView.frame = CGRectMake(0, 0, self.ParentView.frame.size.width, self.ParentView.frame.size.height)

self.ScrollView.contentSize = CGSizeMake(self.ParentView.frame.size.width * CGFloat(photos.count), self.ParentView.frame.size.height)
self.ScrollView.pagingEnabled = true
var i: Int = 0
while i < 2 {
if let userXib = NSBundle.mainBundle().loadNibNamed("User", owner: self, options: nil)[0] as? User {
userXib.frame = CGRect(x: self.ScrollView.frame.size.width * CGFloat(i), y: 0, width: self.ScrollView.frame.size.width, height: userXib.frame.size.height)
userXib.assignValues(photos[i], myName: userNames[i])
self.ScrollView.addSubview(userXib)
}
i = i + 1
}
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}


UPDATE #1 - Coder1000 solution:
I tried implementing #3 & #4 in your answer by adding the UIView layer inside the scroll. I called it ScrollMainView. In the storyboard, I set its leading, trailing, top and bottom to fill its superview: Scrollview and then in the loop added those elements to it instead of the scrollview. But now the scroll doesn't scroll! My code and final display look like this:

import UIKit
class ViewController: UIViewController {
@IBOutlet weak var ParentView: UIView!
@IBOutlet weak var ScrollView: UIScrollView!
@IBOutlet weak var ScrollMainView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
let photos = ["joe", "john"]
let userNames = ["joe", "john"]
self.ScrollView.frame = CGRectMake(0, 0, self.ParentView.frame.size.width, self.ParentView.frame.size.height)
self.ScrollView.contentSize = CGSizeMake(self.ParentView.frame.size.width * CGFloat(photos.count), self.ParentView.frame.size.height)
self.ScrollView.pagingEnabled = true
self.ScrollMainView.frame = CGRectMake(0, 0, self.ScrollView.frame.size.width, self.ScrollView.frame.size.height)
print("the frame for parentview is: \(self.ParentView.frame)")
var i: Int = 0
while i < 2 {
if let userXib = NSBundle.mainBundle().loadNibNamed("User", owner: self, options: nil)[0] as? User {
userXib.frame = CGRect(x: self.ScrollMainView.frame.size.width * CGFloat(i), y: 0, width: self.ScrollMainView.frame.size.width, height: userXib.frame.size.height)
userXib.assignValues(photos[i], myName: userNames[i])
self.ScrollMainView.addSubview(userXib)
}
i = i + 1
}
self.ScrollView.addSubview(ScrollMainView)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}


enter image description here

Answer

There are several solutions, in viewDidLoad the frame is not set correctly, so when you ask it, it is wrong.

The parentView and your scrollView are adjusted by the autolayout constraint later, but you User view is not...

A simple solution may be to put the code in:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    self.ScrollView.frame = CGRectMake(0, 0, self.ParentView.frame.size.width, self.ParentView.frame.size.height)

    self.ScrollView.contentSize = CGSizeMake(self.ParentView.frame.size.width * CGFloat(photos.count), self.ParentView.frame.size.height)
    self.ScrollView.pagingEnabled = true

    for subView: UIView in self.ScrollView.subviews {
        if subView is User { subView.removeFromSuperview()
    }

    var i: Int = 0
    while i < 2 {
        if let userXib = NSBundle.mainBundle().loadNibNamed("User", owner: self, options: nil)[0] as? User {
            userXib.frame = CGRect(x: self.ScrollView.frame.size.width * CGFloat(i), y: 0, width: self.ScrollView.frame.size.width, height: userXib.frame.size.height)
            userXib.assignValues(photos[i], myName: userNames[i])
            self.ScrollView.addSubview(userXib)
        }
        i = i + 1
    }
}    

Or you can add constraints to your custom xib programmatically.

Or you can keep an array of your costom xibs and just adjust their frames, AND THE SCROLLVIEW CONTENTSIZE, in viewDidLayoutSubviews()

Or you can put the code in viewDidAppear()