首页 > 解决方案 > Swift:以编程方式添加视图时,UIScrollView 的可滚动内容大小不明确,而不使用 IB

问题描述

我在不使用情节提要的情况下以编程方式创建我的视图。当调试视图层次结构打开时,我从 Xcode 中得到这个问题“运行时:布局问题:UIScrollView 的可滚动内容大小不明确”。我认为这意味着对 scollView 的限制尚不清楚。

我可以看到 scrollView 在视图层次结构中显示(黄色之一),但它的子视图 UIView 不是。使用故事板/IB 找到一些解决方案,尽管我无法将其与我的代码联系起来。任何提示和建议表示赞赏。

在此处输入图像描述

下面是scrollView的结构。

ScrollView
  ->UIView as contentView(coverImageContainer)
      -> UIImageView(coverArtImageView)
      -> UIButton
// scroller
    lazy var scrollView: UIScrollView = {
        let scrollView = UIScrollView()
        scrollView.translatesAutoresizingMaskIntoConstraints = false
//        scrollView.contentMode = .scaleToFill
        scrollView.contentInsetAdjustmentBehavior = .never
        scrollView.alwaysBounceVertical = true
        scrollView.backgroundColor = .yellow
        
        return scrollView
    }()
    
    // cover image
    lazy var coverImageContainer: UIView = {
        let containerView = UIView()
        containerView.translatesAutoresizingMaskIntoConstraints = false
        return containerView
    }()
    
    lazy var coverArtImageView: UIImageView = {
        let imageView = UIImageView()
        imageView.translatesAutoresizingMaskIntoConstraints = false
        imageView.contentMode = .scaleAspectFit
        imageView.layer.cornerRadius = 5
        return imageView
    }()
    
    lazy var dismissChevron: UIButton = {
        let btn = UIButton()
        btn.translatesAutoresizingMaskIntoConstraints = false
        btn.addTarget(self, action: #selector(disimissAction), for: .touchUpInside)
        return btn
    }()

override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = .black
        backingImageView.image = backingImage
        
        view.addSubview(backingImageView)
        view.addSubview(dimmerLayer)
        view.addSubview(scrollView)
        scrollView.addSubview(coverImageContainer)
        scrollView.addSubview(stretchySkirt)
        coverImageContainer.addSubview(coverArtImageView)
        coverImageContainer.addSubview(dismissChevron)
        
        // set layout constraint
        configureLayout()
        ...        

    }
func configureLayout() {
        
        let g = view.safeAreaLayoutGuide
        backingImageleadInset = backingImageView.leadingAnchor.constraint(equalTo: g.leadingAnchor)
        backingImageTrailingInset = backingImageView.trailingAnchor.constraint(equalTo: g.trailingAnchor)
        backingImageTopInset = backingImageView.topAnchor.constraint(equalTo: view.topAnchor)
        backingImageBottomInset = backingImageView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        
        NSLayoutConstraint.activate([

            backingImageleadInset,
            backingImageTrailingInset,
            backingImageTopInset,
            backingImageBottomInset,
            
            dimmerLayer.leadingAnchor.constraint(equalTo: g.leadingAnchor),
            dimmerLayer.trailingAnchor.constraint(equalTo: g.trailingAnchor),
            dimmerLayer.topAnchor.constraint(equalTo: view.topAnchor),
            dimmerLayer.bottomAnchor.constraint(equalTo: view.bottomAnchor),

            scrollView.leadingAnchor.constraint(equalTo: g.leadingAnchor),
            scrollView.trailingAnchor.constraint(equalTo: g.trailingAnchor),
            scrollView.topAnchor.constraint(equalTo: backingImageView.topAnchor, constant: 15),
            scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor),

            coverImageContainer.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor),
            coverImageContainer.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 57),
            coverImageContainer.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
            coverImageContainer.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
            coverImageContainer.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: -237),

            stretchySkirt.topAnchor.constraint(equalTo: coverImageContainer.bottomAnchor),
            stretchySkirt.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
            stretchySkirt.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
            stretchySkirt.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),

            coverArtImageView.centerXAnchor.constraint(equalTo: coverImageContainer.centerXAnchor),
            coverArtImageView.topAnchor.constraint(equalTo: coverImageContainer.topAnchor, constant: 38),
            coverArtImageView.leadingAnchor.constraint(equalTo: coverImageContainer.leadingAnchor, constant: 20),
            coverArtImageView.trailingAnchor.constraint(equalTo: coverImageContainer.trailingAnchor, constant: -20),
//            coverArtImageView.widthAnchor.constraint(equalToConstant: 354),
            coverArtImageView.heightAnchor.constraint(equalTo: coverArtImageView.widthAnchor),

            dismissChevron.centerXAnchor.constraint(equalTo: coverImageContainer.centerXAnchor),
            dismissChevron.topAnchor.constraint(equalTo: coverImageContainer.topAnchor, constant: 4),
        ])
    }

标签: swiftuiscrollviewautolayout

解决方案


正如 DongMag 的评论,我现在解决了这个问题。

我想要达到的效果如下图所示。就像 Apple Music 的 Max Card View。

在此处输入图像描述

好吧,问题出在coverImageContainer's 约束上,我应该将其约束为 view 或 view.safeAreaLayoutGuide 而不是 scrollView。因为我不想coverImageContainer滚动。

在这里更新我的代码,如果将来有人遇到同样的问题,他们可能会做参考:

let g = view.safeAreaLayoutGuide 
NSLayoutConstraint.activate([
            . . . 
            scrollView.leadingAnchor.constraint(equalTo: g.leadingAnchor),
            scrollView.trailingAnchor.constraint(equalTo: g.trailingAnchor),
            scrollView.topAnchor.constraint(equalTo: backingImageView.topAnchor, constant: 15),
            scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor),

            coverImageContainer.centerXAnchor.constraint(equalTo: g.centerXAnchor),
            coverImageContainer.topAnchor.constraint(equalTo: g.topAnchor, constant: 57),
            coverImageContainer.leadingAnchor.constraint(equalTo: g.leadingAnchor),
            coverImageContainer.trailingAnchor.constraint(equalTo: g.trailingAnchor),
            coverImageContainer.heightAnchor.constraint(equalTo: coverImageContainer.widthAnchor),

            stretchySkirt.topAnchor.constraint(equalTo: coverImageContainer.bottomAnchor),
            stretchySkirt.leadingAnchor.constraint(equalTo: g.leadingAnchor),
            stretchySkirt.trailingAnchor.constraint(equalTo: g.trailingAnchor),
            stretchySkirt.bottomAnchor.constraint(equalTo: view.bottomAnchor),

            coverArtImageView.centerXAnchor.constraint(equalTo: coverImageContainer.centerXAnchor),
            coverArtImageView.topAnchor.constraint(equalTo: coverImageContainer.topAnchor, constant: 38),
            coverArtImageView.leadingAnchor.constraint(equalTo: coverImageContainer.leadingAnchor, constant: 38),
            coverArtImageView.heightAnchor.constraint(equalTo: coverArtImageView.widthAnchor),

            dismissChevron.centerXAnchor.constraint(equalTo: coverImageContainer.centerXAnchor),
            dismissChevron.topAnchor.constraint(equalTo: coverImageContainer.topAnchor, constant: 4),
        ])

推荐阅读