iOSiOS Developer首页投稿(暂停使用,暂停投稿)

图形与动画(一)--附Demo

2016-07-13  本文已影响198人  0o冻僵的企鹅o0

最近在看《iOS 6 Programming Cookbook》的翻译版,它由DevDiv论坛的网友翻译,原文地址:点击跳转。由于下载的pdf都有水印,并且排版不是很好,特别是代码排版,基本不能看,所以这里就整理了一下,方便再次查看。另外把里面提到的点写了一个demo,由于里面一些代码现在已经废弃,所以demo中都是用的新api,下载地址在这里:图形与动画Demo

1.1 枚举和加载字体

字体是在图形用户界面上显示文字的基础。UIKIt 框架为程序员提供了便于枚举,加载,和使用字体的高级别 API。字体被封装于 Cocoa Touch 中的 UIFont 类中。每个 iOS 设 备自身都有内建的系统字体。字体被组织到 family 中,每个 family 中包含 face。比如,Helvetica 是一个字体 family,Helvetica BoldHelvetica 家庭的一个 face。为了能加载字体,你必须知道字体的face(也就是他的名字)--- 要想知道它的face,就必须知道 family,所以,我们首先要枚举出安装到设备上的所有的字体family,使用 UIFont 类的 familyNames 类方法:

- (void) enumerateFonts
{
    for (NSString *familyName in [UIFont familyNames])
    {
        NSLog(@"Font Family = %@", familyName);
    }
}

在 iOS 模拟器上运行这个程序,我得到了类似下面的结果:

Font Family = Heiti TC
Font Family = Sinhala Sangam MN
Font Family = Kannada Sangam MN
Font Family = Georgia
Font Family = Heiti J
Font Family = Times New Roman Font
Family = Snell Roundhand
Font Family = Geeza Pro
Font Family = Helvetica Neue ...

在得到字体 family 之后,我们可以在每个 family 内部枚举字体名字。我们使用UIFont 类的 fontNamesForFamilyName:类方法,可以得到以 family 名字作为参数得到的字体名字数组:

- (void) enumerateFonts
{
    for (NSString *familyName in [UIFont familyNames])
    { 
        NSLog(@"Font Family = %@", familyName);
        for (NSString *fontName in [UIFont fontNamesForFamilyName:familyName])
        {
            NSLog(@"\t%@", fontName);
        }
    }
}

在 iOS 设备上运行上面的代码,我们得到如下结果:

...
Font Family = Geeza Pro
GeezaPro
GeezaPro-Bold
Font Family = Helvetica Neue
HelveticaNeue-Italic 
HelveticaNeue-Bold 
HelveticaNeue-BoldItalic
HelveticaNeue
...

你可以看到,Helvetica Neue 是字体 family,HelveticaNeue-Bold 是这个family 中的一个字体名字。现在我们知道了字体名字,我们就可以使用 UIFont 的fontWithName:size:类方法 将字体加载到 UIFont 类型对象中:

UIFont *helveticaBold = [UIFont fontWithName:@"HelveticaNeue-Bold" size:12.0f];

如果 UIFont 类的 fontWithName:size:类方法的返回结果为 nil,指定的字体名字不能被找到。首先枚举出所有的字体 family 和该 family 中的所有字体名字,可以确 保你提供的字体名字在系统中可用。
你也可以使用 UIFont 类的 systemFontOfSize:类方法(译者:原文是 instance method,但 实际上是类方法)(或者它的粗体方法,boldSystemFontOfSize:)从你代码运行的设备上加 载系统字体,不管这些字体是什么。iOS 设备的默认系统字体是 Helvetica

1.2 绘制文本

drawRect:方法是我们要进行绘制的地方,如前面所提到的那样。在此,我们可以开始加载字体,然后在屏幕上 x 轴的 40 及 y 轴 180 处以 40 点的字体画出一个简单的字符串(图 1-1):

- (void)drawRect:(CGRect)rect
{
    UIFont *font = [UIFont fontWithName:@"IowanOldStyle-BoldItalic"
                                   size:30];
    NSString *str = @"some string";
    [str drawAtPoint:CGPointMake(20, 200)
      withAttributes:@{NSFontAttributeName:font}];
}

在上面的代码中,我见仅仅是加载了一个 40 点尺寸的粗体 Helvetica 字体,然后使用它 来在点(40, 180)画出了文本“Some String”。

图 1-1 在一个视图的图形环境上绘制的一个随机字符串

绘制颜色和字体

- (void)drawRect:(CGRect)rect
{
    UIColor *magentaColor =[UIColor redColor];
    UIFont *font = [UIFont fontWithName:@"IowanOldStyle-BoldItalic"
                                   size:30];
    NSString *str = @"some string";
    [str drawAtPoint:CGPointMake(20, 200)
      withAttributes:@{NSFontAttributeName:font,
                       NSForegroundColorAttributeName:magentaColor}];

使用 NSString 的 drawInRect:withAttributes:方法绘制文字

使用 NSString 类的drawInRect:withAttributes:实例方法,将文本绘制在指定矩形空间 中。文本为了适配矩形会被拉伸

- (void)drawRect:(CGRect)rect
{
    // Drawing code
    UIColor *magentaColor =[UIColor redColor];
    UIFont *font = [UIFont fontWithName:@"IowanOldStyle-BoldItalic"
                                   size:30];
    NSString *str = @"I Learn Really Fast";
    [str drawInRect:CGRectMake(20, 200, 100, 200)
     withAttributes:@{NSFontAttributeName:font,
                      NSForegroundColorAttributeName:magentaColor}];
}

效果如下图所示:

图1-2 绘制文本"I Learn Really Fast"

获取颜色的组成

/* Load the color */
    UIColor *steelBlueColor = [UIColor colorWithRed:0.3f
                                              green:0.4f
                                               blue:0.6f
                                              alpha:1.0f];
    CGColorRef colorRef = [steelBlueColor CGColor];
    const CGFloat *components = CGColorGetComponents(colorRef);
    NSUInteger componentsCount = CGColorGetNumberOfComponents(colorRef);
    NSUInteger counter = 0;
    for (counter = 0; counter < componentsCount;  counter++)
    {
        NSLog(@"Component %lu = %.02f", (unsigned long)counter + 1, components[counter]);
    }
   

在我们运行上面的代码后,控制台窗口的输出为:

Component 1 = 0.30
Component 2 = 0.40
Component 3 = 0.60
Component 4 = 1.00

1.3 绘制图像

imageNamed: 类方法

加载图片(如果加载成功还会缓存图像)。参这个方法的参数是 bundle 中的图像名字,比如 Tree Texture.png。

imageWithData: 类方法

NSData 对象实例中包裹的数据中加载图片,NSData 对象是此方法的参数传入的。

initWithContentsOfFile:实例方法(用于初始化)

使用指定参数作为路径来加载一个图像,并用来初始化图像对象。路径应该是在 bundle 中图像的完整路径

initWithData:实例方法(用于初始化)

使用 NSData 类型的指定参数来初始化图像。这个数据应该属于一个有效图像。

 drawAtPoint:UIImage 的实例方法

将图片以原始尺寸绘制到指定坐标点。使用 CGPointMake 函数来构造坐标点。

drawInRect:UIImage 的实例方法 

在指定的矩形空间绘制图片,要构造这个矩形空间,请使用 CGRectMake 函数。

两个绘制图片的方法与绘制文字方法类似,就不贴代码了,可以在demo里面查看。

1.4 构造可伸缩图片

使用 UIImage 类的实例方法 resizableImageWithCapInsets:创建一个可伸缩图片。

第一次听说可伸缩图片可能会感到陌生,在程序中它主要是针对不同的显示需求。例如,你的程序可能希望为按钮 供一个背景图片。按钮内部有一个很大的文本,按钮本身也很宽。这对这样的情况,有两种方法为按钮供背景图片:

毫无疑问,第二种方法非常合适。那么伸缩图片是什么呢?伸缩图片是将一个图片分为虚拟的两部分:

图4-1 一个可以作为伸缩图片候选的图片

你可能会问为什么?如图 4-2,

图4-2 中间的各个切片图片内容都是相同的

我以相同的大小将图片切为许多切片,这些切片内容是一样的。仔细看一下,如果矩形区域内我只留下 1pixel 宽,高度跟图片一样,那么我还能用这个图片为一个按钮构建一个背景图片吗?答案是可以,并且很简单。在这里,图片保持着相同的跨度,在中间,我们可以只留下 1像素的宽度即可.如图 图4-3 所示——对图片操作过后的结果。

图4-3 利用 1 个像素的宽度当做可伸缩区域

我们如何告诉 iOS SDK 哪部份图片保存不变,而哪部份图片有可以进行伸缩呢?事实证明,iOS SDK已经对此做好了准备。首先,利用本章学到的内容——使用 UIImage APIs 将图片加载到内存。然后使用 UIImage 的实例对象的实例方法 resizableImgaeWithCapInsets:对图片进行可伸缩区域的设置。这个方法的参数类似UIEdgeInsets,定义方法属下:

typedef struct UIEdgeInsets
{
    CGFloat top, left, bottom, right;
} UIEdgeInsets

Edge insets 运允许我们创建九图。九图是一个图片,由九不分组成:

图4-4 九图的组成

将一个图片存储为九图的目的是允许开发者可以任意的对图片进行垂直和水平伸缩。当开发者要对图片大小进行调整时,九图中的有些部分保持不变,有些则需要调整。保持不变的部分是边角,边角的尺寸不会改变。而其它部分则会进行大小调整:

Inset 中的上下左右值代表你不想要伸缩的区域。例如,如果指定左的值为 10,上的值为 11,有的值为 10,下的值为 5,这会告诉 iOS 在图片距离左边 10 像素地方放置一条垂直线,在距离顶部 11 像素的地方,放置一条水平线。另外一条垂直线在离右边 14 像素的位置,最后一条水平现在距离底部 5 像素的地方。这些线条限定的矩形区域内部是可伸缩的,外部是不可伸缩的。这听起来可能会有点迷惑,不过可以这样想象一下这里有两个矩形区域:一个是图片矩形,另外一个则是在这个图片内绘制的另外一个矩形。内部矩形区域是可伸缩的,而外部矩形区域保持不变。如图 4-5 可以演示一下上面的这些值:

图 4-5 使用 edge insets 定义的可伸缩区域

下面看一个示例,代码如图4-5:

- (void)drawResizableImage
{
    UIImage *img = [[UIImage imageNamed:@"1"] resizableImageWithCapInsets:UIEdgeInsetsMake(5, 10, 8, 5)];
    UIImageView *imgView = [[UIImageView alloc] initWithFrame:CGRectMake(20, 81, 200, 100)];
    imgView.image = img;
    
    [self addSubview:imgView];
}

被拉伸的图片如下:

图4-5 被拉伸的原图

拉伸后结果如图4-6:

图4-6 被拉伸后

可以很明显看出哪里被拉伸。

上一篇 下一篇

猜你喜欢

热点阅读