Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 在不使用依赖于帧的intrinsicContentSize的情况下,视图如何基于其宽度的函数确定其高度?_Ios_Swift_Uikit - Fatal编程技术网

Ios 在不使用依赖于帧的intrinsicContentSize的情况下,视图如何基于其宽度的函数确定其高度?

Ios 在不使用依赖于帧的intrinsicContentSize的情况下,视图如何基于其宽度的函数确定其高度?,ios,swift,uikit,Ios,Swift,Uikit,我试图找出如何最好地创建一个视图,该视图根据给定的宽度确定其自身的高度。我想要的行为与垂直视图的行为非常相似,即: 当受其顶部、前缘和后缘约束时,应根据其内容确定其自身的自然高度 当约束在所有边上时,它应通过根据这些约束确定的展开和折叠来填充所有可用空间 此外,我希望在视图内部不使用自动布局的情况下实现这一点 为了说明这一点,请考虑下面的例子: 类ViewController:UIViewController{ 设v=View() 重写func viewDidLoad(){ super.vi

我试图找出如何最好地创建一个视图,该视图根据给定的宽度确定其自身的高度。我想要的行为与垂直视图的行为非常相似,即:

  • 当受其顶部前缘后缘约束时,应根据其内容确定其自身的自然高度
  • 当约束在所有边上时,它应通过根据这些约束确定的展开和折叠来填充所有可用空间
  • 此外,我希望在视图内部不使用自动布局的情况下实现这一点
为了说明这一点,请考虑下面的例子:

类ViewController:UIViewController{
设v=View()
重写func viewDidLoad(){
super.viewDidLoad()
v、 translatesAutoresizingMaskIntoConstraints=false
视图。添加子视图(v)
NSLayoutConstraint.activate([
v、 topAnchor.constraint(等同于:视图.安全区域布局指南.topAnchor),
v、 leadingAnchor.constraint(等式:view.leadingAnchor),
v、 trailingAnchor.constraint(equalTo:view.trailingAnchor),
//打开和关闭此约束。
//v.bottomAnchor.constraint(相等于:视图.安全区域布局指南.bottomAnchor),
])
}
}
类视图:UIView{
//想象一下,这来自于计算一些子视图的大小
//它与边界的宽度有关。
var contentHeight:CGFloat{bounds.width*0.5}
var boundsWidth:CGFloat=0{
didSet{if oldValue!=boundsWidth{invalidateIntrinsicContentSize()}
}
重写变量intrinsicContentSize:CGSize{
.init(宽度:bounds.width,高度:contentHeight)
}
覆盖func布局子视图(){
super.layoutSubviews()
boundsWidth=bounds.width
背景颜色=.red
}
}
这个例子实现了我上面描述的行为,但是我对它有很大的保留,因为我使用的是
intrinsicContentSize

声明它必须独立于我尚未管理的内容框架。我正在根据帧的宽度计算内部大小


如何才能实现此行为并且不使
instrinsicContentSize
依赖于边界

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

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

例如,
UILabel
具有基于其文本的固有大小。可以将“顶部”标签约束到视图的顶部,“中间”标签约束到“顶部”标签的底部,“底部”标签约束到“中间”标签的底部约束到视图的底部

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

结果是:

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


编辑

关于固有内容大小的一点澄清

在此图像中,所有5个子视图的
intrinsicContentSize
值均为
120 x 80

class IntrinsicTestView: UIView {
    override var intrinsicContentSize: CGSize {
        return CGSize(width: 120, height: 80)
    }
}

如你所见:

  • 如果我不添加约束来指定宽度,则视图的宽度将为120磅
  • 如果我不添加约束来指定高度,则视图的高度将为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

    }

}

正如DonMag在他的回答中所说,
intrinsicContentSize
并不完全用于复杂的布局管理,而是在没有足够的框架约束时作为视图首选大小的指示

不过,我可以提供一个简单的例子,希望能为您指明正确的方向。
让我们假设我想要一个
比率视图
具有固有的大小,以便其高度是其宽度的线性函数:

let ratioView = RatioView()
ratioView.ratio = 0.5
在本例中,
ratioView
的固有高度等于其宽度的一半

比率视图的代码如下所示:

class RatioView: UIView {
  var contentHeight: CGFloat { bounds.width * ratio }
  private var kvoObservation: NSKeyValueObservation?

  var ratio: CGFloat = 1 {
    didSet { invalidateIntrinsicContentSize() }
  }

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

  override func didMoveToSuperview() {
    guard let _ = superview else { return }
    kvoObservation = observe(\.frame, options: .initial) { [weak self] (_, change) in
      self?.invalidateIntrinsicContentSize()
    }
  }

  override func willMove(toSuperview newSuperview: UIView?) {
    if newSuperview == nil {
      kvoObservation = nil
    }
  }
}
上述代码中有两个重要亮点:

  • 视图调用以通知布局系统其
    intrinsicContentSize
    属性的值已更改
  • 视图通过对其
    frame
    属性的任何更改不断进行监视,以便在每次宽度更改时计算新高度

第二步特别值得注意:如果没有它,视图将不知道其大小何时发生变化,因此没有任何机会通知布局系统(通过
invalidateIntrinsicContentSize
)其
intrinsicContentSize
已刷新。

您提供了更多详细信息,但你到底想做什么还不清楚。“创建一个根据给定宽度确定自身高度的视图”-是否希望高度为宽度的百分比?您是否计划将子视图添加到此视图,并且希望子视图的高度确定视图的高度?谢谢您的答复!我跳过了这些要点,可能是错误的,因为我认为它们有损于我的实际问题!我正在处理的特定视图将是许多较小子视图的容器,我将在内部定位这些子视图。为了简化事情,你可以画一个垂直视图。我在示例代码中使用了宽度的一个百分比,希望人们能够理解
class RatioView: UIView {
  var contentHeight: CGFloat { bounds.width * ratio }
  private var kvoObservation: NSKeyValueObservation?

  var ratio: CGFloat = 1 {
    didSet { invalidateIntrinsicContentSize() }
  }

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

  override func didMoveToSuperview() {
    guard let _ = superview else { return }
    kvoObservation = observe(\.frame, options: .initial) { [weak self] (_, change) in
      self?.invalidateIntrinsicContentSize()
    }
  }

  override func willMove(toSuperview newSuperview: UIView?) {
    if newSuperview == nil {
      kvoObservation = nil
    }
  }
}