将可视格式的约束转换为 NSLayoutAnchor API
Translating constraints in a visual format to NSLayoutAnchor APIs
我有以下从 this SO question a few months ago 获得的扩展,我想将其转换为 NSLayoutAnchor(或更详细的布局 APIs),原因很简单视觉格式不支持指定安全区域布局指南。
link中的分机是这个:
extension UIView {
/// Adds constraints to this `UIView` instances `superview` object to make sure this always has the same size as the superview.
/// Please note that this has no effect if its `superview` is `nil` – add this `UIView` instance as a subview before calling this.
func bindFrameToSuperviewBounds() {
guard let superview = self.superview else {
print("Error! `superview` was nil – call `addSubview(view: UIView)` before calling `bindFrameToSuperviewBounds()` to fix this.")
return
}
self.translatesAutoresizingMaskIntoConstraints = false
superview.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[subview]-0-|", options: .directionLeadingToTrailing, metrics: nil, views: ["subview": self]))
superview.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-0-[subview]-0-|", options: .directionLeadingToTrailing, metrics: nil, views: ["subview": self]))
}
}
我的视图层次结构是:
UINavigationController -> 根视图控制器:UIPageViewController -> 第一页:UIViewController -> UIScrollView -> UIImageView
当我调用bindFrameToSuperviewBounds()
时,结果如下:
大部分看起来还不错。问题是图像视图位于导航栏下方,这是我不想要的。所以为了解决这个问题,我尝试将 bindFrameToSuperviewBounds()
重写为:
guard let superview = self.superview else {
fatalError("Attempting to bound to a non-existing superview.")
}
translatesAutoresizingMaskIntoConstraints = false
self.topAnchor.constraint(equalTo: superview.safeAreaLayoutGuide.topAnchor).isActive = true
self.leadingAnchor.constraint(equalTo: superview.safeAreaLayoutGuide.leadingAnchor).isActive = true
self.bottomAnchor.constraint(equalTo: superview.safeAreaLayoutGuide.bottomAnchor).isActive = true
self.trailingAnchor.constraint(equalTo: superview.safeAreaLayoutGuide.trailingAnchor).isActive = true
结果是这样的:
这次它正确地没有进入导航栏下方,但是......你可以看到它被拉长了,这是我不想要的。
将视觉布局 API 转换为可以考虑安全区域布局指南的正确方法是什么?
为了完成,设置滚动视图和图像视图的代码如下:
override func viewDidLoad() {
super.viewDidLoad()
imageScrollView.addSubview(imageView)
imageScrollView.layoutIfNeeded()
imageView.bindFrameToSuperviewBounds()
view.addSubview(imageScrollView)
imageView.layoutIfNeeded()
imageScrollView.backgroundColor = .white
imageScrollView.bindFrameToSuperviewBounds()
imageScrollView.delegate = self
}
老实说,我不会为那些奇怪的 "visual" 布局而烦恼,它们很快就会消失。
这有帮助吗?
extension UIView {
// put this view "inside" it's superview, simply stretched all four ways
// amazingly useful
func bindEdgesToSuperview() {
guard let s = superview else {
preconditionFailure("`superview` nil in bindEdgesToSuperview")
}
translatesAutoresizingMaskIntoConstraints = false
leadingAnchor.constraint(equalTo: s.leadingAnchor).isActive = true
trailingAnchor.constraint(equalTo: s.trailingAnchor).isActive = true
topAnchor.constraint(equalTo: s.topAnchor).isActive = true
bottomAnchor.constraint(equalTo: s.bottomAnchor).isActive = true
}
}
就这样使用..
textOnTop = .. UILabel or whatever
userPhoto.addSubview(textOnTop)
textOnTop.bindEdgesToSuperview()
简单!
(PS - 不要忘记,如果它是图像:您几乎肯定想要在所有情况下始终将其设置为 AspectFit。)
安全布局指南的手柄就像...
.safeAreaLayoutGuide
通过 Fattie 提供的代码,我得到了这个解决方案:
guard let superview = self.superview else {
fatalError("Attempting to bound to a non-existing superview.")
}
translatesAutoresizingMaskIntoConstraints = false
self.topAnchor.constraint(equalTo: superview.safeAreaLayoutGuide.topAnchor).isActive = true
self.leadingAnchor.constraint(equalTo: superview.leadingAnchor).isActive = true
self.bottomAnchor.constraint(equalTo: superview.bottomAnchor).isActive = true
self.trailingAnchor.constraint(equalTo: superview.trailingAnchor).isActive = true
(现在我只是将顶部锚定到安全布局是指南。这是否会给 iPhone X 带来问题还有待观察)。
这给出了我期望的结果:
我有以下从 this SO question a few months ago 获得的扩展,我想将其转换为 NSLayoutAnchor(或更详细的布局 APIs),原因很简单视觉格式不支持指定安全区域布局指南。
link中的分机是这个:
extension UIView {
/// Adds constraints to this `UIView` instances `superview` object to make sure this always has the same size as the superview.
/// Please note that this has no effect if its `superview` is `nil` – add this `UIView` instance as a subview before calling this.
func bindFrameToSuperviewBounds() {
guard let superview = self.superview else {
print("Error! `superview` was nil – call `addSubview(view: UIView)` before calling `bindFrameToSuperviewBounds()` to fix this.")
return
}
self.translatesAutoresizingMaskIntoConstraints = false
superview.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[subview]-0-|", options: .directionLeadingToTrailing, metrics: nil, views: ["subview": self]))
superview.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-0-[subview]-0-|", options: .directionLeadingToTrailing, metrics: nil, views: ["subview": self]))
}
}
我的视图层次结构是:
UINavigationController -> 根视图控制器:UIPageViewController -> 第一页:UIViewController -> UIScrollView -> UIImageView
当我调用bindFrameToSuperviewBounds()
时,结果如下:
大部分看起来还不错。问题是图像视图位于导航栏下方,这是我不想要的。所以为了解决这个问题,我尝试将 bindFrameToSuperviewBounds()
重写为:
guard let superview = self.superview else {
fatalError("Attempting to bound to a non-existing superview.")
}
translatesAutoresizingMaskIntoConstraints = false
self.topAnchor.constraint(equalTo: superview.safeAreaLayoutGuide.topAnchor).isActive = true
self.leadingAnchor.constraint(equalTo: superview.safeAreaLayoutGuide.leadingAnchor).isActive = true
self.bottomAnchor.constraint(equalTo: superview.safeAreaLayoutGuide.bottomAnchor).isActive = true
self.trailingAnchor.constraint(equalTo: superview.safeAreaLayoutGuide.trailingAnchor).isActive = true
结果是这样的:
这次它正确地没有进入导航栏下方,但是......你可以看到它被拉长了,这是我不想要的。
将视觉布局 API 转换为可以考虑安全区域布局指南的正确方法是什么?
为了完成,设置滚动视图和图像视图的代码如下:
override func viewDidLoad() {
super.viewDidLoad()
imageScrollView.addSubview(imageView)
imageScrollView.layoutIfNeeded()
imageView.bindFrameToSuperviewBounds()
view.addSubview(imageScrollView)
imageView.layoutIfNeeded()
imageScrollView.backgroundColor = .white
imageScrollView.bindFrameToSuperviewBounds()
imageScrollView.delegate = self
}
老实说,我不会为那些奇怪的 "visual" 布局而烦恼,它们很快就会消失。
这有帮助吗?
extension UIView {
// put this view "inside" it's superview, simply stretched all four ways
// amazingly useful
func bindEdgesToSuperview() {
guard let s = superview else {
preconditionFailure("`superview` nil in bindEdgesToSuperview")
}
translatesAutoresizingMaskIntoConstraints = false
leadingAnchor.constraint(equalTo: s.leadingAnchor).isActive = true
trailingAnchor.constraint(equalTo: s.trailingAnchor).isActive = true
topAnchor.constraint(equalTo: s.topAnchor).isActive = true
bottomAnchor.constraint(equalTo: s.bottomAnchor).isActive = true
}
}
就这样使用..
textOnTop = .. UILabel or whatever
userPhoto.addSubview(textOnTop)
textOnTop.bindEdgesToSuperview()
简单!
(PS - 不要忘记,如果它是图像:您几乎肯定想要在所有情况下始终将其设置为 AspectFit。)
安全布局指南的手柄就像...
.safeAreaLayoutGuide
通过 Fattie 提供的代码,我得到了这个解决方案:
guard let superview = self.superview else {
fatalError("Attempting to bound to a non-existing superview.")
}
translatesAutoresizingMaskIntoConstraints = false
self.topAnchor.constraint(equalTo: superview.safeAreaLayoutGuide.topAnchor).isActive = true
self.leadingAnchor.constraint(equalTo: superview.leadingAnchor).isActive = true
self.bottomAnchor.constraint(equalTo: superview.bottomAnchor).isActive = true
self.trailingAnchor.constraint(equalTo: superview.trailingAnchor).isActive = true
(现在我只是将顶部锚定到安全布局是指南。这是否会给 iPhone X 带来问题还有待观察)。
这给出了我期望的结果: