如何自动调整从 xib 创建的 MarkerView 的大小

How to automatically resize a MarkerView created from xib

我从 xib 布局创建标记,但它不会根据标签长度调整大小:

我的标记class:

class MyMarker: MarkerView {
    
    @IBOutlet weak var lblValue: UILabel!
    
    override open func awakeFromNib() {
        // centering on top of bar
        self.offset.x = -self.frame.size.width / 2.0
        self.offset.y = -self.frame.size.height - 7.0
    }
    
    override func refreshContent(entry: ChartDataEntry, highlight: Highlight) {
        lblValue.text = String(entry.y)
    }
}

我在 IOS-Charts 库中做了一些挖掘,发现了一个有趣的特性——虽然可以从 xib(其内容是一个视图)创建一个标记,但标记本身并没有添加到查看层次结构。相反,视图的内容只是简单地绘制在图表上 canvas.

如果我们查看 MarkerView,我们会注意到它只是一个方便的包装器。图表上的渲染发生在 draw(context:point:) 方法中,该方法在 IMarker 协议中定义。即MarkerView没有添加到视图层级.

在我看来,这可能是 MarkerView 的约束没有重新计算的原因。我试图强制 MarkerView 重新计算它们但没有成功:

override func refreshContent(entry: ChartDataEntry, highlight: Highlight) {
    lblValue.text = String(entry.y)
    layoutSubviews() // doesn't work
    updateConstraints() // doesn't work
    subviews.forEach() { // even that doesn't work!
        [=11=].updateConstraints()
    }
}

我什至尝试调整视图边界的大小(并为清晰起见添加了绿色背景),但这并没有强制重新计算约束:

override func refreshContent(entry: ChartDataEntry, highlight: Highlight) {
    lblValue.text = String(entry.y)

    bounds = CGRect(x: bounds.minX, y: bounds.minY, width: 200, height: bounds.height)
    frame = bounds
    backgroundColor = UIColor.green

    layoutSubviews() // doesn't work
    updateConstraints() // doesn't work
    subviews.forEach() { // even that doesn't work!
        [=12=].updateConstraints()
    }
}

结果:

问题是如何重新计算MarkerView约束?最重要的是 - 不是手工操作。毕竟,MarkerView 在从 xib 初始化时以某种方式计算出正确的约束。

是的,确实可以重新计算视图常量,即使它不包含在层次结构中。对于 IOS-Charts,它将如下所示:

override func refreshContent(entry: ChartDataEntry, highlight: Highlight) {
    lblValue.text = String(entry.y)
    
    // Recalculate marker sized based on lblValue width
    setNeedsLayout()
    layoutIfNeeded()

    // ...
}