ScrollableController

使用帶有 UIScrollView 的 Autolayout 時,根據其內容或子檢視的大小,它不會正確調整大小。

為了讓 UIScrollView 在其內容變得太大而無法放入可見區域時自動滾動,我們需要新增一個 ContentView 和一些約束,允許 UIScrollView 確定其內容的大小及其父級的寬度和高度檢視。

import Foundation
import UIKit

class ScrollableController : UIViewController {
    
    private var scrollView: UIScrollView!
    private var contentView: UIView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        //Setup
        self.initControls()
        self.setTheme()
        self.layoutScrollView()
        self.layoutContentView()
        
        //Add child views
        self.addChildViews()
    }
    
    func initControls() {
        self.scrollView = UIScrollView()
        self.contentView = UIView()
    }
    
    func setTheme() {
        self.scrollView.backgroundColor = UIColor.blue()
        self.contentView.backgroundColor = UIColor.orange()
    }
    
    func layoutScrollView() {
        self.view.addSubview(self.scrollView)
        
        let views: NSDictionary = ["scrollView": self.scrollView]
        var constraints = Array<String>()
        
        //Constrain the scrollView to our controller's self.view.
        constraints.append("H:|-0-[scrollView]-0-|")
        constraints.append("V:|-0-[scrollView]-0-|")
        
        for constraint in constraints {
            self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: constraint, options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views as! [String : AnyObject]))
        }
        
        self.scrollView.translatesAutoresizingMaskIntoConstraints = false
    }
    
    func layoutContentView() {
        self.scrollView.addSubview(self.contentView)
        
        let views: NSDictionary = ["contentView": self.contentView, "view": self.view]
        var constraints = Array<String>()
        
        //Constrain the contentView to the scrollView.
        constraints.append("H:|-0-[contentView]-0-|")
        constraints.append("V:|-0-[contentView]-0-|")
        
        for constraint in constraints {
            self.scrollView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: constraint, options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views as! [String : AnyObject]))
        }
        
        //Disable Horizontal Scrolling by making the contentView EqualWidth with our controller's self.view (ScrollView's parentView).
        self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:[contentView(==view)]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views as! [String : AnyObject]))
        
        self.contentView.translatesAutoresizingMaskIntoConstraints = false
    }
    
    func addChildViews() {
        //Init
        let greenView = UIView()
        let whiteView = UIView()
        
        //Theme
        greenView.backgroundColor = UIColor.green()
        whiteView.backgroundColor = UIColor.orange()
        
        //Layout -- Child views are added to the 'ContentView'
        self.contentView.addSubview(greenView)
        self.contentView.addSubview(whiteView)
        
        let views: NSDictionary = ["greenView": greenView, "whiteView": whiteView];
        var constraints = Array<String>()
        
        //Constrain the greenView to the contentView with a height of 400 and 15 spacing all around.
        constraints.append("H:|-15-[greenView]-15-|")
        constraints.append("V:|-15-[greenView(400)]")
        
        //Constrain the whiteView below the greenView with 15 spacing all around and a height of 500.
        constraints.append("H:|-15-[whiteView]-15-|")
        constraints.append("V:[greenView]-15-[whiteView(500)]-15-|")
        
        for constraint in constraints {
            self.contentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: constraint, options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views as! [String : AnyObject]))
        }
        
        greenView.translatesAutoresizingMaskIntoConstraints = false
        whiteView.translatesAutoresizingMaskIntoConstraints = false
    }
}

現在我們可以看到 greenView(400 高度)+ whiteView(500 高度)比我們的螢幕大。這將導致 ScrollView 的 contentSize 增長到適合兩個檢視,允許它垂直滾動。

我們在 contentViewself.view 上使用 EqualWidth 約束禁用了水平滾動

StackOverflow 文件