通常,当您想到 super 视图与子视图的关系时,人们往往会期望子视图的原点将包含在 super 视图中(通常是 super 视图的原点)。但是,在iOS上的UIKit
中,情况似乎并非如此。为什么子视图的原始点是UIWindow
(0,0)?
为了演示,以下代码生成了两个UIView,一个是另一个的子视图。由于某种原因,innerView
的原点似乎是整个UIWindow
的(0,0)。我希望innerView
的原点是outerView
的原点(其原点由其父视图的中心点决定)。
我得到的是:
self.edgesForExtendedLayout = []
let superView = self.view!
superView.backgroundColor = .white
let outerView = UIView()
outerView.backgroundColor = .cyan
superView.addSubview(outerView)
outerView.snp.makeConstraints { make in
make.width.equalToSuperview().inset(20)
make.height.equalTo(superView.snp.height).dividedBy(3)
make.center.equalToSuperview()
}
let innerView = UIView()
innerView.backgroundColor = .purple
outerView.addSubview(innerView)
innerView.snp.makeConstraints { (make) in
make.height.width.equalToSuperview().dividedBy(2)
}
我想要的:
添加一条额外的
SnapKit
约束行会将innerView
起点设置为outerView
的起点,但是我发现这一步是多余的。self.edgesForExtendedLayout = []
let superView = self.view!
superView.backgroundColor = .white
let outerView = UIView()
outerView.backgroundColor = .cyan
superView.addSubview(outerView)
outerView.snp.makeConstraints { make in
make.width.equalToSuperview().inset(20)
make.height.equalTo(superView.snp.height).dividedBy(3)
make.center.equalToSuperview()
}
let innerView = UIView()
innerView.backgroundColor = .purple
outerView.addSubview(innerView)
innerView.snp.makeConstraints { (make) in
make.top.left.equalToSuperview() // Set origins equal
make.height.width.equalToSuperview().dividedBy(2)
}
到目前为止,这可能是对iOS中视图层次结构的一个基本误解,因为我一直依靠Storyboard。这是我首次涉足iOS上的程序化UI,因此我仍会全神贯注于所有细微差别。现在,证据使我相信,每个视图(无论它在视图层次结构中的位置如何)都始于键
UIWindow
的位置(0,0)。 最佳答案
每个视图中都有一个新的坐标空间。该窗口无法确定没有原点的子视图的原点。关于示例的最有趣的事情是,您没有给紫色视图画框,因此也没有原点。如果要打印紫色的原点,则它将是紫色的高度和宽度的一半的负数作为相对于 super 视图的原点。最主要的是通过自动布局或分配点为其指定原点。我想我们很幸运能够建立一个起源。这是一个在屏幕快照中添加视图的示例。
import UIKit
class MeasureViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//view will start at 0,0 of superview which is the main view and be the same size
let green = UIView(frame: CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height))
green.backgroundColor = .green
self.view.addSubview(green)
//first inside view half of outers width and height
let blue = UIView(frame: CGRect(x: 0, y: 0, width: green.bounds.midX, height: green.bounds.midY))
blue.backgroundColor = .blue
// in this case it is self.view.center and outer.center but won't always be just works because coordinate space matches
blue.center = green.center
green.addSubview(blue)
let white = UIView(frame: CGRect(x: 0, y: 0, width: blue.bounds.midX, height: blue.bounds.midY))
//will not be in the center of firstInside because it is using the coordinate derived from outer
white.center = blue.center
white.backgroundColor = .white
blue.addSubview(white)
let redDot = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 10))
redDot.layer.cornerRadius = 5
redDot.backgroundColor = .red
//will be the center of blue center because it is half the width and height and be correct
redDot.center = CGPoint(x: blue.bounds.midX, y: blue.bounds.midY)
blue.addSubview(redDot)
//same size as white view above but no origin. this is bad
let noOriginView = UIView()
noOriginView.backgroundColor = .cyan
noOriginView.bounds.size = CGSize(width: blue.bounds.midX, height: blue.bounds.midY)
blue.addSubview(noOriginView)
print("Test withoutFrame \(noOriginView.frame.origin)")
}
}
说明和屏幕截图
这些基本原理适用于手动布局,自动布局和Snapkit。使用自动布局和Snapkit时,您不会直接设置点和边界,但是需要约束来做同样的事情。
使用自动版式:
经过对Autolayout的大量测试之后,我确实认为如果视图缺少位置约束,则将其转换为窗口的0,0,这意味着实际原点将为x,y的负值,并且上面的示例将调整为将原点转换为窗口协调空间。
关于ios - 在使用SnapKit的iOS上,为什么 subview 的原点不是其父 View 的原点?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/45395566/