gpt4 book ai didi

ios - View 如何在不使用依赖于框架的 intrinsicContentSize 的情况下根据其宽度的函数确定其高度?

转载 作者:行者123 更新时间:2023-12-01 21:47:28 27 4
gpt4 key购买 nike

我试图弄清楚如何最好地创建一个根据给定宽度确定其自高度度的 View 。我想要的行为与垂直 UIStackView 的行为非常相似:

  • 当受其 约束时顶部 , 领先 , 和 尾随 边缘,它应该根据其内容确定自己的自然高度。
  • 当限制在 上时所有边缘 ,它应该通过由这些约束确定的展开和折叠来填充所有可用空间。
  • 此外,我希望在不使用内部自动布局的情况下实现这一点。

  • 为了说明这一点,请考虑以下示例:

    class ViewController: UIViewController {

    let v = View()

    override func viewDidLoad() {
    super.viewDidLoad()

    v.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(v)

    NSLayoutConstraint.activate([
    v.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
    v.leadingAnchor.constraint(equalTo: view.leadingAnchor),
    v.trailingAnchor.constraint(equalTo: view.trailingAnchor),

    // Toggle this constraint on and off.
    // v.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
    ])
    }
    }

    class View: UIView {

    // Imagine this came from computing the size of some child views
    // and that it is relative to the width of the bounds.
    var contentHeight: CGFloat { bounds.width * 0.5 }

    var boundsWidth: CGFloat = 0 {
    didSet { if oldValue != boundsWidth { invalidateIntrinsicContentSize() } }
    }

    override var intrinsicContentSize: CGSize {
    .init(width: bounds.width, height: contentHeight)
    }

    override func layoutSubviews() {
    super.layoutSubviews()
    boundsWidth = bounds.width
    backgroundColor = .red
    }
    }


    这个例子实现了我上面描述的行为,但由于我使用 intrinsicContentSize 的方式,我对此有很大的保留。 .

    documentation for instrinsicContentSize 声明它 必须独立于内容框架 ,我没有管理。我正在根据框架的宽度计算内在尺寸。

    如何实现这种行为 不做 instrinsicContentSize依靠界限?

    最佳答案

    这一切都可以通过自动布局约束来完成。无需计算任何东西。

    您需要做的就是确保您的自定义 View 的内容具有适当的约束来定义布局。

    例如,UILabel具有基于其文本的固有大小。您可以将“顶部”标签限制在 View 的顶部,将“中间”标签限制在“顶部”标签的底部,将“底部”标签限制在“中间”标签的底部 到 View 的底部。

    这是一个示例(全部通过代码):

    class SizeTestViewController: UIViewController {

    let v = ExampleView()

    override func viewDidLoad() {
    super.viewDidLoad()

    v.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(v)

    NSLayoutConstraint.activate([
    v.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
    v.leadingAnchor.constraint(equalTo: view.leadingAnchor),
    v.trailingAnchor.constraint(equalTo: view.trailingAnchor),

    ])

    v.topLabel.text = "This is the top label."
    v.middleLabel.text = "This is a bunch of text for the middle label. Since we have it set to numberOfLines = 0, the text will wrap onto mutliple lines (assuming it needs to)."
    v.bottomLabel.text = "This is the bottom label text\nwith embedded newline characters\nso we can see the multiline feature without needing word wrap."

    // so we can see the view's frame
    v.backgroundColor = .red
    }
    }

    class ExampleView: UIView {
    var topLabel: UILabel = {
    let v = UILabel()
    v.translatesAutoresizingMaskIntoConstraints = false
    v.backgroundColor = .yellow
    v.numberOfLines = 0
    return v
    }()

    var middleLabel: UILabel = {
    let v = UILabel()
    v.translatesAutoresizingMaskIntoConstraints = false
    v.backgroundColor = .cyan
    v.numberOfLines = 0
    return v
    }()

    var bottomLabel: UILabel = {
    let v = UILabel()
    v.translatesAutoresizingMaskIntoConstraints = false
    v.backgroundColor = .green
    v.numberOfLines = 0
    return v
    }()

    override init(frame: CGRect) {
    super.init(frame: frame)
    commonInit()
    }
    required init?(coder: NSCoder) {
    super.init(coder: coder)
    commonInit()
    }
    func commonInit() -> Void {

    addSubview(topLabel)
    addSubview(middleLabel)
    addSubview(bottomLabel)

    NSLayoutConstraint.activate([

    // constrain topLabel 8-pts from top, leading, trailing
    topLabel.topAnchor.constraint(equalTo: topAnchor, constant: 8.0),
    topLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8.0),
    topLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -8.0),

    // constrain middleLabel 8-pts from topLabel
    // 8-pts from leading, trailing
    middleLabel.topAnchor.constraint(equalTo: topLabel.bottomAnchor, constant: 8.0),
    middleLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8.0),
    middleLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -8.0),

    // constrain bottomLabel 8-pts from middleLabel
    // 8-pts from leading, trailing
    // 8-pts from bottom
    bottomLabel.topAnchor.constraint(equalTo: middleLabel.bottomAnchor, constant: 8.0),
    bottomLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8.0),
    bottomLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -8.0),
    bottomLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -8.0),

    ])

    }

    }

    结果:

    enter image description here

    并旋转,因此您可以看到自动调整大小:

    enter image description here

    编辑

    关于 的一点说明内在内容大小 ...

    在这张图片中,所有 5 个 subview 都有 intrinsicContentSize120 x 80 :
    class IntrinsicTestView: UIView {
    override var intrinsicContentSize: CGSize {
    return CGSize(width: 120, height: 80)
    }
    }

    enter image description here

    如你看到的:
  • 如果我 不要添加约束以指定 宽度 - 使用宽度约束或前导和尾随约束 - View 将为 120 点宽。
  • 如果我 不要添加约束以指定 高度 - 具有高度约束或顶部和底部约束 - View 将是 80 分高。
  • 否则,宽度和高度将由我添加的约束决定。

  • 这是该示例的完整代码:
    class IntrinsicTestView: UIView {
    override var intrinsicContentSize: CGSize {
    return CGSize(width: 120, height: 80)
    }
    }

    class IntrinsicExampleViewController: UIViewController {

    override func viewDidLoad() {
    super.viewDidLoad()

    var iViews: [IntrinsicTestView] = [IntrinsicTestView]()

    var v: IntrinsicTestView

    let colors: [UIColor] = [.red, .green, .blue, .yellow, .purple]

    colors.forEach { c in
    let v = IntrinsicTestView()
    v.backgroundColor = c
    v.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(v)
    iViews.append(v)
    }

    let g = view.safeAreaLayoutGuide

    // first view at Top: 20 / Leading: 20
    v = iViews[0]
    v.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0).isActive = true
    v.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0).isActive = true

    // second view at Top: 120 / Leading: 20
    // height: 20
    v = iViews[1]
    v.topAnchor.constraint(equalTo: g.topAnchor, constant: 120.0).isActive = true
    v.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0).isActive = true
    v.heightAnchor.constraint(equalToConstant: 20).isActive = true

    // third view at Top: 160 / Leading: 20
    // height: 40 / width: 250
    v = iViews[2]
    v.topAnchor.constraint(equalTo: g.topAnchor, constant: 160.0).isActive = true
    v.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0).isActive = true
    v.heightAnchor.constraint(equalToConstant: 40).isActive = true
    v.widthAnchor.constraint(equalToConstant: 250).isActive = true

    // fourth view at Top: 220
    // trailing: 20 / width: 250
    v = iViews[3]
    v.topAnchor.constraint(equalTo: g.topAnchor, constant: 220.0).isActive = true
    v.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0).isActive = true
    v.widthAnchor.constraint(equalToConstant: 250).isActive = true

    // fourth view at Top: 400 / Leading: 20
    // trailing: 20 / bottom: 20
    v = iViews[4]
    v.topAnchor.constraint(equalTo: g.topAnchor, constant: 400.0).isActive = true
    v.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0).isActive = true
    v.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0).isActive = true
    v.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -20.0).isActive = true

    }

    }

    关于ios - View 如何在不使用依赖于框架的 intrinsicContentSize 的情况下根据其宽度的函数确定其高度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62083165/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com