iOS自定义View 控件自动计算size能力

背景

在使用 UILabel 和 UIImage 的时候,不用指定宽高约束,控件也不会报约束缺失,还可以根据内容自己确定适合的宽高,特别适合 Xib 和 Storyboard 布局。

我们在自定义控件的时候,怎么才能让控件具备这种自动计算宽高的功能了?

基本知识点

只需要自定义控件满足以下条件之一即可:

  1. 自定义控件实现intrinsicContentSize的重写并返回合适大小,适合子控件存在 frame初始化,或者动态添加。
  2. 自定义控件内部约束满足

这时候有部分长得帅的小伙伴要问了,如果自定义控件即满足了所有约束,又重写了intrinsicContentSize返回了计算大小怎么办。答案只有一个,执行约束,忽略 这时候有部分长得帅的小伙伴要问了,如果自定义控件即满足了所有约束,又重写了intrinsicContentSize返回了计算大小怎么办。答案只有一个,执行约束,忽略 intrinsicContentSize.

intrinsicContentSize

intrinsicContentSize又叫内容大小,决定了控件自动布局下的大小,(当控件没有宽高约束的时候,系统会自动添加宽高约束)自定义控件重写 intrisicContentsize 返回内在大小,自动布局系统就可以自己确定控件大小,就像使用UILabel,根据文本多少弹性控制大小。

自定义控件如果要适配AutoLayout, 达到自动适应的效果,则需要重写此属性。

 override var intrinsicContentSize: CGSize {// 计算内容大小, 如果某个维度不使用内在大小可以设置为 UIView.noIntrinsicMetric//return CGSize(width: bounds.width, height: itemHeight*CGFloat(items.count))//返回计算的size}

UIView.noIntrinsicMetric

内在大小需要返回 CGSize, 就是你希望控件的内在大小。

但是可能存在,我的控件只想指定高度,宽度随外部约束。这时候就需要使用UIView.noIntrinsicMetric使用-1也可以,同样的效果。

比如 UIView 的内在大小默认值等于(UIView.noIntrinsicMetric,UIView.noIntrinsicMetric)也就是(-1,-1),表示宽高由外部控件外部约束决定,或者有创建的自动约束决定。

一旦重写并返回非noIntrinsicMetric, 那么控件自己就会为自己添加对应的约束。

比如我重写

 override var intrinsicContentSize: CGSize {return CGSize(width: UIView.noIntrinsicMetric, height: itemH)}

打印约束自动添加

<NSContentSizeLayoutConstraint:0x600003650960 AnyTest.SequenceView:0x7fc91bf0a1b0.height == 162.5 Hug:250 CompressionResistance:750   (active)>

invalidateIntrinsicContentSize()

该方法的作用是重新计算intrinsicContentSize,相当于原来的内置大小失效,重新生效一个新的。

func invalidateIntrinsicContentSize()

通常需要内在大小改变时候调用,如外部数据变化时。

约束调整周期

一般情况调用顺序

invlidateIntricContentSize() --> intrisicContenSize --> updateConstraints 之后会调用 layoutSubviews()。

如 UILabel 调整周期如下:

#mermaid-svg-buAvG81S94HdRYXM .label{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);fill:#333;color:#333}#mermaid-svg-buAvG81S94HdRYXM .label text{fill:#333}#mermaid-svg-buAvG81S94HdRYXM .node rect,#mermaid-svg-buAvG81S94HdRYXM .node circle,#mermaid-svg-buAvG81S94HdRYXM .node ellipse,#mermaid-svg-buAvG81S94HdRYXM .node polygon,#mermaid-svg-buAvG81S94HdRYXM .node path{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-buAvG81S94HdRYXM .node .label{text-align:center;fill:#333}#mermaid-svg-buAvG81S94HdRYXM .node.clickable{cursor:pointer}#mermaid-svg-buAvG81S94HdRYXM .arrowheadPath{fill:#333}#mermaid-svg-buAvG81S94HdRYXM .edgePath .path{stroke:#333;stroke-width:1.5px}#mermaid-svg-buAvG81S94HdRYXM .flowchart-link{stroke:#333;fill:none}#mermaid-svg-buAvG81S94HdRYXM .edgeLabel{background-color:#e8e8e8;text-align:center}#mermaid-svg-buAvG81S94HdRYXM .edgeLabel rect{opacity:0.9}#mermaid-svg-buAvG81S94HdRYXM .edgeLabel span{color:#333}#mermaid-svg-buAvG81S94HdRYXM .cluster rect{fill:#ffffde;stroke:#aa3;stroke-width:1px}#mermaid-svg-buAvG81S94HdRYXM .cluster text{fill:#333}#mermaid-svg-buAvG81S94HdRYXM div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);font-size:12px;background:#ffffde;border:1px solid #aa3;border-radius:2px;pointer-events:none;z-index:100}#mermaid-svg-buAvG81S94HdRYXM .actor{stroke:#ccf;fill:#ECECFF}#mermaid-svg-buAvG81S94HdRYXM text.actor>tspan{fill:#000;stroke:none}#mermaid-svg-buAvG81S94HdRYXM .actor-line{stroke:grey}#mermaid-svg-buAvG81S94HdRYXM .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333}#mermaid-svg-buAvG81S94HdRYXM .messageLine1{stroke-width:1.5;stroke-dasharray:2, 2;stroke:#333}#mermaid-svg-buAvG81S94HdRYXM #arrowhead path{fill:#333;stroke:#333}#mermaid-svg-buAvG81S94HdRYXM .sequenceNumber{fill:#fff}#mermaid-svg-buAvG81S94HdRYXM #sequencenumber{fill:#333}#mermaid-svg-buAvG81S94HdRYXM #crosshead path{fill:#333;stroke:#333}#mermaid-svg-buAvG81S94HdRYXM .messageText{fill:#333;stroke:#333}#mermaid-svg-buAvG81S94HdRYXM .labelBox{stroke:#ccf;fill:#ECECFF}#mermaid-svg-buAvG81S94HdRYXM .labelText,#mermaid-svg-buAvG81S94HdRYXM .labelText>tspan{fill:#000;stroke:none}#mermaid-svg-buAvG81S94HdRYXM .loopText,#mermaid-svg-buAvG81S94HdRYXM .loopText>tspan{fill:#000;stroke:none}#mermaid-svg-buAvG81S94HdRYXM .loopLine{stroke-width:2px;stroke-dasharray:2, 2;stroke:#ccf;fill:#ccf}#mermaid-svg-buAvG81S94HdRYXM .note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-buAvG81S94HdRYXM .noteText,#mermaid-svg-buAvG81S94HdRYXM .noteText>tspan{fill:#000;stroke:none}#mermaid-svg-buAvG81S94HdRYXM .activation0{fill:#f4f4f4;stroke:#666}#mermaid-svg-buAvG81S94HdRYXM .activation1{fill:#f4f4f4;stroke:#666}#mermaid-svg-buAvG81S94HdRYXM .activation2{fill:#f4f4f4;stroke:#666}#mermaid-svg-buAvG81S94HdRYXM .mermaid-main-font{font-family:"trebuchet ms", verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-buAvG81S94HdRYXM .section{stroke:none;opacity:0.2}#mermaid-svg-buAvG81S94HdRYXM .section0{fill:rgba(102,102,255,0.49)}#mermaid-svg-buAvG81S94HdRYXM .section2{fill:#fff400}#mermaid-svg-buAvG81S94HdRYXM .section1,#mermaid-svg-buAvG81S94HdRYXM .section3{fill:#fff;opacity:0.2}#mermaid-svg-buAvG81S94HdRYXM .sectionTitle0{fill:#333}#mermaid-svg-buAvG81S94HdRYXM .sectionTitle1{fill:#333}#mermaid-svg-buAvG81S94HdRYXM .sectionTitle2{fill:#333}#mermaid-svg-buAvG81S94HdRYXM .sectionTitle3{fill:#333}#mermaid-svg-buAvG81S94HdRYXM .sectionTitle{text-anchor:start;font-size:11px;text-height:14px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-buAvG81S94HdRYXM .grid .tick{stroke:#d3d3d3;opacity:0.8;shape-rendering:crispEdges}#mermaid-svg-buAvG81S94HdRYXM .grid .tick text{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-buAvG81S94HdRYXM .grid path{stroke-width:0}#mermaid-svg-buAvG81S94HdRYXM .today{fill:none;stroke:red;stroke-width:2px}#mermaid-svg-buAvG81S94HdRYXM .task{stroke-width:2}#mermaid-svg-buAvG81S94HdRYXM .taskText{text-anchor:middle;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-buAvG81S94HdRYXM .taskText:not([font-size]){font-size:11px}#mermaid-svg-buAvG81S94HdRYXM .taskTextOutsideRight{fill:#000;text-anchor:start;font-size:11px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-buAvG81S94HdRYXM .taskTextOutsideLeft{fill:#000;text-anchor:end;font-size:11px}#mermaid-svg-buAvG81S94HdRYXM .task.clickable{cursor:pointer}#mermaid-svg-buAvG81S94HdRYXM .taskText.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-buAvG81S94HdRYXM .taskTextOutsideLeft.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-buAvG81S94HdRYXM .taskTextOutsideRight.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-buAvG81S94HdRYXM .taskText0,#mermaid-svg-buAvG81S94HdRYXM .taskText1,#mermaid-svg-buAvG81S94HdRYXM .taskText2,#mermaid-svg-buAvG81S94HdRYXM .taskText3{fill:#fff}#mermaid-svg-buAvG81S94HdRYXM .task0,#mermaid-svg-buAvG81S94HdRYXM .task1,#mermaid-svg-buAvG81S94HdRYXM .task2,#mermaid-svg-buAvG81S94HdRYXM .task3{fill:#8a90dd;stroke:#534fbc}#mermaid-svg-buAvG81S94HdRYXM .taskTextOutside0,#mermaid-svg-buAvG81S94HdRYXM .taskTextOutside2{fill:#000}#mermaid-svg-buAvG81S94HdRYXM .taskTextOutside1,#mermaid-svg-buAvG81S94HdRYXM .taskTextOutside3{fill:#000}#mermaid-svg-buAvG81S94HdRYXM .active0,#mermaid-svg-buAvG81S94HdRYXM .active1,#mermaid-svg-buAvG81S94HdRYXM .active2,#mermaid-svg-buAvG81S94HdRYXM .active3{fill:#bfc7ff;stroke:#534fbc}#mermaid-svg-buAvG81S94HdRYXM .activeText0,#mermaid-svg-buAvG81S94HdRYXM .activeText1,#mermaid-svg-buAvG81S94HdRYXM .activeText2,#mermaid-svg-buAvG81S94HdRYXM .activeText3{fill:#000 !important}#mermaid-svg-buAvG81S94HdRYXM .done0,#mermaid-svg-buAvG81S94HdRYXM .done1,#mermaid-svg-buAvG81S94HdRYXM .done2,#mermaid-svg-buAvG81S94HdRYXM .done3{stroke:grey;fill:#d3d3d3;stroke-width:2}#mermaid-svg-buAvG81S94HdRYXM .doneText0,#mermaid-svg-buAvG81S94HdRYXM .doneText1,#mermaid-svg-buAvG81S94HdRYXM .doneText2,#mermaid-svg-buAvG81S94HdRYXM .doneText3{fill:#000 !important}#mermaid-svg-buAvG81S94HdRYXM .crit0,#mermaid-svg-buAvG81S94HdRYXM .crit1,#mermaid-svg-buAvG81S94HdRYXM .crit2,#mermaid-svg-buAvG81S94HdRYXM .crit3{stroke:#f88;fill:red;stroke-width:2}#mermaid-svg-buAvG81S94HdRYXM .activeCrit0,#mermaid-svg-buAvG81S94HdRYXM .activeCrit1,#mermaid-svg-buAvG81S94HdRYXM .activeCrit2,#mermaid-svg-buAvG81S94HdRYXM .activeCrit3{stroke:#f88;fill:#bfc7ff;stroke-width:2}#mermaid-svg-buAvG81S94HdRYXM .doneCrit0,#mermaid-svg-buAvG81S94HdRYXM .doneCrit1,#mermaid-svg-buAvG81S94HdRYXM .doneCrit2,#mermaid-svg-buAvG81S94HdRYXM .doneCrit3{stroke:#f88;fill:#d3d3d3;stroke-width:2;cursor:pointer;shape-rendering:crispEdges}#mermaid-svg-buAvG81S94HdRYXM .milestone{transform:rotate(45deg) scale(0.8, 0.8)}#mermaid-svg-buAvG81S94HdRYXM .milestoneText{font-style:italic}#mermaid-svg-buAvG81S94HdRYXM .doneCritText0,#mermaid-svg-buAvG81S94HdRYXM .doneCritText1,#mermaid-svg-buAvG81S94HdRYXM .doneCritText2,#mermaid-svg-buAvG81S94HdRYXM .doneCritText3{fill:#000 !important}#mermaid-svg-buAvG81S94HdRYXM .activeCritText0,#mermaid-svg-buAvG81S94HdRYXM .activeCritText1,#mermaid-svg-buAvG81S94HdRYXM .activeCritText2,#mermaid-svg-buAvG81S94HdRYXM .activeCritText3{fill:#000 !important}#mermaid-svg-buAvG81S94HdRYXM .titleText{text-anchor:middle;font-size:18px;fill:#000;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-buAvG81S94HdRYXM g.classGroup text{fill:#9370db;stroke:none;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);font-size:10px}#mermaid-svg-buAvG81S94HdRYXM g.classGroup text .title{font-weight:bolder}#mermaid-svg-buAvG81S94HdRYXM g.clickable{cursor:pointer}#mermaid-svg-buAvG81S94HdRYXM g.classGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-buAvG81S94HdRYXM g.classGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-buAvG81S94HdRYXM .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5}#mermaid-svg-buAvG81S94HdRYXM .classLabel .label{fill:#9370db;font-size:10px}#mermaid-svg-buAvG81S94HdRYXM .relation{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-buAvG81S94HdRYXM .dashed-line{stroke-dasharray:3}#mermaid-svg-buAvG81S94HdRYXM #compositionStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-buAvG81S94HdRYXM #compositionEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-buAvG81S94HdRYXM #aggregationStart{fill:#ECECFF;stroke:#9370db;stroke-width:1}#mermaid-svg-buAvG81S94HdRYXM #aggregationEnd{fill:#ECECFF;stroke:#9370db;stroke-width:1}#mermaid-svg-buAvG81S94HdRYXM #dependencyStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-buAvG81S94HdRYXM #dependencyEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-buAvG81S94HdRYXM #extensionStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-buAvG81S94HdRYXM #extensionEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-buAvG81S94HdRYXM .commit-id,#mermaid-svg-buAvG81S94HdRYXM .commit-msg,#mermaid-svg-buAvG81S94HdRYXM .branch-label{fill:lightgrey;color:lightgrey;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-buAvG81S94HdRYXM .pieTitleText{text-anchor:middle;font-size:25px;fill:#000;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-buAvG81S94HdRYXM .slice{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-buAvG81S94HdRYXM g.stateGroup text{fill:#9370db;stroke:none;font-size:10px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-buAvG81S94HdRYXM g.stateGroup text{fill:#9370db;fill:#333;stroke:none;font-size:10px}#mermaid-svg-buAvG81S94HdRYXM g.statediagram-cluster .cluster-label text{fill:#333}#mermaid-svg-buAvG81S94HdRYXM g.stateGroup .state-title{font-weight:bolder;fill:#000}#mermaid-svg-buAvG81S94HdRYXM g.stateGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-buAvG81S94HdRYXM g.stateGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-buAvG81S94HdRYXM .transition{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-buAvG81S94HdRYXM .stateGroup .composit{fill:white;border-bottom:1px}#mermaid-svg-buAvG81S94HdRYXM .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px}#mermaid-svg-buAvG81S94HdRYXM .state-note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-buAvG81S94HdRYXM .state-note text{fill:black;stroke:none;font-size:10px}#mermaid-svg-buAvG81S94HdRYXM .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.7}#mermaid-svg-buAvG81S94HdRYXM .edgeLabel text{fill:#333}#mermaid-svg-buAvG81S94HdRYXM .stateLabel text{fill:#000;font-size:10px;font-weight:bold;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-buAvG81S94HdRYXM .node circle.state-start{fill:black;stroke:black}#mermaid-svg-buAvG81S94HdRYXM .node circle.state-end{fill:black;stroke:white;stroke-width:1.5}#mermaid-svg-buAvG81S94HdRYXM #statediagram-barbEnd{fill:#9370db}#mermaid-svg-buAvG81S94HdRYXM .statediagram-cluster rect{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-buAvG81S94HdRYXM .statediagram-cluster rect.outer{rx:5px;ry:5px}#mermaid-svg-buAvG81S94HdRYXM .statediagram-state .divider{stroke:#9370db}#mermaid-svg-buAvG81S94HdRYXM .statediagram-state .title-state{rx:5px;ry:5px}#mermaid-svg-buAvG81S94HdRYXM .statediagram-cluster.statediagram-cluster .inner{fill:white}#mermaid-svg-buAvG81S94HdRYXM .statediagram-cluster.statediagram-cluster-alt .inner{fill:#e0e0e0}#mermaid-svg-buAvG81S94HdRYXM .statediagram-cluster .inner{rx:0;ry:0}#mermaid-svg-buAvG81S94HdRYXM .statediagram-state rect.basic{rx:5px;ry:5px}#mermaid-svg-buAvG81S94HdRYXM .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#efefef}#mermaid-svg-buAvG81S94HdRYXM .note-edge{stroke-dasharray:5}#mermaid-svg-buAvG81S94HdRYXM .statediagram-note rect{fill:#fff5ad;stroke:#aa3;stroke-width:1px;rx:0;ry:0}:root{--mermaid-font-family: '"trebuchet ms", verdana, arial';--mermaid-font-family: "Comic Sans MS", "Comic Sans", cursive}#mermaid-svg-buAvG81S94HdRYXM .error-icon{fill:#522}#mermaid-svg-buAvG81S94HdRYXM .error-text{fill:#522;stroke:#522}#mermaid-svg-buAvG81S94HdRYXM .edge-thickness-normal{stroke-width:2px}#mermaid-svg-buAvG81S94HdRYXM .edge-thickness-thick{stroke-width:3.5px}#mermaid-svg-buAvG81S94HdRYXM .edge-pattern-solid{stroke-dasharray:0}#mermaid-svg-buAvG81S94HdRYXM .edge-pattern-dashed{stroke-dasharray:3}#mermaid-svg-buAvG81S94HdRYXM .edge-pattern-dotted{stroke-dasharray:2}#mermaid-svg-buAvG81S94HdRYXM .marker{fill:#333}#mermaid-svg-buAvG81S94HdRYXM .marker.cross{stroke:#333}:root { --mermaid-font-family: "trebuchet ms", verdana, arial;}#mermaid-svg-buAvG81S94HdRYXM {color: rgba(0, 0, 0, 0.75);font: normal normal normal normal 16px/26px -apple-system, "SF UI Text", Arial, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", sans-serif;}

调整contentSize
layoutSubviews 方法
updateConstraints 方法
初始化
intrinsicContentSize
invalidateIntrinsicContentSize 方法
约束结束

虚线表示可能调用, 可能某些步骤存在重复调用。

我们需要在合适的时机去调用invalidateIntrinsicContentSize()方法以返回正确的内在大小。

比如当某个属性改变可能引起控件的内在大小改变时调用该方法,比如UILabel设置文本的时候应该会调用这个方法(猜测)。

但要注意跳出循环(可能会引起循环)。

override func layoutSubviews() {super.layoutSubviews()//if intrinsicContentSize() != bound.size {//计算相应的内置大小invalidateIntrinsicContentSize() // 重置内容大小。//}
}

sizeToFit()

调整子视图大小和位置(不能重写),可以在外部或者内部调用,如果使内部调用,可以使得控件本身基于外部约束获取大小值(

func sizeToFit()

计算和返回视图合适的尺寸

/// size参数: 给定大小
func sizeThatFits(_ size: CGSize) -> CGSize

自定义View内部宽度,可以在layousubViews中调用super.layoutSubviews后获得准确宽度。

 override func layoutSubviews() {super.layoutSubviews()print(frame)  // 这里获取的宽度是准备的。
}

sizeTofit简单使用与理解(laughing–简书)

实例代码

   @objc private func tap(){//此处引起内在大小改变为点击事件。self.invalidateIntrinsicContentSize()  //先使内置大小无效,自动调用重写内置大小。// 改变的数据extentSize = CGSize(width: 0, height: 20)}// 重写改变内置大小override var intrinsicContentSize: CGSize{// 返回新大小return CGSize(width: bounds.width, height: bounds.height+extentSize.height)}

使用实例:只有20%的iOS程序员能看懂(自定义控件的随内容变换而自适应大小)

返回最佳的大小,基于当前的约束

// targetSize: layoutFittingCompressedSize(尽可能小) layoutFittingExpandedSize(尽可能大)
func systemLayoutSizeFitting(_ targetSize: CGSize) -> CGSize
/// targetSize: 目标大小 如果需要尽可能小 使用layoutFittingCompressedSize, layoutFittingCompressedSize(尽可能大)
/// horizontalFittingPriority: 水平约束的优先级。指定fittingSizeLevel以获得尽可能接近targetSize宽度值的宽度
/// verticalFittingPriority: 垂直约束的优先级。指定fittingSizeLevel以获得尽可能接近targetSize高度值的高度
func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize

参考:

github某issues 关于AutoLayout的讨论 推荐

Apple Autolayout相关文档

疑问

  1. UILabel 的内部怎么计算出内在大小的?

即在intrinsicContentSize属性返回值是怎么计算的。按照打印日志来看,是经过多次(超过四次)updateLayout, intrinsicContenSize调用得出的。

  1. 自定义视图实现了 intrinsicContentSize,如何适配在UITableViewCell中自适应行高?

经过测试,自定义视图实现intrinsicContentSize,会使用第一次返回的内置大小,如果是通过多次invalidateIntrinsicContentSize来确定内置大小,在UITableViewCell中使用将不会达到想要的效果。

参考

Intrinsic Content Size of Multi-Line Text

iOS 中编码约束

实例

实现如下自定义控件,外部传入黄色 view 数量,等比例计算黄色高度,计算intrinsicContentSize

示例代码

override var intrinsicContentSize: CGSize {return CGSize(width: UIView.noIntrinsicMetric, height: itemH)
}

layoutSubviews

     override func layoutSubviews() {super.layoutSubviews()updateItemsLayout()invalidateIntrinsicContentSize()}

完整代码

import UIKit
@IBDesignable
class SequenceView: UIView {@IBInspectablevar count: Int = 0 {didSet {updateItemsCount()}}private var items: [UIView] = []private var itemH: CGFloat = 0override var intrinsicContentSize: CGSize {return CGSize(width: UIView.noIntrinsicMetric, height: itemH)}override init(frame: CGRect) {super.init(frame: frame)commonInit()}required init?(coder: NSCoder) {super.init(coder: coder)commonInit()heightAnchor.constraint(equalToConstant: 200).isActive = true}override func layoutSubviews() {super.layoutSubviews()updateItemsLayout()invalidateIntrinsicContentSize()}override func prepareForInterfaceBuilder() {count = 3}
}private extension SequenceView {func commonInit() {count = 0backgroundColor = .gray}func updateItemsCount() {items.forEach { $0.removeFromSuperview() }items = []items = (0 ..< count).map { _ in createItem() }}func updateItemsLayout() {guard count > 0 else {return}let space: CGFloat = 10let itemW = (bounds.size.width - (CGFloat(count - 1)*space)) / CGFloat(count)itemH = itemWfor (index, item) in items.enumerated() {// 根据 控件当前自身宽度 计算 item 高度,设置 frame 。item.frame = CGRect(x: CGFloat(index)*(space + itemW), y: 0, width: itemW, height: itemH)}}func createItem() -> UIView {let view = UIView()view.backgroundColor = .yellowaddSubview(view)return view}
}

iOS自定义View 控件自动计算size能力相关推荐

  1. 安卓中自定义view控件代替radiogroup实现颜色渐变效果的写法

    利用自定义控件代替radiogroup,同时实现在使用viewpager进行翻页的时候,实现颜色渐变的效果. 一: 首先创建一个自定义view类继承自View类,所有的控件均用canvas绘制出来(包 ...

  2. 自定义View控件(2—手写实例代码)

    1. 步骤: + 1.自定义一个类继承于UIView + 2.在initWithFrame方法中添加子控件 + 3.在layoutSubviews中设置子控件的位置 + 4.提供一个属性保存外界传入的 ...

  3. android 自定义view控件,Android 自定义View——自定义View控件

    Android给我们提供了大量的View控件,但这还是远远满足不了我们的要求,有时候开发所需要的控件形式是在Android提供的控件中是不存在,这就需要我们自己去定义一个.那么如何自定义控件? 学习自 ...

  4. Android自定义View控件

    转自:http://blog.csdn.net/lvwenbo0107/article/details/50542597 写的够详细了 为什么要自定义控件 1.特定的显示风格. 2.处理特有的用户交互 ...

  5. ios swift 纯代码自定义view(控件) XYswitchView

    文章目录 1.截图 2.代码 2.1 XYswitchView.swift 2.2 LoginVC.swift 3.参考博客 1.截图 2.代码 2.1 XYswitchView.swift impo ...

  6. Flutter 自定义UI控件并设置交互能力

    1.自定义UI控件 首先UI控件按照是否能够与用户交互分为交互型控件和非交互型控件. 下面就是创建了一个交互型控件,只是关于界面是空的,如果我们继承StatelessWidget就是创建了一个非交互型 ...

  7. Android View体系(十)自定义组合控件

    相关文章 Android View体系(一)视图坐标系 Android View体系(二)实现View滑动的六种方法 Android View体系(三)属性动画 Android View体系(四)从源 ...

  8. Android 自定义View修炼-打造完美的自定义侧滑菜单/侧滑View控件(转)

    一.概述 在App中,经常会出现侧滑菜单,侧滑滑出View等效果,虽然说Android有很多第三方开源库,但是实际上 咱们可以自己也写一个自定义的侧滑View控件,其实不难,主要涉及到以下几个要点: ...

  9. Android自定义View 自定义组合控件

    自定义组合控件: 以三国杀游戏武将为例,包括武将头像,血条,装备区 1.先定义该组合的XML文件布局 1 <?xml version="1.0" encoding=" ...

最新文章

  1. Linux虚拟内存和进程虚拟地址空间简述
  2. RPM安装rabbitMQ
  3. 10gocm-gt;session3-gt;数据备份与恢复
  4. DictVectorizer中的fit_transform
  5. 闪屏页新手引导页面主页判断跳转的逻辑
  6. MySQL Create Table创建表
  7. Queue - 一种线程安全的FIFO实现
  8. 捷安四方聚合支付系统功能和优势的简介介绍?
  9. 宏文件下载_技能 | WPS如何启用宏功能,VBA组件安装
  10. SVM -支持向量机原理详解与实践之四
  11. 无法打开计算机分区,电脑硬盘分区打不开怎么办
  12. 我和腾讯不得不说的故事
  13. 阿里20亿美金收购考拉,丁磊到底是怎么“失身”的?
  14. python+qqbot实现qq聊天机器人
  15. 关于BIOS的入口地址0xFFFF0
  16. 写任务,列清单-4D工作法
  17. 将其他图片转换为ico图片
  18. js数组查找最接近_js查找数组所有符合条件数据 js替换数组中的某个元素
  19. Fleet 1.9.231发布,支持window10 version 1809及以上版本,MacOs支持,但win7不支持
  20. scrollView封装广告轮播实例代码(Hank版)

热门文章

  1. ADODB.Connection 错误 '800a0e7a' 未找到提供程序。该程序可能未正确安装。解决办法...
  2. python数据库-mysql
  3. 浅谈Linux的内存管理机制
  4. (转)C#开发微信门户及应用(4)--关注用户列表及详细信息管理
  5. 第十二周项目1-阅读程序(三)
  6. myeclipse8.6安装svn
  7. s:iterator获取遍历数据的索引下标
  8. 不丹的启示:用国民幸福总值替代GDP
  9. 关于用户表设计及多用户登入限制
  10. python 时间字符串和时间戳之间的转换