IB — 根据条件初始化特定的自定义 UIView

Posted

技术标签:

【中文标题】IB — 根据条件初始化特定的自定义 UIView【英文标题】:IB — Initialize specific custom UIView depending on conditions 【发布时间】:2020-11-18 10:18:16 【问题描述】:

我有以下课程:

/**
 * 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 文件中,我有一个 @IBOutlet private weak var heading: BaseHeading!,连接到这个。

在 Swift 文件中,我知道应该使用哪个特定的标头 (HeadingIconRight / HeadingIconLeft),我只是不确定如何在代码中实现这一点。

我想要什么:

初始化特定的 HeadingIconXXX 将IBOutlet 的引用替换为该视图 替换视图层次结构中的视图 它需要具有相同的约束(通常是 0leading/ trailing/ superview.top0 到它下面的第一个视图)

到目前为止我已经尝试过:

let headingIndex = self.view.subviews.firstIndex  $0 == 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 视图的生命周期函数,并将其替换为特定的标头,那将是一个不错的解决方案(如果它不违反 UIViewController API)。

【问题讨论】:

全部添加并隐藏,根据需要安装? 如果我知道它们不会被使用,我不想不必要地添加视图,并以这种方式混乱 ViewController.. 为此使用 IBOutlet 毫无意义。您可以拥有一个属性,然后在运行时创建并分配正确的视图。您无法更改笔尖加载过程。 感谢您的意见。我会调查的。 【参考方案1】:

我选择了@Paulw11 的suggestion 并在运行时用代码创建了视图。

我没有在 IB 中添加 BaseHeading-view,而是将下一个最顶层视图约束到 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 禁用旧约束,它将另一个视图约束到屏幕顶部

在我的ViewControllerviewDidLoad() 中,我现在可以执行以下操作:

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)
    

这似乎完成了这项工作,并且最终没有我预期的那么复杂。

【讨论】:

以上是关于IB — 根据条件初始化特定的自定义 UIView的主要内容,如果未能解决你的问题,请参考以下文章

我的自定义 UIView 没有收到触摸

Objective C - 带有动画的自定义 UIView 类初始化

Objective-C - 给定一个 UINib 实例,我如何初始化我的自定义 UIView?

隐藏视图时如何使用自动布局移动其他视图?

自定义uiview中控件的初始化

如何根据objective-c中的滚动方向创建一个从UINavBar后面向下或向上滑动的自定义UIView?