IB — 根据条件初始化特定的自定义 UIView
IB — Initialize specific custom UIView depending on conditions
我有以下 类:
/**
* This is basically an empty class and exists for the purpose of being able to
* define IBOutlets as BaseHeading, regardless of which specific heading is used in IB.
*/
class BaseHeading: UIView { }
/**
* This class has a .xib where the layout is defined.
* This view should be used as navigationBar for modally-presented ViewControllers.
*/
class HeadingIconRight: BaseHeading { } // This class has a .xib.
/**
* This class has a .xib where the layout is defined.
* This view should be used as navigationBar for pused ViewControllers.
*/
class HeadingIconLeft: BaseHeading { } // This class has a .xib.
在 MyViewController
的 .xib 中,我有一个类型为 BaseHeading
的自定义 UIView
。在它的 Swift-file 中,我有一个 @IBOutlet private weak var heading: BaseHeading!
,与之相连。
在 Swift 文件中我知道应该使用哪个特定的 header (HeadingIconRight
/ HeadingIconLeft
),我只是不确定如何在代码中实现这一点.
我想要的:
- 初始化特定的 HeadingIconXXX
- 将
IBOutlet
的引用替换为该视图
- 替换视图层次结构中的视图
- 它需要有相同的约束(通常是 0 到 leading/ trailing/ superview.top, 0到它下面的第一个视图)
到目前为止我尝试过的:
let headingIndex = self.view.subviews.firstIndex { [=11=] == self.heading }
let newHeading = HeadingIconRight()
// Loop through 'old' heading's constraints and convert them to the new heading.
self.heading.constraints.forEach { constraint in
let firstItem: AnyObject? = constraint.firstItem as! AnyHashable == self.heading as AnyHashable ? newHeading : constraint.firstItem
let secondItem: AnyObject? = constraint.secondItem as! AnyHashable == self.heading as AnyHashable ? newHeading : constraint.secondItem
newHeading.addConstraint(
NSLayoutConstraint(item: firstItem,
attribute: constraint.firstAttribute,
relatedBy: constraint.relation,
toItem: secondItem,
attribute: constraint.secondAttribute,
multiplier: constraint.multiplier,
constant: constraint.constant)
)
}
self.heading.removeFromSuperview()
self.view.insertSubview(newHeading, at: headingIndex!)
self.heading = newHeading
当然,我会尝试更多,但我不想构建非常复杂的东西,而是希望在正确的方向上得到一些指导,以找到一个好的解决方案。
如果能以某种方式覆盖初始化 Xib 视图的生命周期函数,并用特定的 header 替换这个函数,那将是一个很好的解决方案(如果它不违反UIViewController API).
我选择了 @Paulw11's 并在运行时用代码创建了视图。
我没有在 IB 中添加 BaseHeading
-视图,而是将下一个最顶层视图限制在 ViewController
的顶部并引用此约束(例如 topMostConstraint
).
我在 BaseHeading
中添加了以下函数:
public func constrainToTop(in container: UIView, above otherView: UIView, bottomMargin: CGFloat = 0, disableConstraint: NSLayoutConstraint? = nil)
{
container.addSubview(self)
self.translatesAutoresizingMaskIntoConstraints = false
self.topAnchor.constraint(equalTo: container.topAnchor).isActive = true
self.leadingAnchor.constraint(equalTo: container.leadingAnchor).isActive = true
self.trailingAnchor.constraint(equalTo: container.trailingAnchor).isActive = true
self.bottomAnchor.constraint(equalTo: otherView.topAnchor, constant: -bottomMargin).isActive = true
disableConstraint?.isActive = false
}
这是做什么的:
- 添加
self
到containerView
- 创建必要的约束条件
- 如果需要,将 bottomMargin 添加到下一个(下方)视图
- 禁用将另一个视图限制在屏幕顶部的旧约束
在我的 ViewController
的 viewDidLoad()
中,我现在可以执行以下操作:
public class MyViewController: UIViewController
{
private var heading: BaseHeading?
@IBOutlet private weak var topMostConstraint: NSLayoutConstraint!
@IBOutlet private weak var anyOtherView: UIStackView!
override func viewDidLoad()
{
super.viewDidLoad()
self.heading = HeadingIconRight() // Or any other BaseHeading-subclass.
self.heading?.constrainToTop(in: self.view,
above: self.anyOtherView,
bottomMargin: 16,
disableConstraint: self.topMostConstraint)
}
}
这似乎可以完成工作,而且比我预期的要简单。
我有以下 类:
/**
* This is basically an empty class and exists for the purpose of being able to
* define IBOutlets as BaseHeading, regardless of which specific heading is used in IB.
*/
class BaseHeading: UIView { }
/**
* This class has a .xib where the layout is defined.
* This view should be used as navigationBar for modally-presented ViewControllers.
*/
class HeadingIconRight: BaseHeading { } // This class has a .xib.
/**
* This class has a .xib where the layout is defined.
* This view should be used as navigationBar for pused ViewControllers.
*/
class HeadingIconLeft: BaseHeading { } // This class has a .xib.
在 MyViewController
的 .xib 中,我有一个类型为 BaseHeading
的自定义 UIView
。在它的 Swift-file 中,我有一个 @IBOutlet private weak var heading: BaseHeading!
,与之相连。
在 Swift 文件中我知道应该使用哪个特定的 header (HeadingIconRight
/ HeadingIconLeft
),我只是不确定如何在代码中实现这一点.
我想要的:
- 初始化特定的 HeadingIconXXX
- 将
IBOutlet
的引用替换为该视图 - 替换视图层次结构中的视图
- 它需要有相同的约束(通常是 0 到 leading/ trailing/ superview.top, 0到它下面的第一个视图)
到目前为止我尝试过的:
let headingIndex = self.view.subviews.firstIndex { [=11=] == self.heading }
let newHeading = HeadingIconRight()
// Loop through 'old' heading's constraints and convert them to the new heading.
self.heading.constraints.forEach { constraint in
let firstItem: AnyObject? = constraint.firstItem as! AnyHashable == self.heading as AnyHashable ? newHeading : constraint.firstItem
let secondItem: AnyObject? = constraint.secondItem as! AnyHashable == self.heading as AnyHashable ? newHeading : constraint.secondItem
newHeading.addConstraint(
NSLayoutConstraint(item: firstItem,
attribute: constraint.firstAttribute,
relatedBy: constraint.relation,
toItem: secondItem,
attribute: constraint.secondAttribute,
multiplier: constraint.multiplier,
constant: constraint.constant)
)
}
self.heading.removeFromSuperview()
self.view.insertSubview(newHeading, at: headingIndex!)
self.heading = newHeading
当然,我会尝试更多,但我不想构建非常复杂的东西,而是希望在正确的方向上得到一些指导,以找到一个好的解决方案。
如果能以某种方式覆盖初始化 Xib 视图的生命周期函数,并用特定的 header 替换这个函数,那将是一个很好的解决方案(如果它不违反UIViewController API).
我选择了 @Paulw11's
我没有在 IB 中添加 BaseHeading
-视图,而是将下一个最顶层视图限制在 ViewController
的顶部并引用此约束(例如 topMostConstraint
).
我在 BaseHeading
中添加了以下函数:
public func constrainToTop(in container: UIView, above otherView: UIView, bottomMargin: CGFloat = 0, disableConstraint: NSLayoutConstraint? = nil)
{
container.addSubview(self)
self.translatesAutoresizingMaskIntoConstraints = false
self.topAnchor.constraint(equalTo: container.topAnchor).isActive = true
self.leadingAnchor.constraint(equalTo: container.leadingAnchor).isActive = true
self.trailingAnchor.constraint(equalTo: container.trailingAnchor).isActive = true
self.bottomAnchor.constraint(equalTo: otherView.topAnchor, constant: -bottomMargin).isActive = true
disableConstraint?.isActive = false
}
这是做什么的:
- 添加
self
到containerView - 创建必要的约束条件
- 如果需要,将 bottomMargin 添加到下一个(下方)视图
- 禁用将另一个视图限制在屏幕顶部的旧约束
在我的 ViewController
的 viewDidLoad()
中,我现在可以执行以下操作:
public class MyViewController: UIViewController
{
private var heading: BaseHeading?
@IBOutlet private weak var topMostConstraint: NSLayoutConstraint!
@IBOutlet private weak var anyOtherView: UIStackView!
override func viewDidLoad()
{
super.viewDidLoad()
self.heading = HeadingIconRight() // Or any other BaseHeading-subclass.
self.heading?.constrainToTop(in: self.view,
above: self.anyOtherView,
bottomMargin: 16,
disableConstraint: self.topMostConstraint)
}
}
这似乎可以完成工作,而且比我预期的要简单。