UIKit 探秘——UIView头文件分析

博客声明:

所有写的这些文字都只是我的个人学习笔记,内容不一定准确,仅供参考。如有错误请拍砖。鄙人及时更正。

<br />
<br />

UIView 类是 UIKit 中最基础的类。
在屏幕上我们能够看得见的东西基本上都是 UIView或者是 UIView 的子视图。一般翻译:视图、控件、组件。

  • 注意点:

每一个UIView都是一个容器,能容纳其他UIView。

UIView 的功能:
1. 管理 UIView 视图中的内容
2. 处理 UIView 视图中的事件

我主要是通过的 UIView 的头文件进行分析,了解 UIView 中的各个细节知识点。在通过 UIView 中包含的细节知识点进行知识点的扩展学习。

UIView 接口文档分析:

UIView 基本定义

// UIView 继承自 UIResponder 可以说所有继承自 UIView 的视图都是可以处理触摸事件。
NS_CLASS_AVAILABLE_IOS(2_0) @interface UIView : UIResponder <NSCoding, UIAppearance, UIAppearanceContainer, UIDynamicItem, UITraitEnvironment, UICoordinateSpace, UIFocusEnvironment>

+ (Class)layerClass;                        
// default is [CALayer class]. Used when creating the underlying layer for the view. 
//(默认是 [CALayer class] 当使用的时候创建 view 的根图层)


// 指定初始化构造器
// 代码创建的时候调用
- (instancetype)initWithFrame:(CGRect)frame NS_DESIGNATED_INITIALIZER;
// xib sb 创建的时候调用
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder NS_DESIGNATED_INITIALIZER;

// 是否允许与用户交互
@property(nonatomic,getter=isUserInteractionEnabled) BOOL userInteractionEnabled;  
// default is YES. if set to NO, user events (touch, keys) are ignored and removed from the event queue.(默认是 yes,如果设置为 no ,用户的事件就会被忽略并且从事件队列中移除)

// 视图的标签(可以用来获取视图)
@property(nonatomic)                                 NSInteger tag;                // default is 0

// 返回 view 的根 图层,返回值总是一个非空的值 view 是 layer 的代理
@property(nonatomic,readonly,strong)                 CALayer  *layer;              // returns view's layer. Will always return a non-nil value. view is layer's delegate

// iOS9新加的方法,没有怎么关注
- (BOOL)canBecomeFocused NS_AVAILABLE_IOS(9_0); // NO by default
@property (readonly, nonatomic, getter=isFocused) BOOL focused NS_AVAILABLE_IOS(9_0);

+ (UIUserInterfaceLayoutDirection)userInterfaceLayoutDirectionForSemanticContentAttribute:(UISemanticContentAttribute)attribute NS_AVAILABLE_IOS(9_0);
@property (nonatomic) UISemanticContentAttribute semanticContentAttribute NS_AVAILABLE_IOS(9_0);
@end

问题 1:UIView 初始化方法的使用
- (instancetype)initWithFrame:(CGRect)frame
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder

  • 我们使用 IB(使用拖拽的方式构建视图:xib、sb) 进行开发的时候, 我们需要在代码中动态调整 xib 或 sb 视图的属性的时候需要重写 - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder 方法。
  • 当我们使用手动 alloc 和 init 的方式来创建视图的时候。我们需要重写 - (instancetype)initWithFrame:(CGRect)frame 方法来添加视图或设置默认的属性。使用这个方法会根据指定的 frame 来创建子视图(有时候不一定)。这个方法的使用必须先调用父类。
// 调用init这个方法来初始化view的时候,系统会自动调用initWithFrame方法
- (instancetype)initWithFrame:(CGRect)frame{
    NSLog(@"%s",__func__);
    if (self = [super initWithFrame:frame])
    {

    }
    return self;
}

// 如果系统是通过xib/storyboard初始化的时候会调用这个方法,
- (instancetype)initWithCoder:(NSCoder *)aDecoder{
    NSLog(@"%s",__func__);
    if (self = [super initWithCoder:aDecoder])
    {

    }
    return self;
}

问题 2:UIView 初始化方法的时候 什么怎么使用 initinitWithFrame

UIView *view = [[UIView alloc] init];  // 这个是使用系统的类创建

// 我们自己创建一个子类 XXJView
XXJView *view = [[XXJView alloc] init];

//重写子类的方法 进行拦截
- (instancetype)init
{
    self = [super init];
    if (self) {
        NSLog(@"%s",__func__);
    }
    return self;
}

- (instancetype)initWithCoder:(NSCoder *)coder
{
    self = [super initWithCoder:coder];
    if (self) {
        NSLog(@"%s",__func__);
    }
    return self;
}

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        NSLog(@"%s",__func__);
    }
    return self;
}

// 打印结果:
2016-04-21 02:11:00.813 UIViewDemo[12148:3954143] -[XXJView initWithFrame:]
2016-04-21 02:11:00.814 UIViewDemo[12148:3954143] -[XXJView init]

使用 init 的时候还是会调用 initWithFrame 方法。
所以:
    当我们在 initWithFrame 执行完相应的初始化操作后,不应该再在 init 方法中进行初始化。


我们也有可能这么用:
XXJView *view = [[XXJView alloc] initWithFrame:CGRectZero];


打印的结构是:
2016-04-21 02:50:01.240 UIViewDemo[12281:4161758] -[XXJView initWithFrame:]

使用 initWithFrame 的时候,  init 方法是不会被调用。

在使用纯代码创建视图的时候:我们一定要重写 initWithFrame 方法来进行相应的初始化操作。 init 方法可以重写也可以不重写。

UIView 的几何分类 ( 这个是我们用的最多的也是最重要的)

@interface UIView(UIViewGeometry)

// animatable. do not use frame if view is transformed since it will not correctly reflect the actual location of the view. use bounds + center instead.
// 视图在父视图中的尺寸和位置(以父控件的左上角为坐标原点)
@property(nonatomic) CGRect            frame;

// use bounds/center and not frame if non-identity transform. if bounds dimension is odd, center may be have fractional part

// 控件所在矩形框的位置和尺寸(以自己左上角为坐标原点,所以bounds的x\y一般为0)
@property(nonatomic) CGRect            bounds;      // default bounds is zero origin, frame size. animatable

// 控件中点的位置(以父控件的左上角为坐标原点)
@property(nonatomic) CGPoint           center;      // center is center of frame. animatable

// 仿射变换(通过这个属性可以进行视图的平移、旋转和缩放)
@property(nonatomic) CGAffineTransform transform;   // default is CGAffineTransformIdentity. animatable

// 内容视图伸张的模式
@property(nonatomic) CGFloat           contentScaleFactor NS_AVAILABLE_IOS(4_0);
// 是否多点触摸
@property(nonatomic,getter=isMultipleTouchEnabled) BOOL multipleTouchEnabled __TVOS_PROHIBITED;   // default is NO
@property(nonatomic,getter=isExclusiveTouch) BOOL       exclusiveTouch __TVOS_PROHIBITED;         // default is NO


// 这两个方法主要是进行用户事件的拦截
- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event;   // recursively calls -pointInside:withEvent:. point is in the receiver's coordinate system
- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event;   // default returns YES if point is in bounds (当 point 在 视图内,返回的值是 yes)



// 视图中的坐标转换
- (CGPoint)convertPoint:(CGPoint)point toView:(nullable UIView *)view;
- (CGPoint)convertPoint:(CGPoint)point fromView:(nullable UIView *)view;
- (CGRect)convertRect:(CGRect)rect toView:(nullable UIView *)view;
- (CGRect)convertRect:(CGRect)rect fromView:(nullable UIView *)view;

@property(nonatomic) BOOL               autoresizesSubviews; // default is YES. if set, subviews are adjusted according to their autoresizingMask if self.bounds changes
@property(nonatomic) UIViewAutoresizing autoresizingMask;    // simple resize. default is UIViewAutoresizingNone

- (CGSize)sizeThatFits:(CGSize)size;     // return 'best' size to fit given size. does not actually resize view. Default is return existing view size

// 调用这个方法实际上是调用 sizeThatFits 方法。
- (void)sizeToFit;                       // calls sizeThatFits: with current view bounds and changes bounds size.

@end

问题 1 : 理解 frame bounds center 三个属性。
frame bounds center 的图示:
frame: 以父视图为原点。
bounds : 以自身为原点。
center : 以父视图为原点。


Snip20160421_7.png

问题 2 : 仿射变换 属性的使用
@property(nonatomic) CGAffineTransform transform; 这个属性主要是来给视图进行一些 2D 的转换。主要的操作有 :平移、 旋转、缩放。

(1) 创建“基于控件初始位置”的形变

CGAffineTransformMakeTranslation(平移)
CGAffineTransformMakeScale(缩放)
CGAffineTransformMakeRotation(旋转)

(2) 创建“基于transform参数”的形变

CGAffineTransformTranslate
CGAffineTransformScale
CGAffineTransformRotate
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容