如何以编程方式调整 UIScrollView 中内容视图的大小?

How to resize content view in UIScrollView programmatically?

这里是问题所在:我需要以编程方式将包含其他子视图的视图添加到滚动视图。此外,我还需要让这样一个视图的框架紧贴主超视图的边界。下面的代码显示了我试图实现的方法,但是正如您从下面的图片中看到的那样,'contentView' 在屏幕旋转时不会更新其帧大小。出于演示目的,初始代码取自 here。任何帮助将不胜感激。

import UIKit

class TestViewController : UIViewController {
    
    var contentViewSize = CGSize()
    
    let contentView: UIView = {
        let view = UIView()
        view.backgroundColor = .magenta
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()
    
    let labelOne: UILabel = {
        let label = UILabel()
        label.text = "Scroll Top"
        label.backgroundColor = .red
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()
    
    let labelTwo: UILabel = {
        let label = UILabel()
        label.text = "Scroll Bottom"
        label.backgroundColor = .green
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()
    
    let scrollView: UIScrollView = {
        let v = UIScrollView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.backgroundColor = .cyan
        return v
    }()
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        contentViewSize = view.bounds.size
        labelTwo.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: (contentViewSize.width - labelTwo.frame.size.width - 16.0)).isActive = true
        
        labelTwo.topAnchor.constraint(equalTo: contentView.topAnchor, constant: (contentViewSize.height - labelTwo.frame.size.height - 16.0)).isActive = true
    }
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        contentViewSize = view.bounds.size
        
        view.backgroundColor = .yellow
        
        self.view.addSubview(scrollView)
        
        scrollView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 8.0).isActive = true
        scrollView.topAnchor.constraint(equalTo: view.topAnchor, constant: 8.0).isActive = true
        scrollView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -8.0).isActive = true
        scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -8.0).isActive = true
        
        scrollView.addSubview(contentView)
        
        contentView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor, constant: 16).isActive = true
        contentView.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 16).isActive = true
        contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: 16).isActive = true
        contentView.rightAnchor.constraint(equalTo: scrollView.rightAnchor, constant: 16).isActive = true
        
        contentView.addSubview(labelOne)
        
        labelOne.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16.0).isActive = true
        labelOne.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 16.0).isActive = true
        
        contentView.addSubview(labelTwo)
        
        labelTwo.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: (contentViewSize.width - labelTwo.frame.size.width - 16.0)).isActive = true
        
        labelTwo.topAnchor.constraint(equalTo: contentView.topAnchor, constant: (contentViewSize.height - labelTwo.frame.size.height - 16.0)).isActive = true
        
        labelTwo.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -16.0).isActive = true
        labelTwo.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -16.0).isActive = true
        
    }
    
}

您对链接到的答案中的代码进行了一些奇怪的更改。另外,那个答案有点out-of-date.

这是一个更好的例子。假设您想要 仅垂直 滚动,这将:

  • 添加一个青色滚动视图,在 safe-area
  • 的每一侧插入 8 磅
  • 向滚动视图添加洋红色“内容视图”,每侧 16 磅 限制为滚动视图的 contentLayoutGuide,宽度为 32-点小于滚动视图的框架(每边 16 点)
  • 在内容视图的 top-left 添加标签
  • 在内容视图的 bottom-right 添加标签
  • 将底部标签限制在顶部标签下方 1500 磅(因此它会垂直滚动)

代码:

class ScrollTestViewController : UIViewController {
    
    let contentView: UIView = {
        let view = UIView()
        view.backgroundColor = .magenta
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()
    
    let labelOne: UILabel = {
        let label = UILabel()
        label.text = "Scroll Top"
        label.backgroundColor = .red
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()
    
    let labelTwo: UILabel = {
        let label = UILabel()
        label.text = "Scroll Bottom"
        label.backgroundColor = .green
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()
    
    let scrollView: UIScrollView = {
        let v = UIScrollView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.backgroundColor = .cyan
        return v
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = .yellow
        
        // add the scroll view
        self.view.addSubview(scrollView)
        
        // add contentView to scroll view
        scrollView.addSubview(contentView)
        
        // add two labels to contentView
        contentView.addSubview(labelOne)
        contentView.addSubview(labelTwo)
                
        // respect safe-area
        let g = view.safeAreaLayoutGuide
        
        // if you want to ignore the safe-area (bad idea),
        //  use this instead
        //let g = view!
        //scrollView.contentInsetAdjustmentBehavior = .never
        
        // we're going to constrain the contentView to the scroll view's content layout guide
        let scg = scrollView.contentLayoutGuide
        
        NSLayoutConstraint.activate([
            
            // constrain scrollView Top / Leading / Trailing / Bottom to view (safe-area)
            //  with 8-pts on each side
            scrollView.topAnchor.constraint(equalTo: g.topAnchor, constant: 8.0),
            scrollView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 8.0),
            scrollView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -8.0),
            scrollView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -8.0),
            
            // constrain contentView Top / Leading / Trailing / Bottom to scroll view's Content Layout Guide
            //  with 16-pts on each side
            contentView.topAnchor.constraint(equalTo: scg.topAnchor, constant: 16.0),
            contentView.leadingAnchor.constraint(equalTo: scg.leadingAnchor, constant: 16.0),
            contentView.trailingAnchor.constraint(equalTo: scg.trailingAnchor, constant: -16.0),
            contentView.bottomAnchor.constraint(equalTo: scg.bottomAnchor, constant: -16.0),

            // if we only want vertical scrolling, constrain contentView Width
            // to scrollView's Frame Layout Guide minus 32-pts (because we have 16-pts on each side)
            contentView.widthAnchor.constraint(equalTo: scrollView.frameLayoutGuide.widthAnchor, constant: -32.0),
            
            // constrain labelOne Top / Leading 16-pts to contentView Top / Leading
            //  (so it shows up at top-left corner)
            labelOne.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 16.0),
            labelOne.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16.0),
            
            // constrain labelTwo Bottom / Trailing 16-pts to contentView Bottom / Trailing
            //  (so it shows up at bottom-right corner)
            labelTwo.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16.0),
            labelTwo.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -16.0),
            
            // constrain labelTwo Top to labelOne Bottom + 1500-pts
            //  so we'll have some vertical scrolling to get to it
            labelTwo.topAnchor.constraint(equalTo: labelOne.bottomAnchor, constant: 1500.0),
            
        ])
                
    }
    
}