最近在看《iOS 6 Programming Cookbook》的翻译版,它由DevDiv论坛的网友翻译,原文地址:点击跳转。由于下载的pdf都有水印,并且排版不是很好,特别是代码排版,基本不能看,所以这里就整理了一下,方便再次查看。另外把里面提到的点写了一个demo,由于里面一些代码现在已经废弃,所以demo中都是用的新api,下载地址在这里:图形与动画Demo。
1.1 枚举和加载字体
字体是在图形用户界面上显示文字的基础。UIKIt 框架为程序员提供了便于枚举,加载,和使用字体的高级别 API。字体被封装于 Cocoa Touch 中的 UIFont 类中。每个 iOS 设 备自身都有内建的系统字体。字体被组织到 family
中,每个 family
中包含 face
。比如,Helvetica
是一个字体 family,Helvetica Bold
是 Helvetica
家庭的一个 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
中的一个字体名字。现在我们知道了字体名字,我们就可以使用 UIFon
t 的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 绘制文本
-
使用 NSString 的
drawAtPoint:withAttributes:
方法绘制文字
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”。
绘制颜色和字体
- (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}];
}
效果如下图所示:
获取颜色的组成
/* 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 绘制图像
- iOS 中的一些比较重要的方法
imageNamed: 类方法
加载图片(如果加载成功还会缓存图像)。参这个方法的参数是 bundle 中的图像名字,比如 Tree Texture.png。
imageWithData: 类方法
从 NSData
对象实例中包裹的数据中加载图片,NSData 对象是此方法的参数传入的。
initWithContentsOfFile:实例方法(用于初始化)
使用指定参数作为路径来加载一个图像,并用来初始化图像对象。路径应该是在 bundle 中图像的完整路径
initWithData:实例方法(用于初始化)
使用 NSData
类型的指定参数来初始化图像。这个数据应该属于一个有效图像。
- 在图形环境上绘制
UIImage
类型的图片的两种最简单的方法是:
drawAtPoint:UIImage 的实例方法
将图片以原始尺寸绘制到指定坐标点。使用 CGPointMake
函数来构造坐标点。
drawInRect:UIImage 的实例方法
在指定的矩形空间绘制图片,要构造这个矩形空间,请使用 CGRectMake
函数。
两个绘制图片的方法与绘制文字方法类似,就不贴代码了,可以在demo里面查看。
1.4 构造可伸缩图片
使用 UIImage
类的实例方法 resizableImageWithCapInsets:
创建一个可伸缩图片。
第一次听说可伸缩图片可能会感到陌生,在程序中它主要是针对不同的显示需求。例如,你的程序可能希望为按钮 供一个背景图片。按钮内部有一个很大的文本,按钮本身也很宽。这对这样的情况,有两种方法为按钮供背景图片:
为不同尺寸的按钮各自创建一个图片。这将会增加 bundle 的大小,并消耗更多的内存,你也需要做更多的工作。另外,如果按钮内的文本发生了任何改变,你都需要为按钮 供一个适当的图片。
创建一个可伸缩图片,程序中所有的按钮都可以使用这个图片。
毫无疑问,第二种方法非常合适。那么伸缩图片是什么呢?伸缩图片是将一个图片分为虚拟的两部分:
- 不需要被拉伸的部分
- 被拉伸以适应任何尺寸的部分
如图 4-1 所示,我为一个按钮创建了一个图片。这个图片具有渐变的效果。我在图片上画的这个矩形区域内容可以将其从图片中裁减出来。
你可能会问为什么?如图 4-2,
我以相同的大小将图片切为许多切片,这些切片内容是一样的。仔细看一下,如果矩形区域内我只留下 1pixel 宽,高度跟图片一样,那么我还能用这个图片为一个按钮构建一个背景图片吗?答案是可以,并且很简单。在这里,图片保持着相同的跨度,在中间,我们可以只留下 1像素的宽度即可.如图 图4-3 所示——对图片操作过后的结果。
我们如何告诉 iOS SDK 哪部份图片保存不变,而哪部份图片有可以进行伸缩呢?事实证明,iOS SDK已经对此做好了准备。首先,利用本章学到的内容——使用 UIImage APIs
将图片加载到内存。然后使用 UIImage
的实例对象的实例方法 resizableImgaeWithCapInsets:
对图片进行可伸缩区域的设置。这个方法的参数类似UIEdgeInsets
,定义方法属下:
typedef struct UIEdgeInsets
{
CGFloat top, left, bottom, right;
} UIEdgeInsets
Edge insets 运允许我们创建九图。九图是一个图片,由九不分组成:
- 左上(Upper left corner)
- 上(Top edge)
- 右上(Upper right corner)
- 右(Right edge)
- 右下(Lower right corner)
- 下(Bottom edge)
- 左下(Lower left corner)
- 左(Left edge)
- 中心(Center)
图 4-4 是九图的各个部分:
将一个图片存储为九图的目的是允许开发者可以任意的对图片进行垂直和水平伸缩。当开发者要对图片大小进行调整时,九图中的有些部分保持不变,有些则需要调整。保持不变的部分是边角,边角的尺寸不会改变。而其它部分则会进行大小调整:
上(Top edge)
图片中的这部分宽度会进行调整,而高度不会。右(Right edge)
图片中的这部分高度会进行调整,而宽度不会。下(Bottom edge)
跟 Top edge 部分一样,图片中的这部分宽度会进行调整,而高度不会。左(Left edge)
跟 Bottom edge 部分一样,图片中的这部分宽度会进行调整,而高度不会。中心(Center)
图片中的这部分会进行宽和高的调整。
Inset 中的上下左右值代表你不想要伸缩的区域。例如,如果指定左的值为 10,上的值为 11,有的值为 10,下的值为 5,这会告诉 iOS 在图片距离左边 10 像素地方放置一条垂直线,在距离顶部 11 像素的地方,放置一条水平线。另外一条垂直线在离右边 14 像素的位置,最后一条水平现在距离底部 5 像素的地方。这些线条限定的矩形区域内部是可伸缩的,外部是不可伸缩的。这听起来可能会有点迷惑,不过可以这样想象一下这里有两个矩形区域:一个是图片矩形,另外一个则是在这个图片内绘制的另外一个矩形。内部矩形区域是可伸缩的,而外部矩形区域保持不变。如图 4-5 可以演示一下上面的这些值:
下面看一个示例,代码如图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-6:
可以很明显看出哪里被拉伸。