UIImageView 切入 UIScrollView 内部

UIImageView cuts inside UIScrollView

我正在尝试使用以下代码创建 UIScrollView With UIStackView,其中包含多个 UIImageView

let stackView = UIStackView(frame: .zero)

scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.backgroundColor = .green
scrollView.showsHorizontalScrollIndicator = false
scrollView.delegate = self

self.view.addSubview(scrollView)


scrollView.anchor(top: textSV.bottomAnchor, leading: self.view.safeAreaLayoutGuide.leadingAnchor, bottom: anotherView?.topAnchor, trailing: self.view.safeAreaLayoutGuide.trailingAnchor)
scrollView.widthAnchor.constraint(equalToConstant: UIScreen.main.bounds.width).isActive = true

scrollView.contentInsetAdjustmentBehavior = .never

stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.distribution = .equalSpacing
stackView.spacing = 0

scrollView.addSubview(stackView)
stackView.fillSuperview()

for _ in 1...8 {
    let pageView = UIImageView(image: UIImage(named: "iphone12mockup"))
    pageView.clipsToBounds = true
    pageView.contentMode = .scaleAspectFit

    pageView.translatesAutoresizingMaskIntoConstraints = false
    stackView.addArrangedSubview(pageView)

    pageView.anchor(top: stackView.topAnchor, leading: nil, bottom: stackView.bottomAnchor, trailing: nil)
}

问题是 UIImageView 没有调整到 scaleAspectFit 并且看起来像这样(看不到完整图像):

编辑

let img = UIImage(named: "iphone12mockup")
let width = img?.size.width

let pageView = UIImageView(image: img)
pageView.clipsToBounds = true
pageView.contentMode = .scaleAspectFit

pageView.translatesAutoresizingMaskIntoConstraints = false
stackView.addArrangedSubview(pageView)

pageView.anchor(top: stackView.topAnchor, leading: nil, bottom: stackView.bottomAnchor, trailing: nil)
pageView.widthAnchor.constraint(equalToConstant: width!).isActive = true

您想使用滚动视图的内容和框架布局指南...

  • 将堆栈视图的所有 4 个边限制为滚动视图的内容布局指南
  • 将堆栈视图的高度限制为滚动视图的框架布局指南

对于您添加到堆栈视图的每个图像视图:

  • 将图像视图的宽度限制为滚动视图的框架布局指南

这是一个完整的例子:

class ViewController: UIViewController, UIScrollViewDelegate {
    
    override func viewDidLoad() {
        super.viewDidLoad()

        // just trying to include what you've shown
        let textSV = UILabel()
        textSV.backgroundColor = .yellow
        textSV.text = "textSV"
        textSV.textAlignment = .center
        
        let anotherView = UILabel()
        anotherView.backgroundColor = .cyan
        anotherView.text = "anotherView"
        anotherView.textAlignment = .center
        
        [textSV, anotherView].forEach {
            [=10=].translatesAutoresizingMaskIntoConstraints = false
            view.addSubview([=10=])
        }
        
        // respect safe area
        let safeG = view.safeAreaLayoutGuide
        
        NSLayoutConstraint.activate([
            textSV.topAnchor.constraint(equalTo: safeG.topAnchor),
            textSV.leadingAnchor.constraint(equalTo: safeG.leadingAnchor),
            textSV.trailingAnchor.constraint(equalTo: safeG.trailingAnchor),
            textSV.heightAnchor.constraint(equalToConstant: 60.0),

            anotherView.leadingAnchor.constraint(equalTo: safeG.leadingAnchor),
            anotherView.trailingAnchor.constraint(equalTo: safeG.trailingAnchor),
            anotherView.bottomAnchor.constraint(equalTo: safeG.bottomAnchor),
            anotherView.heightAnchor.constraint(equalToConstant: 60.0),
        ])

        let scrollView = UIScrollView()
        scrollView.translatesAutoresizingMaskIntoConstraints = false
        scrollView.backgroundColor = .green
        scrollView.showsHorizontalScrollIndicator = false
        scrollView.delegate = self

        view.addSubview(scrollView)
        
        // use a stack view to hold and arrange the scrollView's subviews
        let stackView = UIStackView()
        stackView.translatesAutoresizingMaskIntoConstraints = false
        
        // add the stackView to the scrollView
        scrollView.addSubview(stackView)
        
        // use scrollView's Content Layout Guide to define scrollable content
        let layoutG = scrollView.contentLayoutGuide
        
        // use scrollView's Frame Layout Guide to define content height (since you want horizontal scrolling)
        let frameG = scrollView.frameLayoutGuide
        
        NSLayoutConstraint.activate([

            // constrain scrollView Top to textSV Bottom
            scrollView.topAnchor.constraint(equalTo: textSV.bottomAnchor),
            
            // constrain scrollView Leading/Trailing to safe area
            scrollView.leadingAnchor.constraint(equalTo: safeG.leadingAnchor),
            scrollView.trailingAnchor.constraint(equalTo: safeG.trailingAnchor),
            
            // constrain scrollView Bottom to anotherView Top
            scrollView.bottomAnchor.constraint(equalTo: anotherView.topAnchor),
            
            // constrain all 4 sides of the stackView to scrollView's Content Layout Guide
            stackView.topAnchor.constraint(equalTo: layoutG.topAnchor),
            stackView.bottomAnchor.constraint(equalTo: layoutG.bottomAnchor),
            stackView.leadingAnchor.constraint(equalTo: layoutG.leadingAnchor),
            stackView.trailingAnchor.constraint(equalTo: layoutG.trailingAnchor),
            
            // constrain stackView's height to scrollView's Frame Layout Guide height
            stackView.heightAnchor.constraint(equalTo: frameG.heightAnchor),
            
        ])
        
        // add imageViews to the stack view
        for _ in 1...8 {
            let pageView = UIImageView(image: UIImage(named: "iphone12mockup"))
            //let pageView = UIImageView(image: UIImage(named: "sample"))
            // set image view background color so you can
            //  see its frame (since the image will be aspect-fit scaled)
            pageView.backgroundColor = .systemYellow
            pageView.contentMode = .scaleAspectFit
            // add it to the stack view
            stackView.addArrangedSubview(pageView)
            // constrain its Width to scrollView's Frame Layout Guide Width
            pageView.widthAnchor.constraint(equalTo: frameG.widthAnchor).isActive = true
        }

    }
    
}

启动时看起来像这样(在 iPhone 8 上):

向右滚动一点后:

请注意,由于您希望图像视图设置为 Aspect Fit,我为“pageView”图像视图设置了 .systemYellow 的背景颜色,因此您可以看到 imageView 框架填充了滚动视图框架宽度和高度。


Edit -- 如果你想让图片与它们的高度成比例,而不是“边上空 space”,你需要设置图片视图宽度约束与其高度成比例,基于图像大小。

将“添加图像视图”循环替换为:

    // add imageViews to the stack view
    for _ in 1...8 {
        guard let img = UIImage(named: "iphone12mockup") else {
            fatalError("Could not load image!")
        }
        let pageView = UIImageView()
        pageView.image = img
        pageView.contentMode = .scaleToFill
        // add it to the stack view
        stackView.addArrangedSubview(pageView)
        // constrain its Width proportional to the image height
        pageView.widthAnchor.constraint(equalTo: pageView.heightAnchor, multiplier: img.size.width / img.size.height).isActive = true
    }

输出将是:

向右滚动一点后: