UIScrollViews contentOffset is broken with AutoLayout

Originator:let.adrian.know
Number:rdar://22770934 Date Originated:19-Sep-2015 07:09 PM
Status:Closed Resolved:21-Sep-2015 00:40 PM
Product:iOS SDK Product Version:Xcode 7
Classification:UI/Usability Reproducible:Always
 
Summary:
The contentOffset property of an UIScrollView does not begin at the origin of the UIScrollView. Instead container subview will begin at the screen origin (top left corner).

Expected Results:
Container view should sit at the origin of the scrollview.

Actual Results:
Container view will sit at the top left of the screen.

Version:
iOS 9 +

Sourcecode:

class ViewController: UIViewController, UIScrollViewDelegate {
	
	private let scrollView = UIScrollView()
	private let containerView = UIView()

	override func loadView() {
		
		self.view = UIView()
		self.view.backgroundColor = UIColor.whiteColor()
	}
	
	override func viewDidLoad() {
		
		super.viewDidLoad()
		
		self.scrollView.layer.borderColor = UIColor.greenColor().CGColor
		self.scrollView.layer.borderWidth = 1.0
		self.scrollView.clipsToBounds = false
		
		self.scrollView.translatesAutoresizingMaskIntoConstraints = false
		
		self.view.addSubview(scrollView)
		
		self.scrollView.topAnchor.constraintEqualToAnchor(self.view.topAnchor, constant: 40).active = true
		self.scrollView.heightAnchor.constraintEqualToAnchor(self.view.widthAnchor).active = true
		self.scrollView.widthAnchor.constraintEqualToAnchor(self.view.widthAnchor).active = true
		
		self.containerView.backgroundColor = UIColor.redColor()
		self.containerView.translatesAutoresizingMaskIntoConstraints = false
		
		self.scrollView.addSubview(self.containerView)
		
		self.containerView.widthAnchor.constraintEqualToAnchor(self.scrollView.widthAnchor).active = true
		self.containerView.heightAnchor.constraintEqualToAnchor(self.scrollView.heightAnchor).active = true
	}
	
	override func viewDidLayoutSubviews() {
		
		super.viewDidLayoutSubviews()
		
		print("content offset: \(self.scrollView.contentOffset)")
		print("origin: \(self.scrollView.frame.origin)")
		print("they to not match visually, but they should :( <-- BROKEN !!!")
	}
	
	override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
		
		return UIInterfaceOrientationMask.Portrait
	}

	override func prefersStatusBarHidden() -> Bool {
		
		return false
	}
}

Comments

The solution was:

self.containerView.topAnchor.constraintEqualToAnchor(self.scrollView.topAnchor).active = true self.containerView.leftAnchor.constraintEqualToAnchor(self.scrollView.leftAnchor).active = true self.containerView.rightAnchor.constraintEqualToAnchor(self.scrollView.rightAnchor).active = true self.containerView.bottomAnchor.constraintEqualToAnchor(self.scrollView.bottomAnchor).active = true

// actually the debugger showed two different constraints, but this had no effect on the functionality // trailing and button constraints where like this:

// self.scrollView.trailingAnchor.constraintEqualToAnchor(self.containerView.trailingAnchor).active = true // self.scrollView.bottomAnchor.constraintEqualToAnchor(self.containerView.bottomAnchor).active = true

By let.adrian.know at Sept. 20, 2015, 10:43 p.m. (reply...)

Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!