圖形與動畫(一)--附Demo

最近在看《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 BoldHelvetica 家庭的一個 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)在我們知道了字體名字,我們就可以使用 UIFont 的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”。

圖 1-1 在一個視圖的圖形環(huán)境上繪制的一個隨機(jī)字符串

繪制顏色和字體

- (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 繪制圖像

  • 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-1 一個可以作為伸縮圖片候選的圖片

你可能會問為什么?如圖 4-2,

圖4-2 中間的各個切片圖片內(nèi)容都是相同的

我以相同的大小將圖片切為許多切片,這些切片內(nèi)容是一樣的。仔細(xì)看一下,如果矩形區(qū)域內(nèi)我只留下 1pixel 寬,高度跟圖片一樣,那么我還能用這個圖片為一個按鈕構(gòu)建一個背景圖片嗎?答案是可以,并且很簡單。在這里,圖片保持著相同的跨度,在中間,我們可以只留下 1像素的寬度即可.如圖 圖4-3 所示——對圖片操作過后的結(jié)果。

圖4-3 利用 1 個像素的寬度當(dāng)做可伸縮區(qū)域

我們?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 是九圖的各個部分:
圖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 使用 edge insets 定義的可伸縮區(qū)域

下面看一個示例,代碼如圖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 被拉伸的原圖

拉伸后結(jié)果如圖4-6:

圖4-6 被拉伸后

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,461評論 6 532
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,538評論 3 417
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,423評論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,991評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,761評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,207評論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,268評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,419評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,959評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,782評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,983評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,222評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,653評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,901評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,678評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,978評論 2 374

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,660評論 25 708
  • 問答題47 /72 常見瀏覽器兼容性問題與解決方案? 參考答案 (1)瀏覽器兼容問題一:不同瀏覽器的標(biāo)簽?zāi)J(rèn)的外補(bǔ)...
    _Yfling閱讀 13,776評論 1 92
  • 一、使用UIImage和CGImage處理圖位 可用通過Quartz的圖片對象或原始圖片數(shù)據(jù)來創(chuàng)建UIImage。...
    MD_963閱讀 1,614評論 0 3
  • 20160210 團(tuán)隊智慧一定會大于個人智慧嗎?我第一次思考這個問題的時候,說實話,我是懷疑的。因為在我的大多數(shù)經(jīng)...
    f7d01673dcd6閱讀 6,031評論 0 2
  • 偶遇 一場跨年舞會 美麗精巧的面具 遮不住奔突的靈魂 在光影中 人們用狂歡和過去告別 我站在新舊交替的門口 希望再...
    初見___閱讀 571評論 2 3