使用UIStackView将标签放在UISlider上方

时间:2018-03-15 21:18:31

标签: ios autolayout storyboard uilabel uistackview

我们正在尝试为以下场景找到仅限故事板的解决方案:

我们希望设置"里程碑" /"步骤" UISlider上方的标签。值为0.2的拇指位置应恰好位于其上方对应标签的中间。标签位置将适应的重要性取决于屏幕,因此约束需要与比例成正比。插图:

enter image description here

我们尝试了什么:

我们将UIStackView放置在滑块上方的7个排列的子视图(每个步骤一个),并使其稍微宽一些(滑块宽度的1.14倍,其目的是大1/7)。出于某种原因,它对齐某些步骤而不与其他步骤对齐。样品:

enter image description here

enter image description here

任何有关解决问题的建议或建议都将受到高度赞赏。谢谢!

最诚挚的问候,Roi

1 个答案:

答案 0 :(得分:1)

Complete Playground source available here

enter image description here

如果您继承UISlider,则可以覆盖thumbRect(forBounds:trackRect:value:)方法,该方法允许您调整显示拇指图像的矩形。这样做,并使其成为拇指 - 图像的中心位于轨道上的相应点上。

override func thumbRect(forBounds bounds: CGRect, trackRect rect: CGRect, value: Float) -> CGRect {
    let superThumbRect = super.thumbRect(forBounds: bounds, trackRect: rect, value: value)
    let valueAsDecimalFraction = value == minimumValue ? 0 : (value - minimumValue)/(maximumValue - minimumValue)
    let valueAsDecimalFractionOfMinusOneToOne = (valueAsDecimalFraction*2 - 1)/2
    let xOffset = CGFloat(valueAsDecimalFractionOfMinusOneToOne) * superThumbRect.width
    return CGRect(
        x: superThumbRect.origin.x + xOffset,
        y: superThumbRect.origin.y,
        width: superThumbRect.size.width,
        height: superThumbRect.size.height)
}

一旦覆盖thumbRect(forBounds:trackRect:value:),您将看到拇指图像现在具有正确的行为,除非它现在在滑块处于最小值或最大值时挂在视图外。要更正此问题,请覆盖trackRect(forBounds:)方法,以便使用允许拇指图像保留在滑块边界内的某个值填充轨道。

let padding = CGFloat(18)

override func trackRect(forBounds bounds: CGRect) -> CGRect {
    let superTrackRect = super.trackRect(forBounds: bounds)
    return CGRect(
        x: superTrackRect.origin.x + padding,
        y: superTrackRect.origin.y,
        width: superTrackRect.size.width - padding*2,
        height: superTrackRect.size.height)
}

您可能很难使用UILabel定位UIStackView - 标签的中心点将不在正确的位置。相反,使用相对于滑块的约束来布局标签。

// Assuming labels: [UILabel], and a value of thumbIndent

override func viewWillLayoutSubviews() {
    let labelConstraints = labels.enumerated().map { (i, label) -> [NSLayoutConstraint] in
        let pct = CGFloat(i)/CGFloat(labels.count-1)
        let centerX = (view.bounds.size.width-2*thumbIndent) * pct + thumbIndent
        return [
            label.centerXAnchor.constraint(equalTo: slider.leftAnchor, constant: centerX),
            label.bottomAnchor.constraint(equalTo: slider.topAnchor, constant: 0),
        ]
        }.flatMap { $0 }
        .
        .
        .
}