【IOS 知识点】 视图&图像相关

Auto Layout 原理

Auto Layout是一种全新的布局方式,它采用一系列约束(constraints)来实现自动布局,当你的屏幕尺寸发生变化或者屏幕发生旋转时,可以不用添加代码来保持原有布局不变,实现视图的自动布局。

所谓约束,通常是定义了两个视图之间的关系(当然你也可以一个视图自己跟自己设定约束)。如下图就是一个约束的例子,当然要确定一个视图的位置,跟基于frame一样,也是需要确定视图的横纵坐标以及宽度和高度的,只是,这个横纵坐标和宽度高度不再是写死的数值,而是根据约束计算得来,从而达到自动布局的效果

UIView之drawRect: & layoutSubviews的作用和机制

drawRect 调用机制

1、调用时机:loadView ->ViewDidload ->drawRect:
2、如果在UIView初始化时没有设置rect大小,将直接导致drawRect:不被自动调用。
3、通过设置contentMode属性值为UIViewContentModeRedraw。那么将在每次设置或更改frame的时候自动调用drawRect:
4、直接调用setNeedsDisplay,或者setNeedsDisplayInRect:触发drawRect:,但是有个前提条件是:view当前的rect不能为nil

5、该方法在调用sizeThatFits后被调用,所以可以先调用sizeToFit计算出size。然后系统自动调用drawRect:方法。
这里简单说一下sizeToFit和sizeThatFit:
sizeToFit:会计算出最优的 size 而且会改变自己的size
sizeThatFits:会计算出最优的 size 但是不会改变 自己的 size

注意事项

1、若使用UIView绘图,只能在drawRect:方法中获取相应的contextRef并绘图。如果在其他方法中获取到一个invalidate的ref保存下来,在drawRect中并不能用于画图。等到在这里调用时,可能当前上下文环境已经变化。
2、若使用CALayer绘图,只能在drawInContext: 中(类似于drawRect)绘制,或者在delegate中的相应方法绘制。同样也是调用setNeedDisplay等间接调用以上方法。
3、若要实时画图,不能使用gestureRecognizer,只能使用touchbegan等方法来掉用setNeedsDisplay实时刷新屏幕。
4、UIImageView继承自UIView,但是UIImageView能不重写drawRect方法用于实现自定义绘图。具体原因如下:
Apple在文档中指出:UIImageView是专门为显示图片做的控件,用了最优显示技术,是不让调用darwrect方法, 要调用这个方法,只能从uiview里重写。

layoutSubviews

这个方法是用来对subviews重新布局,默认没有做任何事情,需要子类进行重写。
当我们在某个类的内部调整子视图位置时,需要调用。
反过来的意思就是说:如果你想要在外部设置subviews的位置,就不要重写。

①、- (void)layoutSubviews;
对subview重新布局
②、- (void)setNeedsLayout;
将视图标记为需要重新布局, 这个方法会在系统runloop的下一个周期自动调用layoutSubviews。
③、- (void)layoutIfNeeded;
如果有需要刷新的标记立即调用layoutSubviews进行布局(如果没有标记,不会调用layoutSubviews)这里注意一个点:标记,没有标记,即使我们掉了该函数也不起作用
如果要立即刷新,要先调用[view setNeedsLayout],把标记设为需要布局,然后马上调用[view layoutIfNeeded],实现布局.
在视图第一次显示之前,标记总是“需要刷新”的,可以直接调用[view layoutIfNeeded]

这里有必要描述下三者之间的关系:
在没有外界干预的情况下,一个view的frame或者bounds发生变化时,系统会先去标记flag这个view,等下一次渲染时机到来时(也就是runloop的下一次循环),会去按照最新的布局去重新布局视图。
setNeedLayout就是给这个view添加一个标记,告诉系统下一次渲染时机需要重新布局这个视图。
layoutIfNeed就是告诉系统,如果已经设置了flag,那不用等待下个渲染时机到来,立即重新渲染。前提是设置了flag。
layoutSubviews则是由系统去调用,不需要我们主动调用,我们只需要调用layoutIfNeed,告诉系统是否立即执行重新布局的操作。

layoutSubviews调用时机

结论是经过搜索得到的,基于此笔者进行了验证,并得到了些结果:
1、init初始化不会触发layoutSubviews。
2、addSubview会触发layoutSubviews。(当然这里frame为0,是不会调用的,同上面的drawrect:一样)
3、设置view的Frame会触发layoutSubviews,(当然前提是frame的值设置前后发生了变化。)
4、滚动一个UIScrollView会触发layoutSubviews。
5、旋转屏幕会触发父UIView上的layoutSubviews事件。(这个我们开发中会经常遇到,比如屏幕旋转时,为了界面美观我们需要修改子view的frame,那就会在layoutSubview中做相应的操作)
6、改变一个UIView大小的时候也会触发父UIView上的layoutSubviews事件。
7、直接调用setLayoutSubviews。(Apple是不建议这么做的)

这里需要补充一点:layoutSubview是布局相关,而drawRect则是负责绘制。因此从调用时序上来讲,layoutSubviews要早于drawRect:函数。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 前言: 最近公司项目不怎么忙, 闲暇时间把iOS 在面试中可能会遇到的问题整理了一番, 一部分题目是自己面试遇到...
    Leon_520阅读 7,394评论 3 45
  • 这部分主要讲一下UI视图和图像相关的技术点,大致包括以下内容 UI事件传递&响应 UI图像显示原理 UI卡顿,掉帧...
    theonelgq阅读 403评论 0 1
  • 可否使用 == 来判断两个NSString类型的字符串是否相同?为什么? 不能。==判断的是两个变量的值的内存地址...
    渐z阅读 620评论 0 0
  • layoutSubviews 这个方法,默认没有做任何事情,需要子类进行重写。 (This method) Lay...
    我是不是叫没烦恼阅读 694评论 0 0
  • 原文出自别人之手,只做个人记录而已! Layout相关方法小结 - (CGSize)sizeThatFits:(C...
    安静的抉择阅读 329评论 0 0