为啥 Xcode 模拟器视图与视图层次结构视图不同

Posted

技术标签:

【中文标题】为啥 Xcode 模拟器视图与视图层次结构视图不同【英文标题】:Why Xcode simulator view is different from view-hierarchy view为什么 Xcode 模拟器视图与视图层次结构视图不同 【发布时间】:2019-01-20 02:10:57 【问题描述】:

我正在使用自动布局约束在UICollectionView 之上开发UIImageView

我已经将UIImageView 固定在屏幕的顶部,并以固定的 4:3 的 H:W 比率占据屏幕的顶部,然后让 UICollectionView 占据底部剩余的任何空间。

奇怪的是,当我运行它时,xcode 模拟器中的视图与 view-hierarchy 调试器完全不同:

查看层次结构调试器

iPhone 8 Plus 模拟器

UICollectionView中,每个单元格都会显示一张人脸照片,我已将UICollectionView的itemSize配置为正方形。它应该显示整个面部(所以调试器视图是正确的,模拟器不是)。

// MARK: - UICollectionViewDelegateFlowLayout
extension ViewController : UICollectionViewDelegateFlowLayout 

    // set item size 
    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        sizeForItemAt indexPath: IndexPath) -> CGSize 



        // gw: to force one row, height need to be smaller than flow height
        return CGSize(width: collectionView.bounds.height, height: collectionView.bounds.height)
    

造成这种差异的原因可能是什么? 我正在使用 xcode 10.1、ios 12.1 完整代码在这里(不是很长):

import UIKit


class ViewController: UICollectionViewController

    let collectionViewCellIdentifier = "MyCollectionViewCellIdentifier"
    let canvas:Canvas = 
        let canvas = Canvas()
        canvas.backgroundColor = UIColor.black
        canvas.translatesAutoresizingMaskIntoConstraints=false
        canvas.alpha = 0.2
        return canvas
     ()

    let photoView: UIImageView = 
        let imageView = UIImageView()

        imageView.image = UIImage(imageLiteralResourceName: "hongjinbao")
        imageView.translatesAutoresizingMaskIntoConstraints = false
        imageView.contentMode = .scaleAspectFill
        return imageView
     ()


     private let myArray: NSArray = ["First","Second","Third"]

    override func viewDidLoad() 
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        // stack views
        view.addSubview(photoView)
        view.addSubview(canvas)

        collectionView?.backgroundColor = UIColor.white
        collectionView?.translatesAutoresizingMaskIntoConstraints = false

        collectionView?.register(PersonCollectionViewCell.self, forCellWithReuseIdentifier: collectionViewCellIdentifier)


        setupLayout()


    

    private func setupLayout() 


        photoView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
        photoView.heightAnchor.constraint(equalTo: view.widthAnchor,   multiplier: 1.333).isActive = true
        photoView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
        photoView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true

        canvas.topAnchor.constraint(equalTo: photoView.topAnchor).isActive = true
        canvas.bottomAnchor.constraint(equalTo: photoView.bottomAnchor).isActive = true
        canvas.leadingAnchor.constraint(equalTo: photoView.leadingAnchor).isActive = true
        canvas.trailingAnchor.constraint(equalTo: photoView.trailingAnchor).isActive = true

        collectionView?.topAnchor.constraint(equalTo: photoView.bottomAnchor).isActive = true
        collectionView?.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
        collectionView?.leadingAnchor.constraint(equalTo: photoView.leadingAnchor).isActive = true
        collectionView?.trailingAnchor.constraint(equalTo: photoView.trailingAnchor).isActive = true


    




// MARK: - UICollectionViewDataSource
extension ViewController 

    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: self.collectionViewCellIdentifier, for: indexPath)
        return cell
    


    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int 
        return 13
    




// MARK: - UICollectionViewDelegateFlowLayout
extension ViewController : UICollectionViewDelegateFlowLayout 

    // set item size 
    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        sizeForItemAt indexPath: IndexPath) -> CGSize 



        // gw: to force one row, height need to be smaller than flow height
        return CGSize(width: collectionView.bounds.height, height: collectionView.bounds.height)
    




    import UIKit

    class PersonCollectionViewCell: UICollectionViewCell 

        let face: UIImageView = 
            let imageView = UIImageView()
            imageView.image = UIImage(imageLiteralResourceName: "mary")
            imageView.translatesAutoresizingMaskIntoConstraints = false
            return imageView
         ()

        let name: UILabel = 
            let textLabel = UILabel()
            textLabel.translatesAutoresizingMaskIntoConstraints = false
            return textLabel
         ()

        let desc: UITextView = 
           let textView = UITextView()
            textView.translatesAutoresizingMaskIntoConstraints = false
            return textView
         ()

        override init(frame: CGRect) 
            super.init(frame: frame)

            setupView()
        


        // gw: needed by compiler
        required init?(coder aDecoder: NSCoder) 
            fatalError("init(coder:) has not been implemented")
        

        private func setupView() 
            addSubview(face)
            addSubview(name)
            addSubview(desc)

            backgroundColor = UIColor.red
            addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-16-[v0]|", options: NSLayoutConstraint.FormatOptions(), metrics: nil, views: ["v0":face]))
        




    

【问题讨论】:

首先,确保在界面生成器和模拟器上使用相同的屏幕尺寸。其次,您在运行时添加了约束,因此显然您期望有一些不同。我还会在控制台中检查约束错误。 【参考方案1】:

我找到了原因,这是由于我的ViewController中子视图的堆叠顺序。 photoView 被添加到 collectionView 之上,它阻止了 collectionView 的一部分。

解决方案:在viewDidLoad 中添加以下语句以将后面的语句置于前面:

 // stack views
        view.addSubview(photoView)

        // little trick to bring inherent collectionView to front
        view.bringSubviewToFront(self.collectionView)

【讨论】:

以上是关于为啥 Xcode 模拟器视图与视图层次结构视图不同的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Xcode 视图层次结构中拥有深度视图?

XCode Interface builder缺少视图层次结构

尝试呈现其视图不在窗口层次结构中的 UIAlertController (Swift 3/Xcode 8)

Android Studio 4.0+ 中新的 UI 层次结构调试工具

对 UIKit 视图层次结构感到困惑

插入 iOS 设备时如何检查“调试视图层次结构”?