最近在看《iOS 6 Programming Cookbook》的翻譯版,它由DevDiv論壇的網(wǎng)友翻譯,原文地址:點擊跳轉(zhuǎn)。由于下載的pdf都有水印,并且排版不是很好,特別是代碼排版,基本不能看,所以這里就整理了一下,方便再次查看。另外把里面提到的點寫了一個demo,由于里面一些代碼現(xiàn)在已經(jīng)廢棄,所以demo中都是用的新api,下載地址在這里:圖形與動畫Demo。
1.1 枚舉和加載字體
字體是在圖形用戶界面上顯示文字的基礎(chǔ)。UIKIt 框架為程序員提供了便于枚舉,加載,和使用字體的高級別 API。字體被封裝于 Cocoa Touch 中的 UIFont 類中。每個 iOS 設(shè) 備自身都有內(nèi)建的系統(tǒng)字體。字體被組織到 family
中,每個 family
中包含 face
。比如,Helvetica
是一個字體 family,Helvetica Bold
是 Helvetica
家庭的一個 face
。為了能加載字體,你必須知道字體的face
(也就是他的名字)--- 要想知道它的face
,就必須知道 family
,所以,我們首先要枚舉出安裝到設(shè)備上的所有的字體family
,使用 UIFont
類的 familyNames
類方法:
- (void) enumerateFonts
{
for (NSString *familyName in [UIFont familyNames])
{
NSLog(@"Font Family = %@", familyName);
}
}
在 iOS 模擬器上運行這個程序,我得到了類似下面的結(jié)果:
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
內(nèi)部枚舉字體名字。我們使用UIFont
類的 fontNamesForFamilyName:
類方法,可以得到以 family
名字作為參數(shù)得到的字體名字?jǐn)?shù)組:
- (void) enumerateFonts
{
for (NSString *familyName in [UIFont familyNames])
{
NSLog(@"Font Family = %@", familyName);
for (NSString *fontName in [UIFont fontNamesForFamilyName:familyName])
{
NSLog(@"\t%@", fontName);
}
}
}
在 iOS 設(shè)備上運行上面的代碼,我們得到如下結(jié)果:
...
Font Family = Geeza Pro
GeezaPro
GeezaPro-Bold
Font Family = Helvetica Neue
HelveticaNeue-Italic
HelveticaNeue-Bold
HelveticaNeue-BoldItalic
HelveticaNeue
...
你可以看到,Helvetica Neue
是字體 family
,HelveticaNeue-Bold
是這個family
中的一個字體名字。現(xiàn)在我們知道了字體名字,我們就可以使用 UIFon
t 的fontWithName:size:
類方法 將字體加載到 UIFont
類型對象中:
UIFont *helveticaBold = [UIFont fontWithName:@"HelveticaNeue-Bold" size:12.0f];
如果 UIFont
類的 fontWithName:size:
類方法的返回結(jié)果為 nil
,指定的字體名字不能被找到。首先枚舉出所有的字體 family
和該 family
中的所有字體名字,可以確 保你提供的字體名字在系統(tǒng)中可用。
你也可以使用 UIFont
類的 systemFontOfSize:
類方法(譯者:原文是 instance method,但 實際上是類方法)(或者它的粗體方法,boldSystemFontOfSize:
)從你代碼運行的設(shè)備上加 載系統(tǒng)字體,不管這些字體是什么。iOS 設(shè)備的默認(rèn)系統(tǒng)字體是 Helvetica
。
1.2 繪制文本
-
使用 NSString 的
drawAtPoint:withAttributes:
方法繪制文字
drawRect:方法是我們要進(jìn)行繪制的地方,如前面所提到的那樣。在此,我們可以開始加載字體,然后在屏幕上 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: 類方法
加載圖片(如果加載成功還會緩存圖像)。參這個方法的參數(shù)是 bundle 中的圖像名字,比如 Tree Texture.png。
imageWithData: 類方法
從 NSData
對象實例中包裹的數(shù)據(jù)中加載圖片,NSData 對象是此方法的參數(shù)傳入的。
initWithContentsOfFile:實例方法(用于初始化)
使用指定參數(shù)作為路徑來加載一個圖像,并用來初始化圖像對象。路徑應(yīng)該是在 bundle 中圖像的完整路徑
initWithData:實例方法(用于初始化)
使用 NSData
類型的指定參數(shù)來初始化圖像。這個數(shù)據(jù)應(yīng)該屬于一個有效圖像。
- 在圖形環(huán)境上繪制
UIImage
類型的圖片的兩種最簡單的方法是:
drawAtPoint:UIImage 的實例方法
將圖片以原始尺寸繪制到指定坐標(biāo)點。使用 CGPointMake
函數(shù)來構(gòu)造坐標(biāo)點。
drawInRect:UIImage 的實例方法
在指定的矩形空間繪制圖片,要構(gòu)造這個矩形空間,請使用 CGRectMake
函數(shù)。
兩個繪制圖片的方法與繪制文字方法類似,就不貼代碼了,可以在demo里面查看。
1.4 構(gòu)造可伸縮圖片
使用 UIImage
類的實例方法 resizableImageWithCapInsets:
創(chuàng)建一個可伸縮圖片。
第一次聽說可伸縮圖片可能會感到陌生,在程序中它主要是針對不同的顯示需求。例如,你的程序可能希望為按鈕 供一個背景圖片。按鈕內(nèi)部有一個很大的文本,按鈕本身也很寬。這對這樣的情況,有兩種方法為按鈕供背景圖片:
為不同尺寸的按鈕各自創(chuàng)建一個圖片。這將會增加 bundle 的大小,并消耗更多的內(nèi)存,你也需要做更多的工作。另外,如果按鈕內(nèi)的文本發(fā)生了任何改變,你都需要為按鈕 供一個適當(dāng)?shù)膱D片。
創(chuàng)建一個可伸縮圖片,程序中所有的按鈕都可以使用這個圖片。
毫無疑問,第二種方法非常合適。那么伸縮圖片是什么呢?伸縮圖片是將一個圖片分為虛擬的兩部分:
- 不需要被拉伸的部分
- 被拉伸以適應(yīng)任何尺寸的部分
如圖 4-1 所示,我為一個按鈕創(chuàng)建了一個圖片。這個圖片具有漸變的效果。我在圖片上畫的這個矩形區(qū)域內(nèi)容可以將其從圖片中裁減出來。
你可能會問為什么?如圖 4-2,
我以相同的大小將圖片切為許多切片,這些切片內(nèi)容是一樣的。仔細(xì)看一下,如果矩形區(qū)域內(nèi)我只留下 1pixel 寬,高度跟圖片一樣,那么我還能用這個圖片為一個按鈕構(gòu)建一個背景圖片嗎?答案是可以,并且很簡單。在這里,圖片保持著相同的跨度,在中間,我們可以只留下 1像素的寬度即可.如圖 圖4-3 所示——對圖片操作過后的結(jié)果。
我們?nèi)绾胃嬖V iOS SDK 哪部份圖片保存不變,而哪部份圖片有可以進(jìn)行伸縮呢?事實證明,iOS SDK已經(jīng)對此做好了準(zhǔn)備。首先,利用本章學(xué)到的內(nèi)容——使用 UIImage APIs
將圖片加載到內(nèi)存。然后使用 UIImage
的實例對象的實例方法 resizableImgaeWithCapInsets:
對圖片進(jìn)行可伸縮區(qū)域的設(shè)置。這個方法的參數(shù)類似UIEdgeInsets
,定義方法屬下:
typedef struct UIEdgeInsets
{
CGFloat top, left, bottom, right;
} UIEdgeInsets
Edge insets 運允許我們創(chuàng)建九圖。九圖是一個圖片,由九不分組成:
- 左上(Upper left corner)
- 上(Top edge)
- 右上(Upper right corner)
- 右(Right edge)
- 右下(Lower right corner)
- 下(Bottom edge)
- 左下(Lower left corner)
- 左(Left edge)
- 中心(Center)
圖 4-4 是九圖的各個部分:
將一個圖片存儲為九圖的目的是允許開發(fā)者可以任意的對圖片進(jìn)行垂直和水平伸縮。當(dāng)開發(fā)者要對圖片大小進(jìn)行調(diào)整時,九圖中的有些部分保持不變,有些則需要調(diào)整。保持不變的部分是邊角,邊角的尺寸不會改變。而其它部分則會進(jìn)行大小調(diào)整:
上(Top edge)
圖片中的這部分寬度會進(jìn)行調(diào)整,而高度不會。右(Right edge)
圖片中的這部分高度會進(jìn)行調(diào)整,而寬度不會。下(Bottom edge)
跟 Top edge 部分一樣,圖片中的這部分寬度會進(jìn)行調(diào)整,而高度不會。左(Left edge)
跟 Bottom edge 部分一樣,圖片中的這部分寬度會進(jìn)行調(diào)整,而高度不會。中心(Center)
圖片中的這部分會進(jìn)行寬和高的調(diào)整。
Inset 中的上下左右值代表你不想要伸縮的區(qū)域。例如,如果指定左的值為 10,上的值為 11,有的值為 10,下的值為 5,這會告訴 iOS 在圖片距離左邊 10 像素地方放置一條垂直線,在距離頂部 11 像素的地方,放置一條水平線。另外一條垂直線在離右邊 14 像素的位置,最后一條水平現(xiàn)在距離底部 5 像素的地方。這些線條限定的矩形區(qū)域內(nèi)部是可伸縮的,外部是不可伸縮的。這聽起來可能會有點迷惑,不過可以這樣想象一下這里有兩個矩形區(qū)域:一個是圖片矩形,另外一個則是在這個圖片內(nèi)繪制的另外一個矩形。內(nèi)部矩形區(qū)域是可伸縮的,而外部矩形區(qū)域保持不變。如圖 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];
}
被拉伸的圖片如下:
拉伸后結(jié)果如圖4-6:
可以很明顯看出哪里被拉伸。