iOS自定义View 控件自动计算size能力
背景
在使用 UILabel 和 UIImage 的时候,不用指定宽高约束,控件也不会报约束缺失,还可以根据内容自己确定适合的宽高,特别适合 Xib 和 Storyboard 布局。
我们在自定义控件的时候,怎么才能让控件具备这种自动计算宽高的功能了?
基本知识点
只需要自定义控件满足以下条件之一即可:
- 自定义控件实现
intrinsicContentSize
的重写并返回合适大小,适合子控件存在 frame
初始化,或者动态添加。
- 自定义控件内部约束满足
这时候有部分长得帅的小伙伴要问了,如果自定义控件即满足了所有约束,又重写了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相关文档
疑问
- UILabel 的内部怎么计算出内在大小的?
即在intrinsicContentSize属性返回值是怎么计算的。按照打印日志来看,是经过多次(超过四次)updateLayout, intrinsicContenSize调用得出的。
- 自定义视图实现了 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能力相关推荐
- 安卓中自定义view控件代替radiogroup实现颜色渐变效果的写法
利用自定义控件代替radiogroup,同时实现在使用viewpager进行翻页的时候,实现颜色渐变的效果. 一: 首先创建一个自定义view类继承自View类,所有的控件均用canvas绘制出来(包 ...
- 自定义View控件(2—手写实例代码)
1. 步骤: + 1.自定义一个类继承于UIView + 2.在initWithFrame方法中添加子控件 + 3.在layoutSubviews中设置子控件的位置 + 4.提供一个属性保存外界传入的 ...
- android 自定义view控件,Android 自定义View——自定义View控件
Android给我们提供了大量的View控件,但这还是远远满足不了我们的要求,有时候开发所需要的控件形式是在Android提供的控件中是不存在,这就需要我们自己去定义一个.那么如何自定义控件? 学习自 ...
- Android自定义View控件
转自:http://blog.csdn.net/lvwenbo0107/article/details/50542597 写的够详细了 为什么要自定义控件 1.特定的显示风格. 2.处理特有的用户交互 ...
- ios swift 纯代码自定义view(控件) XYswitchView
文章目录 1.截图 2.代码 2.1 XYswitchView.swift 2.2 LoginVC.swift 3.参考博客 1.截图 2.代码 2.1 XYswitchView.swift impo ...
- Flutter 自定义UI控件并设置交互能力
1.自定义UI控件 首先UI控件按照是否能够与用户交互分为交互型控件和非交互型控件. 下面就是创建了一个交互型控件,只是关于界面是空的,如果我们继承StatelessWidget就是创建了一个非交互型 ...
- Android View体系(十)自定义组合控件
相关文章 Android View体系(一)视图坐标系 Android View体系(二)实现View滑动的六种方法 Android View体系(三)属性动画 Android View体系(四)从源 ...
- Android 自定义View修炼-打造完美的自定义侧滑菜单/侧滑View控件(转)
一.概述 在App中,经常会出现侧滑菜单,侧滑滑出View等效果,虽然说Android有很多第三方开源库,但是实际上 咱们可以自己也写一个自定义的侧滑View控件,其实不难,主要涉及到以下几个要点: ...
- Android自定义View 自定义组合控件
自定义组合控件: 以三国杀游戏武将为例,包括武将头像,血条,装备区 1.先定义该组合的XML文件布局 1 <?xml version="1.0" encoding=" ...
最新文章
- Linux虚拟内存和进程虚拟地址空间简述
- RPM安装rabbitMQ
- 10gocm-gt;session3-gt;数据备份与恢复
- DictVectorizer中的fit_transform
- 闪屏页新手引导页面主页判断跳转的逻辑
- MySQL Create Table创建表
- Queue - 一种线程安全的FIFO实现
- 捷安四方聚合支付系统功能和优势的简介介绍?
- 宏文件下载_技能 | WPS如何启用宏功能,VBA组件安装
- SVM -支持向量机原理详解与实践之四
- 无法打开计算机分区,电脑硬盘分区打不开怎么办
- 我和腾讯不得不说的故事
- 阿里20亿美金收购考拉,丁磊到底是怎么“失身”的?
- python+qqbot实现qq聊天机器人
- 关于BIOS的入口地址0xFFFF0
- 写任务,列清单-4D工作法
- 将其他图片转换为ico图片
- js数组查找最接近_js查找数组所有符合条件数据 js替换数组中的某个元素
- Fleet 1.9.231发布,支持window10 version 1809及以上版本,MacOs支持,但win7不支持
- scrollView封装广告轮播实例代码(Hank版)
热门文章
- ADODB.Connection 错误 '800a0e7a' 未找到提供程序。该程序可能未正确安装。解决办法...
- python数据库-mysql
- 浅谈Linux的内存管理机制
- (转)C#开发微信门户及应用(4)--关注用户列表及详细信息管理
- 第十二周项目1-阅读程序(三)
- myeclipse8.6安装svn
- s:iterator获取遍历数据的索引下标
- 不丹的启示:用国民幸福总值替代GDP
- 关于用户表设计及多用户登入限制
- python 时间字符串和时间戳之间的转换