iOS编程:学习篇(六)

Chapter 4 视图与视图层次结构

视图基础

  • 视图是UIView对象,或是UIView子类对象
  • 视图知道如何绘制自己
  • 视图可以处理事件(触摸touch)
  • 视图会按层次结构排列,位于视图层次结构顶端的是应用窗口

视图层次结构

任何一个应用都有且只有一个UIWindow对象。UIWindow对象就像一个容器,负责包含应用中的所有视图。应用需要在启动时创建并设置UIWindow对象,然后为其添加其他视图。
加入窗口的视图会成为窗口的子视图(subview)。窗口的子视图还可以有自己的子视图,从而构成一个以UIWindow对象为根视图的视图层次结构。
视图层次结构形成之后,系统会将其绘制到屏幕上,绘制过程可以分为两步:
- 层次结构中的每个视图(包括UIWindow对象)分别绘制自己。视图会将自己绘制到图层(layer)上,每个UIView对象都有一个layer属性,指向一个CALayer类的对象。
- 所有视图的图层组合成一幅图像,绘制到屏幕上。
即:视图首先分别绘制自己,然后组合起来绘制到屏幕上。
###视图及其frame属性
CGRect结构包含另外两个结构:origin和size。origin的类型是CGPoint结构,该结构包含两个float类型的成员:x 和 y。size是CGSize结构,该结构也包含两个float类型的成员:width 和 height。
结构不是Objective-C对象,因此不能向CGRect发送消息。可以使用CGRectMake函数创建一个CGRect。CGRect占用的内存比大部分对象都小,因此不用传入指针—-initWithFrame:方法中需要传入的参数类型是CGRect,而不是CGRect *。
其中CGRect的单位是点(point),不是像素(pixels)。如果是单位是像素,那么视图在Retina和非Retina显示屏上的大小无法保持一致。点的大小和分辨率相关,取决于屏幕以多少像素一个点。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    CGRect firstFrame = CGRectMake(160, 240, 100, 150);
    HypnosisterView *firstView = [[HypnosisterView alloc] initWithFrame:firstFrame];
    firstView.backgroundColor = [UIColor redColor];
    [self.window addSubview:firstView];
    self.window.backgroundColor = [UIColor whiteColor];

    [self.window makeKeyAndVisible];
    return YES;
}

每个UIView对象都有一个superview属性。将一个视图作为子视图加入另一个视图时,会自动创建相应的反向关联。此处的HypnosisterView对象的superview属性指向应用的UIWindow对象。

    CGRect secondFrame = CGRectMake(20, 30, 50, 50);
    HypnosisterView *secondView = [[HypnosisterView alloc] initWithFrame:secondFrame];
    secondView.backgroundColor = [UIColor blueColor];
    [firstView addSubview:secondView];

如果将第二个Hypnosister对象加到第一个view中,其中CGRect的位置就不是相对于整个window了,而是相对于第一个Hypnosister对象。

- (void)drawRect:(CGRect)rect{
    CGRect bounds = self.bounds;
    // 根据bounds计算中心
    CGPoint center;
    center.x = bounds.origin.x + bounds.size.width / 2.0;
    center.y = bounds.origin.y + bounds.size.height / 2.0;
    // 比较height和width,将较小值的二分之一设为圆形的半径
    float radius = hypotf(bounds.size.width, bounds.size.height) / 2.0;
    UIBezierPath *path = [[UIBezierPath alloc] init];
    for (float currentRadius = radius; currentRadius > 0; currentRadius -= 20) {
        [path addArcWithCenter:center radius:currentRadius startAngle:0.0 endAngle:M_PI * 2 clockwise:YES];
        path.lineWidth = 10;
        [[UIColor lightGrayColor] setStroke];
        [path stroke];
    }
}

其中上述代码绘制出一个有着一条线连接着的同心圆。
为什么会出现以上这个现象呢?
这是因为单个UIBezierPath对象将多个路径连接起来,形成一个完整的路径。就比如一支铅笔绘制完一个圆时,笔尖并没有抬起来,继续绘制下一个园。

[path moveToPoint:CGPointMake(center.x + currentRadius, center.y)];

所以moveToPoint:就解决了这个问题。

深入学习:Core Graphics

为了真正了解图的过程与原理,必须深入学习Core Graphics是如何工作的。
Core Graphics是一套提供2D绘图功能的C语言API,使用C结构和C函数模拟了一套面向对象的编程机制,并没有Objective-C对象和方法。
Core Graphics是一套提供2D绘图功能的C语言API,使用C结构和C函数模拟了一套面向对象的编程机制,并没有Objective-C对象和方法。Core Graphics中最重要的”对象”是图形上下文(graphics context),图形上下文是CGContextRef的“对象”,负责存储绘图状态和绘制内容所处的内存空间。
drawRect:方法执行过程:
视图的drawRect:方法在执行之前,系统首先为视图的图层创建一个图形上下文,然后为绘图状态设置一些默认参数。drawRect:方法开始执行,随着图形上下文不断执行绘图操作,图层上的内容也会随之改变。drawRect:执行完毕后,系统会讲图层与其他图层一起组合成完整并显示在屏幕上。

Tips:实际上,UIBezierPath和UIColor在Core Graphics中对应的C结构:CGMutablePathRef和CGColorRef。
Core Graphics类型都有一个Ref后缀,Ref是为了区分指针变量还是可以接受消息的Objective-C对象。

高级练习:阴影和渐变

绘制阴影前,需要将阴影效果添加到一个图形上下文中,之后在该图形上下文中绘制的所哟不透明图形都会带有阴影效果。可以为阴影设置偏移量(CGSize)和模糊指数(CGFloat)。
为图形上下文添加阴影效果的方法声明:

void CGContextSetShadow(
    CGContectRef context,
    CGSize offset,
    CGFloat blur);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值