I know this is a common problem having spent many days browsing similar problems and proposed solutions but, having tried everything I can find, I still can't get this work.
Here's what I'm trying to do:
- I have a master-detail view where all of the data is pulled from a remote server.
- Everything possible is done in the story board.
- In my detail view (called Main View) I have a scroll view (Scroll View) tied to the 4 edges of the Main View.
- In the Scroll View I have a content view (contentView) with all 4 edges tied to the Scroll View. The contentView width and height are also tied to the Main View width and height as I understand this is required so the Scroll View can correctly calculate its height.
- In the contentView I have 2 text labels added in the storyboard with their content added programmatically from the remote server. The first is pinned to the top of the content view and the second is pinned to the bottom of the first label.
- Also in the contentView, underneath the second text label, I programmatically add a number of images from the remote server. The number is variable but the height of each image is set programmatically. Each image is pinned to the bottom of the second label with a calculated distance so the images are spaced one above the other.
- So far all of this works. I can see the text labels and the images correctly positioned and the vertical scrolling is working. BUT, the content view (shown with a red background) is not resizing vertically so that some of the image appear outside the content view. The Scroll View is shown with a blue background: Screen shot.
I'm seeking guidance on the principles to apply to make this work, but have now included the code so someone might be able to spot where I'm going wrong. Any suggestions please?
import UIKit class DetailViewController: UIViewController { @IBOutlet var mainView: UIView! @IBOutlet weak var scrollView: UIScrollView! @IBOutlet weak var contentView: UIView! @IBOutlet weak var routeDescriptionLabel: UILabel! @IBOutlet weak var routeDetailLabel: UILabel! @IBOutlet weak var detailNavigationBar: UINavigationItem! // Create new RouteModel var routeModel:RouteModel = RouteModel() var imageNumber:Int = 0 let imageHeight:Int = 200 // Create a variable to hold the bottom constraint for the last route image so it can be tied to the bottom of the contentView in order for the scroll view to calculate its height. var lastImageBottomConstraint:NSLayoutConstraint = NSLayoutConstraint() var detailItem: AnyObject? { didSet { // Update the view. self.configureView() } } func configureView() { if let routeID = self.detailItem { if let label = self.routeDescriptionLabel { //contentView.translatesAutoresizingMaskIntoConstraints = false // Get the route details from the route model for this specified routeID var selectedRoute:Route = Route() selectedRoute = self.routeModel.getRoute(routeID as! Int) // Get the array of route image dictionaries for this route id var routeImageDictArray:[NSDictionary] = [[String:String]]() routeImageDictArray = routeModel.getRouteImages(Int(routeID as! NSNumber)) // Format the view detailNavigationBar.title = selectedRoute.routeName label.text = selectedRoute.routeDesc label.sizeToFit() self.routeDetailLabel.text = selectedRoute.routeDetails self.routeDetailLabel.sizeToFit() // Loop through the array of route images and add each image to the current view for image in routeImageDictArray { // Get the image file name var imageFileName:String = String() if var imageFileName = image["imageFile"]{ // Handle any spaces etc in the image file name imageFileName = imageFileName.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())! // Get the image and add it to the view getRouteImage(imageFileName as! String) } } // Add lastImageBottomConstraint from the last image loaded to the view so that the scroll view can correctly calculate its height self.contentView.addConstraint(self.lastImageBottomConstraint) } } } override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. self.configureView() } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } func getRouteImage(imageFileName:String) { // Set the route image ImageLoader.sharedLoader.imageForUrl("http://www.example.com/files/images/" + imageFileName, completionHandler:{(image: UIImage?, url: String) in // Create an image view for the image var imageView = UIImageView.init(frame: CGRectZero) // Set translatesautoresizingmask to false imageView.translatesAutoresizingMaskIntoConstraints = false // Increment the image number self.imageNumber++ imageView.image = image // Add the image view to the content view self.contentView.addSubview(imageView) // Add size constraints self.applySizeConstraintsToImage(imageView) // Add position constraints self.applyPositionConstraintsToImage(imageView) imageView.contentMode = UIViewContentMode.ScaleAspectFit // Create a position constraint to tie the bottom of the last image to the bottom of the view so that the scroll view can size correctly self.lastImageBottomConstraint = NSLayoutConstraint(item: imageView, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: self.contentView, attribute: NSLayoutAttribute.BottomMargin, multiplier: 1, constant: 20) }) } func applySizeConstraintsToImage(imageView:UIImageView) { // set contstraints for the imageview let heightConstraint:NSLayoutConstraint = NSLayoutConstraint(item: imageView, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: CGFloat(imageHeight)) imageView.addConstraint(heightConstraint) } func applyPositionConstraintsToImage(imageView:UIImageView) { // Set the position of the imageview let verticalConstraint:NSLayoutConstraint = NSLayoutConstraint(item: imageView, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: routeDetailLabel, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: CGFloat((20 * (imageNumber)) + (imageHeight * (imageNumber-1)))) let centerXConstraint = NSLayoutConstraint(item: imageView, attribute: .CenterX, relatedBy: .Equal, toItem: contentView, attribute: .CenterX, multiplier: 1, constant: 0); // Add position constraints to the image self.contentView.addConstraints([verticalConstraint,centerXConstraint]) } }