layoutSubviews和drawRect:(CGRect)rect的用法探讨

布局/定位相关
@interface UIView(UIViewHierarchy)
- (void)setNeedsLayout;
注意:
   1.在receiver标上一个需要被重新布局的标记,在系统runloop的下一个周期自动调用layoutSubviews。
- (void)layoutIfNeeded;
注意:
   1.方法如其名,UIKit会判断该receiver是否需要layout.根据Apple官方文档,layoutIfNeeded方法应该是这样的layoutIfNeeded遍历的不是superview链,应该是subviews链。
- (void)layoutSubviews;
注意:
  1.这是核心函数,最终的目的就是调用该函数,开发者不能调用直接调用该函数,但可以重写该函数,来加入些自己的代码。该函数只会进行位置,视图大小的数字计算,并不会引起屏幕的绘制。
  2.在苹果的官方文档中强调 "You should override this method only if the autoresizing behaviors of the subviews do not offer the behavior you want."
   大意是:当我们在某个类的内部调整子视图位置时,需要调用;如果你想要在外部设置subviews的位置,就不要重写。
  3.如果要立即刷新,要先调用[view setNeedsLayout],把标记设为需要布局,然后马上调用[view layoutIfNeeded],实现布局. 在视图第一次显示之前,标记总是“需要刷新”的,可以直接调用[view layoutIfNeeded]
  4.layoutSubviews自动调用的时机
    1>init初始化不会触发layoutSubviews,
    2>addSubview会触发layoutSubviews,但是frame为0时也不会触发
    3>设置view的Frame会触发layoutSubviews,当然前提是frame的值设置前后发生了变化
    4>改变一个UIView大小的时候也会触发父UIView上的layoutSubviews事件
    5>不用滚动就会触发UIScrollView会触发layoutSubviews
    6>旋转Screen会触发父UIView上的layoutSubviews事件
@end
显示相关
@interface UIView(UIViewRendering)
- (void)setNeedsDisplay;
注意:
   1.在receiver标上一个需要被重新绘图的标记,在下一个draw周期自动重绘,iphone device的刷新频率是60hz,也就是1/60秒后重绘;
- (void)setNeedsDisplayInRect:(CGRect)rect;
注意:
   1.不但设置了flag,而且详细规定了需要刷新的区域。
- (void)drawRect:(CGRect)rect;
注意:
   1.这是核心函数,最终导致显示到屏幕上。开发人员不可以直接调用该函数,只能重写该函数,额外做一些我们想做的事。是对receiver的重绘,能获得context。
   2.在UIView中,重写drawRect: (CGRect) aRect方法,可以自己定义想要画的图案.且此方法一般情况下只会画一次。也就是说这个drawRect方法一般情况下只会被调用一次
   3.调用setNeedsDisplay会自动调用drawRect(注意苹果不建议直接调用drawRect方法),前提是rect大小存在,如果在UIView初始化时没有设置rect大小,将直接导致drawRect不被自动调用。
   4.drawRect调是在Controller->loadView, Controller->viewDidLoad 两方法之后掉用的.所以不用担心在控制器中,这些View的drawRect就开始画了
   5.该方法在调用sizeThatFits后被调用,所以可以先调用sizeToFit计算出size。然后系统自动调用drawRect:方法。
   6.通过设置contentMode属性值为UIViewContentModeRedraw。那么将在每次设置或更改frame的时候自动调用drawRect:。
   7.若使用UIView绘图,只能在drawRect:方法中获取相应的contextRef并绘图。如果在其他方法中获取将获取到一个invalidate的ref并且不能用于画图。drawRect:方法不能手动显示调用,必须通过调用setNeedsDisplay 或者 setNeedsDisplayInRect ,让系统自动调该方法。
   8.若使用calayer绘图,只能在drawInContext: 中(类似鱼drawRect)绘制,或者在delegate中的相应方法绘制。同样也是调用setNeedDisplay等间接调用以上方法。
   9.若要实时画图,不能使用gestureRecognizer,只能使用touchbegan等方法来掉用setNeedsDisplay实时刷新屏幕
  10.调用setNeedsLayout和layoutIfNeeded 也会自动调用drawRect,前提是rect大小存在,如果在UIView初始化时没有设置rect大小,将直接导致drawRect不被自动调用。
@end

@interface UIView(UIViewGeometry)
- (CGSize)sizeThatFits:(CGSize)size;  // return 'best' size to fit given size. does not actually resize view. Default is return existing view size
注意: 1.会计算出最优的 size 但是不会改变自己的size (要想改变label的size ,还要把计算的结果,赋给相应的view);
         2.参数Size 你可以输入任何值,不影响
- (void)sizeToFit;                                  // calls sizeThatFits: with current view bounds and changes bounds size.
注意: 1.会计算出最优的 size 而且会改变自己的size(view直接就改变自身的大小)
@end

示例:

#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    UILabel * label =[[UILabel alloc]initWithFrame:CGRectMake(100, 100, 100, 20)];
    label.backgroundColor =[UIColor blueColor];
    label.text [email protected]"sizeThatFits: 和 sizeToFit 验证";
    label.font=[UIFont systemFontOfSize:20];
    label.textColor =[UIColor blackColor];
    NSInteger i =1;// 1或者2
    switch (i){
        case 1:
            [self  sizeThatFitsSender:label];
            break;
        case 2:
            [self sizeToFitSender:label];
        default:
            break;
    }
    [self.view addSubview:label];
}
//sizeThatFits:的用法验证
-(void)sizeThatFitsSender:(UILabel *)label{
    [label sizeThatFits:CGSizeMake(20, 20)];//会计算出最优的size 但是不会改变自己的size.
    NSLog(@"label sizeThatFits frame=%@ ",NSStringFromCGRect(label.frame));
    NSLog(@"best size = %@ ",NSStringFromCGSize([label sizeThatFits:CGSizeMake(2, 1)]));
}
//sizeToFit的用法验证
-(void)sizeToFitSender:(UILabel *)label{
      [label sizeToFit];//会计算出最优的 size 而且会改变自己的size
      NSLog(@"testLabel sizeToFit frame = %@",NSStringFromCGRect(label.frame));
}

//sizeThatFits:的用法验证

打印结果

//sizeToFit的用法验证

打印结果

时间: 2024-10-19 10:25:57

layoutSubviews和drawRect:(CGRect)rect的用法探讨的相关文章

iOS 学习笔记——0010(- (void)drawRect:(CGRect)rect)

// Created by 少林 on 15/11/26. // Copyright © 2015年 少林. All rights reserved. // #import "UIPillsViewBackgroundView.h" #define THE_VIEW_COLOR [UIColor whiteColor] const CGFloat VIEW_RADIUS = 5.0f; const CGFloat VIEW_LINE_WIDTH = 3.0f; @implementat

UIView中的layoutSubviews和drawRect

UIView里暴露了以下接口,换做之前我是不会管的,基本不会用到:最近由于用到一个第三方代码,需要对其进行改造,不了解清楚的话,感觉是如鲠在喉,化了半天时间做个调研. 我以前做过功能手机上的开发,那个年代没有智能操作系统,每家公司都做自己的操作系统,其中重要且复杂的一块就是关于屏幕上绘制: 1,想象一下,一个uiviewcontroller是盖在另一个uiviewcontroller至少,或者一个view遮盖了另外一个view,也许只遮盖了部分,那么被遮盖部分是无需显示到屏幕上的:再复杂一点,上

iOS开发——UI篇OC篇&layoutSubviews和drawRect

layoutSubviews和drawRect 首先两个方法都是异步执行.layoutSubviews方便数据计算,drawRect方便视图重绘. layoutSubviews在以下情况下会被调用: 1.init初始化不会触发layoutSubviews. 2.addSubview会触发layoutSubviews. 3.设置view的Frame会触发layoutSubviews,当然前提是frame的值设置前后发生了变化. 4.滚动一个UIScrollView会触发layoutSubviews

UIView的layoutSubviews和drawRect方法何时调用

首先两个方法都是异步执行.layoutSubviews方便数据计算,drawRect方便视图重绘. layoutSubviews在以下情况下会被调用: 1.init初始化不会触发layoutSubviews. 2.addSubview会触发layoutSubviews. 3.设置view的Frame会触发layoutSubviews,当然前提是frame的值设置前后发生了变化. 4.滚动一个UIScrollView会触发layoutSubviews. 5.旋转Screen会触发父UIView上的

UIView的layoutSubviews和drawRect方法

UIView的layoutSubviews和drawRect方法 首先两个方法都是异步执行.layoutSubviews方便数据计算,drawRect方便视图重绘. layoutSubviews在以下情况下会被调用: 1.init初始化不会触发layoutSubviews.2.addSubview会触发layoutSubviews.3.设置view的Frame会触发layoutSubviews,当然前提是frame的值设置前后发生了变化.4.滚动一个UIScrollView会触发layoutSu

sed的模式匹配用法探讨

[[email protected] Desktop]# cat sunsky a b c d e f [[email protected] Desktop]# cat sunsky|sed '1,2d'|sed '1,2d' e f [[email protected] Desktop]# cat sunsky|sed -e '1,2d' -e '1,2d' d e f 问题: sed中-e的意思是直接在指令列模式上进行sed的动作编辑按照,那么按照-e的含义,上下两组命令的执行结果应该相同,

IOS中UIView的layoutSubviews和drawRect

UIView的setNeedsDisplay和setNeedsLayout方法.首先两个方法都是异步执行的.setNeedsDisplay会调用自动调用drawRect方法,这样可以拿到UIGraphicsGetCurrentContext,就可以画画了.而setNeedsLayout会默认调用layoutSubViews,就可以处理子视图中的一些数据. 综上两个方法都是异步执行的,layoutSubviews方便数据计算,drawRect方便视图重绘. 先大概看下ios layout机制相关的

iOS UIView的layoutSubviews和drawRect

UIView的setNeedsDisplay和setNeedsLayout方法.首先两个方法都是异步执行的.setNeedsDisplay会调用自动调用drawRect方法,这样可以拿到UIGraphicsGetCurrentContext,就可以画画了.而setNeedsLayout会默认调用layoutSubViews,就可以处理子视图中的一些数据. 综上两个方法都是异步执行的,layoutSubviews方便数据计算,drawRect方便视图重绘. 先大概看下ios layout机制相关的

layoutSubviews 与 drawRect

layoutSubviews在以下情况下会被调用: 1.init初始化不会触发layoutSubviews.2.addSubview会触发layoutSubviews.3.设置view的Frame会触发layoutSubviews,当然前提是frame的值设置前后发生了变化.4.滚动一个UIScrollView会触发layoutSubviews.5.旋转Screen会触发父UIView上的layoutSubviews事件.6.改变一个UIView大小的时候也会触发父UIView上的layoutS