UIView

基本属性

坐标属性

  1. frame:CGRect格式,定义其大小和在superView的坐标位置
  2. bounds:CGRect格式,定义其大小和在自己坐标系的位置
  3. center:CGPoint格式,定义其在superView的中心点


    frame&bounds.jpg

    demo

    UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(20, 20, 280, 250)];
    [view1 setBounds:CGRectMake(-20, -20, 280, 250)];
    view1.backgroundColor = [UIColor redColor];
    [self.view addSubview:view1];//添加到self.view
    NSLog(@"view1 frame:%@========view1 bounds:%@",NSStringFromCGRect(view1.frame),NSStringFromCGRect(view1.bounds));
    
    UIView *view2 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
    view2.backgroundColor = [UIColor yellowColor];
    [view1 addSubview:view2];//添加到view1上,[此时view1坐标系左上角起点为(-20,-20)]
    NSLog(@"view2 frame:%@========view2 bounds:%@",NSStringFromCGRect(view2.frame),NSStringFromCGRect(view2.bounds));
结果

透明度属性

  1. hidden:BOOL,默认值是NO;为YES时

    • 该view和其subViews都会从window中消失,不接收任何输入事件
    • 该view会从响应链中移除,响应链中的第二个有效的view会成为第一响应者
  2. opaque:BOOL,默认值是YES;但是当其设置为NO时,并没有消失,是因为

    • GPU会对相重合的的部分进行重新计算,理想情况的公式R = S + D * ( 1 – Sa ),其中S表示源颜色[上层],D表示目标颜色[下层],Sa是S的opaque
    • 如果opaque为YES,则公式变为R = S,不需要任何计算
    • opaque其实是给绘图的性能优化开关
    • 注意:这个是和alpha有关的,opaque为YES,alpha也必须为1.0

    An opaque view is expected to fill its bounds with entirely opaque content—that is, the content should have an alpha value of 1.0. If the view is opaque and either does not fill its bounds or contains wholly or partially transparent content, the results are unpredictable. You should always set the value of this property to NO if the view is fully or partially transparent.

  3. alpha:浮点值,取值范围0~1.0,表示从完全透明到完全不透明;默认值是1;当alpha设为0时

    • 和hidden类似,view和subviews都会消失,该view会从响应链中被移除
    • 会有动画效果,因为alpha是CALayer的隐式动画

内容属性

  1. contentMode:枚举类型,决定内容在view中如何展示的,比如图像是等比拉伸,还是填满view等等

transform

  1. transform在矩阵变换的层面上改变视图的显示效果,完成旋转、形变、平移等等操作。在它被修改的同时,视图的frame也会被真实改变。其是CGAffineTransform类型,2D层面的变化。还有个关于CALayer层面的3D操作:CATransform3D。
  2. 其原点是view.center或者layer.anchorPoint;默认值是CGAffineTransformIdentity矩阵。
  3. 常用的函数
// 用来连接两个变换效果并返回。返回的t = t1 * t2
CGAffineTransformConcat(CGAffineTransform t1, CGAffineTransform t2)
// 矩阵初始值
CGAffineTransformIdentity
// 自定义矩阵变换
CGAffineTransformMake(CGFloat a, CGFloat b, CGFloat c, CGFloat d, CGFloat tx, CGFloat ty)
// 旋转视图,传入参数为 角度 * (M_PI / 180);如:CGAffineTransformRotate(self.transform, angle)
CGAffineTransformMakeRotation(CGFloat angle)
CGAffineTransformRotate(CGAffineTransform t, CGFloat angle)
// 缩放视图。如:CGAffineTransformScale(self.transform, sx, sy)
CGAffineTransformMakeScale(CGFloat sx, CGFloat sy)
CGAffineTransformScale(CGAffineTransform t, CGFloat sx, CGFloat sy)
// 平移视图。如:CGAffineTransformTranslate(self.transform, tx, ty)
CGAffineTransformMakeTranslation(CGFloat tx, CGFloat ty)
CGAffineTransformTranslate(CGAffineTransform t, CGFloat tx, CGFloat ty)
  - (void)viewDidLoad {
    [super viewDidLoad];
    
    UIView *redView = [[UIView alloc]initWithFrame:CGRectMake((kScreenWidth - VIEW_WIDTH)/2, 60, VIEW_WIDTH, VIEW_HEIGHT)];
    redView.backgroundColor = [UIColor redColor];

    CGPoint anchorPoint = redView.layer.anchorPoint;
    UIView *pointView = [[UIView alloc]initWithFrame:CGRectMake(anchorPoint.x*VIEW_WIDTH - POINT_W_H/2,anchorPoint.y*VIEW_HEIGHT -POINT_W_H/2 ,POINT_W_H ,POINT_W_H )];
    pointView.layer.cornerRadius = POINT_W_H/2;
    pointView.backgroundColor = [UIColor blackColor];
    pointView.clipsToBounds = YES;
    
    [redView addSubview:pointView];
    
    [self.view addSubview:redView];
    
//    [self performSelector:@selector(rotateView:) withObject:redView afterDelay:3];
//    [self performSelector:@selector(translateView:) withObject:redView afterDelay:3];
    [self performSelector:@selector(scaleView:) withObject:redView afterDelay:3];
}

- (void)rotateView:(UIView *)view
{
    view.transform = CGAffineTransformRotate(view.transform, M_PI/6);
    NSLog(@"view frame:%@========view bounds:%@",NSStringFromCGRect(view.frame),NSStringFromCGRect(view.bounds));
    NSLog(@"view layer posistion:%@========view layer anchorPoint:%@",NSStringFromCGPoint(view.layer.position),NSStringFromCGPoint(view.layer.anchorPoint));
    [self performSelector:@selector(rotateView:) withObject:view afterDelay:1];
}

- (void)translateView:(UIView *)view
{
    view.transform = CGAffineTransformTranslate(view.transform, VIEW_WIDTH/10, VIEW_HEIGHT/10);
    [self performSelector:@selector(translateView:) withObject:view afterDelay:1];
}

- (void)scaleView:(UIView *)view
{
    //缩小
    view.transform = CGAffineTransformScale(view.transform , 0.8, 0.8 );
    //放大
//    view.transform = CGAffineTransformScale(view.transform , 1.25, 1.25 );
    [self performSelector:@selector(scaleView:) withObject:view afterDelay:1];
}
//增加动画过程展示,以rotate为例
- (void)rotateViewWithAnimation:(UIView *)view
{
    [UIView animateWithDuration: 3. animations: ^ {
        view.transform = CGAffineTransformRotate(view.transform, M_PI/6);
    }];
}

setNeedsDisplay、setNeedsLayout、layoutIfNeeded、layoutSubviews

  1. 布局/定位相关
  • setNeedsLayout:在receiver标上一个需要被重新布局的标记,在系统runloop的下一个周期自动调用layoutSubviews
  • layoutIfNeeded:会遍历subviews链,如果需要layout,立即调用layoutSubviews
  • layoutSubviews:核心函数,最终的目的就是调用该函数,开发者不要直接调用该函数,但可以重写该函数,来加入些自己的代码。该函数只会进行位置,视图大小的数字计算,并不会引起屏幕的绘制。

在苹果的官方文档中强调: You should override this method only if the autoresizing behaviors of the subviews do not offer the behavior you want.自动布局达不到想要效果时你才有必要重写这个方法.可以直接设置subviews的尺寸;不要直接调用这个方法,因为不会有任何的作用.如果你需要强制layout刷新,调用setNeedsLayout来代替; 如果你想要立即刷新你的view,调用layoutIfNeeded.

  1. 显示相关
  • setNeedsDisplay:在receiver标上一个需要被重新绘图的标记,在下一个draw周期自动重绘
  • setNeedsDisplayInRect:不但设置了标记,而且详细规定了需要刷新的区域。
  • drawRect:核心函数,将重绘的结果显示到屏幕上。开发人员不可以直接调用该函数,只能重写该函数,额外做一些事。
  1. 约束相关(Auto layout)
  • setNeedsUpdateCOnstraints:当一个自定义view的某个属性发生改变,并且可能影响到constraint时,需要调用此方法去标记constraints需要在未来的某个点更新,系统然后调用updateConstraints。
  • updateConstraintsIfNeeded:如果需要更新约束,立即执行
  • updateConstraints:自定义view应该重写此方法在其中建立constraints

layoutSubviews在以下情况下会被调用:

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

drawRect在以下情况下会被调用:

  1. 如果在UIView初始化时没有设置rect大小,将直接导致drawRect不被自动调用。drawRect调用是在Controller->loadView, Controller->viewDidLoad两个方法之后掉用的.所以不用担心在控制器中,这些View的drawRect就开始画了。这样可以在控制器中设置一些值给View(如果这些View draw的时候需要用到某些变量值)。
  2. 该方法在调用sizeToFit后被调用,所以可以先调用sizeToFit计算出size。然后系统自动调用drawRect:方法。
  3. 通过设置contentMode属性值为UIViewContentModeRedraw。那么将在每次设置或更改frame的时候自动调用drawRect:。
  4. 直接调用setNeedsDisplay或者setNeedsDisplayInRect: 触发drawRect:,但是有个前提条件是rect不能为0。

参考

UIView 文档
理解position和anchorPoint
iOS动画-Transform和KeyFrame动画
CGAffineTransform放射变换
内存恶鬼drawRect - 谈画图功能的内存优化

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

推荐阅读更多精彩内容

  • 初识iOS APP开发#### 在iOS APP开发中, main函数仍是程序的入口和出口, 但main函数不需要...
    DeanYan阅读 6,110评论 0 3
  • 一、初始化方法 1、- initWithFrame: UIView *view = [[UIView alloc]...
    默默_David阅读 2,478评论 1 3
  • // //UIView.h //UIKit // //Copyright (c) 2005-2015 Apple ...
    李某lkb阅读 1,699评论 0 0
  • UIView(控件) 功能一:界面显示1. 屏幕上显示的所有UI元素都叫做控件,也有人叫做视图、组件;按钮(UIB...
    翻这个墙阅读 611评论 0 0
  • 你看春天 你看细雨顽皮飘摇过远帆 烟花三月里路过了江南 湖面上波光闪 暖风隔岸 你看夏天 你看江水流深树荫下听蝉 ...
    R先森airy阅读 734评论 0 4