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

Posted

技术标签:

【中文标题】Swift:以编程方式添加视图时,UIScrollView 的可滚动内容大小不明确,而不使用 IB【英文标题】:Swift: Scrollable content size is ambiguous for UIScrollView when add views programmatically, without using IB 【发布时间】:2021-05-06 14:55:14 【问题描述】:

我在不使用情节提要的情况下以编程方式创建视图。当调试视图层次结构打开时,我从 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),
        ])
    

【问题讨论】:

我觉得这个链接对你有用***.com/a/59903579/5140621 您的约束并没有明确您真正想要什么...您有一个 coverImageContainer 应该是滚动视图的全宽 - 它的 Height 应该是什么?您表示您希望其底部为-237,但相对于什么?是为了让它向上滚动吗? 嗨@DonMag,coverImageContainer 的底部与它的superView(scrollView) 的底部相关,并且有一个偏移量-237。我认为这样就可以了。 @hessam mahdiabadi,谢谢,我正在调查。 @ChuckZHB - “与它的superView(scrollView)的底部有关” ...你的意思是“可滚动内容区域”还是“scrollView的FRAME”? 【参考方案1】:

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

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

好吧,问题出在coverImageContainer 的约束上,我应该将其约束到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),
        ])

【讨论】:

以上是关于Swift:以编程方式添加视图时,UIScrollView 的可滚动内容大小不明确,而不使用 IB的主要内容,如果未能解决你的问题,请参考以下文章

Swift - 以编程方式向堆栈视图添加标签

在 Swift 中以编程方式将视图添加到 stackview

当 iAd 横幅出现时,如何将视图的内容上移? (在 Swift 中以编程方式)

在 iOS Swift 3 中以编程方式添加 Web 视图时如何在 UIWebView 中获取响应状态代码?

在 Swift 中以编程方式添加时,UIScrollView 根本不滚动?

IOS swift scrollview以编程方式