为啥 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 Interface builder缺少视图层次结构
尝试呈现其视图不在窗口层次结构中的 UIAlertController (Swift 3/Xcode 8)