petpwiuta的专栏

简单清晰就是稳定高效

Autolayout_自定义View

Autolayout笔记:自定义View

如果你想在自定义View里用Autolayout进行布局的话,有下面几个点需要注意:

  • 指定Intrinsic Content Size
  • 区分frame和alignment rect
  • 是否支持baseline-aligned布局
  • 对子视图进行精确的布局控制

下面将从这些方面逐步讲解。

指定Intrinsic Content Size

这部分的基本概念在上一篇文章已经讲过,这里不再赘述,主要注意三点:

  1. 重写intrinsicContentSize方法。如果这个视图只有一个方向的尺寸设置了Intrinsic Size,那么为另一个方向的尺寸返回 UIViewNoIntrinsicMetric/NSViewNoIntrinsicMetric
  2. 当view的某些属性的改变会影响到Intrinsic Content Size时,需要调用invalidateIntrinsicContentSize,例如当UILabel的text变化时,就需要重新计算Intrinsic Content Size。
  3. 当实现了intrinsicContentSize方法后,如果想进一步控制当View的实际大小和intrinsicContentSize`冲突时的行为,需要实现Compression Resistance和Content Hugging这方面的方法,具体做法请看这里

区分frame和alignment rect

Autolayout系统的布局操作是基于alignment rect而非frame。绝大部分情况下它们是一样的,但是当你设置了alignmentRectInsets或者重写了alignmentRectForFrame:frameForAlignmentRect:时就需要注意两者的差异。

这里写图片描述

如图所示,Autolayout所有的约束(包括指定宽和高)都施加在alignment rect上,当你指定了alignmentRectInsets后View的frame是根据alignment rect和alignmentRectInsets计算出来的。上图里给view添加了left=80、top=100、width=100和height=100约束,使alignment rect上left为80、top为100、width为100、height为100,然后Autolayout系统根据alignmentRectInsets计算出view的frame,这里frame就是

{
alignmentRect.left-alignmentRectInsets.left,
alignmentRect.top-alignmentRectInsets.top,
alignmentRect.width+alignmentRectInsets.left+alignmentRectInsets.right,
alignmentRect.height+alignmentRectInsets.top+alignmentRectInsets.bottom
}

即{60,80,140,140}

是否支持baseline-aligned布局

如果需要支持baseline布局,就需要实现viewForBaselineLayout(iOS平台) ,系统默认实现只是简单地返回self。如果重写这个方法它返回的View的底边会作为baseline,而且这个View必须是你自定义View的子视图。在OS X中实现baseline布局需要重写baselineOffsetFromBottom返回一个从视图底部边缘开始的offset,默认返回0。

如果自定义View的frame和alignment rect不一样(设置了alignmentRectInsets或者重写了alignmentRectForFrame:frameForAlignmentRect:)需要注意Autolayout布局是施加在alignment rect上的,自定义的view的最终位置是由viewForBaselineLayoutalignmentRectInsets共同决定的。

如何对子视图进行精确的布局控制

给子视图添加Constraints 官方建议的方法是在 updateConstraints里添加子视图的Constraints,而且要保证 [super updateConstraints]一定要在你自己的Constraints添加完之后再调用。而且在这个方法里不能“invalidate any constraints”如果Constraints失效时,需要移除对应的Constraints,并调用setNeedsUpdateConstraints来刷新。

如果是用添加Constraints的方式给子视图布局的话,这个自定义视图就仅仅在Autolayout环境下才能正常工作,因此可以重写requiresConstraintBasedLayout方法返回YES来告知系统必须使用Autolayout布局。

子视图布局 回顾一下之前说起过的Autolayout布局的3个步骤,当Update constraints阶段结束后,就进入Layout view阶段,此时就会调用layoutSubviews方法来根据Constraints计算出来的结果来调整view的boundscenter。因此在layoutSubviews方法里可以对布局进行任意的调整。

最极端的情况是重写layoutSubviews/layout时不调用父类的实现。这就意味着系统虽然根据Constraints计算出视图树的位置,但你并没有应用计算的结果,换言之就是你在这个视图中完全放弃Autolayout布局,完全根据自己的意愿对子视图进行布局。

如果你仍然想使用Autolayout布局子视图,你可以先调用[super layoutSubviews]/[super layout],然后对布局进行微调。这样可以创建一些通过Constraints无法实现的布局,比如,由到视图大小之间的关系或是视图之间间距的关系来定义的布局。

参考

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/petpwiuta/article/details/50040809
个人分类: iOS开发
上一篇AutoLayout_基础概念
下一篇iOS worst practice
想对作者说点什么? 我来说一句

自定义View

2016年06月21日 8.85MB 下载

自定义View+属性

2016年03月02日 1.62MB 下载

android 自定义View

2009年12月13日 3KB 下载

Android中自定义View

2016年03月20日 5.82MB 下载

自定义view

2016年11月30日 15.3MB 下载

自定义view基础与原理源码

2016年03月01日 1.39MB 下载

Android自定义View之进度条Demo

2017年10月23日 138KB 下载

自定义View进阶一

2016年05月28日 1.38MB 下载

android横向滑动选择的View

2015年09月01日 45KB 下载

没有更多推荐了,返回首页

关闭
关闭