【问题标题】:How to make autolayout work with custom UIView on XIB?如何使自动布局与 XIB 中的自定义 UIView 一起使用?
【发布时间】:2018-12-19 21:23:46
【问题描述】:

我在 XIB 上有一个 UIView,其中包含一个 UIImageView 和一个 UILabel,两者之间有一个小空格。水平布局是一个简单的链式|--image--label--|,其中-- 是一些固定空间。高度固定为 40,此视图在其视图控制器中水平居中,并且具有>= 100 宽度约束。

如果我更改标签文本,我的组合视图的宽度会按照预期宽度更新其标签的更改宽度,并且它很好地保持在视图控制器的中心。

因为我需要这个包含图像和标签的UIView,在其他地方,我创建了一个由 XIB 和 Swift 文件组成的自定义类。我们就叫它ItemView吧。

我遇到的问题是视图控制器 XIB 上的空 UIView(我已将其更改为 ItemView)不再接受 >= 40 宽度约束。这当然是因为视图控制器 XIB 不再看到变量宽度 UILabel,而只是一个普通的 UIViewItemView。我收到“不等式约束歧义”IB 错误。

结果是我的自定义视图的宽度仍然是 40。如果我指定更大的 >= 标签宽度,它会起作用一点;文本仅在达到此宽度时才会被切断。但在第二种情况下,我的自定义视图不再水平居中,而是向左移动了一点。

我该如何解决这个问题?或者,我如何告诉 IB 以与 UILabel 类似的方式对待我的自定义 ItemView

在我的ItemView 中,我已尽我所能:

override class var requiresConstraintBasedLayout: Bool
{
    return true
}

设置标签文字后调用setNeedsLayout()

致电myLabel.translatesAutoresizingMaskIntoConstraints = false

致电self.translatesAutoresizingMaskIntoConstraints = false

并在两个init()s 中调用self.setNeedsUpdateConstraints()

【问题讨论】:

  • 为什么不关闭这个视图的警告呢?您可以简单地告诉 IB 不要检查此视图的自动布局有效性。
  • 您是否尝试将自定义 XIB 用作 @IBDesignable,而此时您会收到错误/警告?
  • @DonMag 这是一个 IB 布局错误。我没有指定@IBDesignable

标签: ios uiview autolayout


【解决方案1】:

在视图的大小检查器中配置此弹出窗口:

现在 IB 不会担心您的尺寸规格。你比 IB 更清楚,这就是告诉 IB 这个事实的方法。


另一种方式:在视图的 Size 检查器中配置 this 弹出窗口:

这告诉 IB 视图将具有它不知道的固有内容大小。


其中任何一个都可以。正如您在此屏幕截图中看到的,我为自定义视图设置了大于或等于 40 的宽度约束,但 IB 没有抱怨任何错误:

【讨论】:

  • 这确实消除了错误,但我的自定义 UIView 根本没有更新它的宽度。
  • 不,当然不是。怎么可能?直到运行时它才知道宽度。但是您仍然可以对其应用自动布局关系,如果您正确配置,一切都会在运行时运行良好。不过,那是另外一回事!您问在 IB 中使用占位符视图时如何消除警告,我回答了。
  • 我已经用更多细节更新了这个问题。为发展中的“故事”道歉。然而,我的问题从一开始就是“如何使自动布局工作”。
  • 很明显,您需要自定义视图来实现instrinsicContentSize,使其根据标签自行调整大小。没有?
  • instrinsicContentSize 似乎是关键。但是为什么自动布局在这里不起作用,我需要手动计算?我至少可以要求我的自定义视图根据它的约束来计算它的宽度吗?我显然错过了一些东西。
【解决方案2】:

我如何构建我的自定义 UIView:我的 XIB 的文件所有者是 ItemViewItemView 有一个 @IBOutlet var: UIView! 连接到 XIB 中的视图。然后我有:

init()
{
    super.init(frame: .zero)

    self.initView()
}

required init?(coder aDecoder: NSCoder)
{
    super.init(coder: aDecoder)

    self.initView()
}

private func initView()
{
    Bundle.main.loadNibNamed("ItemView", owner: self, options: nil)
    self.view.frame = CGRect(x: 0.0, y: 0.0, width: self.width, height: self.height)
    self.addSubview(self.view!)
}

(在使用 XIB 创建自定义 UIView 时,我似乎需要这个额外的 UIView。很想知道它是否根本不需要。)

为了让它工作,我需要在更新标签后致电self.invalidateIntrinsicContentSize()。并覆盖intrinsicContentSize

override open var intrinsicContentSize: CGSize
{
    return self.view.systemLayoutSizeFitting(self.bounds.size)
}

请注意,我是在 self.view 上调用这个,而不是在 self 上。

感谢@matt 为我指明了正确的方向。这是我第一次遇到这样的事情。

我尝试过的以下事情我们都没有必要:

override class var requiresConstraintBasedLayout: Bool
{
    return true
}

设置标签文字后调用setNeedsLayout()

致电myLabel.translatesAutoresizingMaskIntoConstraints = false

致电self.translatesAutoresizingMaskIntoConstraints = false

并在两个init()s 中调用self.setNeedsUpdateConstraints()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-02-26
    • 1970-01-01
    • 1970-01-01
    • 2016-10-25
    • 1970-01-01
    • 2017-11-04
    • 2015-04-17
    相关资源
    最近更新 更多