-
-
個性化繪製table view的header!
這是結合實例代碼講解Core Graphics API的教程系列的第二部分內容!
在第一部分教程中,我們通過製作美觀的table view cell背景,講解了如何繪製線條,矩形和顏色漸變效果。
在這篇教程中,我們將繼續個性化table view的header。同時,我們將鞏固一些已經學會的知識,進一步學習陰影和光澤效果!
如果你還沒有上篇教程的例子代碼,可以在這裏下載。
開始
個性化我們的table view的下一步是美化table view 的header。開始前,讓我們先按照之前的方式做好初步設置 – 製作一個紅色的view,設置爲header的view。
確保”Groups & Files”下面的”Classes”分組被選中,前往菜單的“FileNew File…”,選擇 iOSCocoa Touch Class, Objective-C class,確保”Subclass of UIView”選項被選中,然後點擊下一步。命名文件爲 ”CustomHeader.m”,確保 ”Also create CustomHeader.h”被選中,然後點擊 ”Finish”。
切換到CustomHeader.m文件,取消drawRect方法的註釋,用以下代碼替換掉原來的內容:
CGContextRef context = UIGraphicsGetCurrentContext();
CGColorRef redColor = [UIColor colorWithRed:1.0 green:0.0
blue:0.0 alpha:1.0].CGColor;
CGContextSetFillColorWithColor(context, redColor);
CGContextFillRect(context, self.bounds);
|
你應該已經對這些操作很熟悉了,因爲我們之前做過!
現在讓我們設置它爲header的view吧。切換到RootViewController.m文件,根據以下代碼做修改:
// In import section
#import "CustomHeader.h"
// Add new methods
- (UIView *) tableView:(UITableView *)tableView
viewForHeaderInSection:(NSInteger)section {
CustomHeader *header = [[[CustomHeader alloc] init] autorelease];
return header;
}
-(CGFloat) tableView:(UITableView *)tableView
heightForHeaderInSection:(NSInteger)section {
return 50;
}
|
實現viewForHeaderInSection方法就可以替換掉table view的header view。我們還需要實現heightForHeaderInSection方法來讓table view知道header的高度。
編譯運行工程,如果一切運行正常,你將看到以下畫面:
很好 – 現在我們來用漂亮的view去填充這個區域吧!
目標
先刷新下內存空間。以下是我們想要的header view的放大效果:
注意以下對上述效果的描述:
-
藍色區域是從淺藍色到深藍色的漸變。
-
藍色區域的頂部有光澤的效果。
-
在藍色區域的邊界處有深藍色的邊。
-
在方框的底部有微小的陰影效果。
-
頁面的頂部區域已經繪製好了,引入到了頂部cell。
-
Table view controller需要爲每個view設置顏色和label標籤。
以上內容是對上篇教程和Custom
UIViews教程的很好複習,但是我們會在接下來講解一些新內容!
開始動手
首先要做的是一些基本設置。我們需要讓table view可以設置header的顏色和顯示一些文本,然後設置一些矩形以便我們在上面繪製(比如header bar還有頁面的下拉效果)。
現在我們開始動手。根據以下代碼對CustomHeader.h文件進行修改:
// Inside @interface
UILabel *_titleLabel;
UIColor *_lightColor;
UIColor *_darkColor;
CGRect _coloredBoxRect;
CGRect _paperRect;
// After @interface
@property (retain) UILabel *titleLabel;
@property (retain) UIColor *lightColor;
@property (retain) UIColor *darkColor;
|
然後根據以下代碼內容對CustomHeader.m文件進行修改:
// In import section
#import "Common.h"
// After @implementation
@synthesize titleLabel = _titleLabel;
@synthesize lightColor = _lightColor;
@synthesize darkColor = _darkColor;
// Add new methods
- (id)init {
if ((self = [super init])) {
self.backgroundColor = [UIColor clearColor];
self.opaque = NO;
self.titleLabel = [[[UILabel alloc] init] autorelease];
_titleLabel.textAlignment = UITextAlignmentCenter;
_titleLabel.opaque = NO;
_titleLabel.backgroundColor = [UIColor clearColor];
_titleLabel.font = [UIFont boldSystemFontOfSize:20.0];
_titleLabel.textColor = [UIColor whiteColor];
_titleLabel.shadowColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.5];
_titleLabel.shadowOffset = CGSizeMake(0, -1);
[self addSubview:_titleLabel];
self.lightColor = [UIColor colorWithRed:105.0f/255.0f green:179.0f/255.0f
blue:216.0f/255.0f alpha:1.0];
self.darkColor = [UIColor colorWithRed:21.0/255.0 green:92.0/255.0
blue:136.0/255.0 alpha:1.0];
}
return self;
}
-(void) layoutSubviews {
CGFloat coloredBoxMargin = 6.0;
CGFloat coloredBoxHeight = 40.0;
_coloredBoxRect = CGRectMake(coloredBoxMargin,
coloredBoxMargin,
self.bounds.size.width-coloredBoxMargin*2,
coloredBoxHeight);
CGFloat paperMargin = 9.0;
_paperRect = CGRectMake(paperMargin,
CGRectGetMaxY(_coloredBoxRect),
self.bounds.size.width-paperMargin*2,
self.bounds.size.height-CGRectGetMaxY(_coloredBoxRect));
_titleLabel.frame = _coloredBoxRect;
}
// Replace drawRect with the following
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGColorRef redColor = [UIColor colorWithRed:1.0 green:0.0
blue:0.0 alpha:1.0].CGColor;
CGColorRef greenColor = [UIColor colorWithRed:0.0 green:1.0
blue:0.0 alpha:1.0].CGColor;
CGContextSetFillColorWithColor(context, redColor);
CGContextFillRect(context, _coloredBoxRect);
CGContextSetFillColorWithColor(context, greenColor);
CGContextFillRect(context, _paperRect);
}
// Inside dealloc
[_titleLabel release];
_titleLabel = nil;
[_lightColor release];
_lightColor = nil;
[_darkColor release];
_darkColor = nil;
|
在之前的教程基礎上,上面的內容你都應該覺得很熟悉。我們快速過一遍。
在init方法中,我們用一些基本的數值建立了label標籤。注意到我們給文本的頂部設置了一塊微小的陰影,讓它看起來像鋸齒狀。原因:如果光線在頂部,然後有些鋸齒效果,就會在上部區域有陰影了。
我們也要確保視圖是透明的,因爲我們想讓背景可以露出來一點。
當我們的view改變大小時就會調用layoutSubviews方法。這裏是我們要添加代碼去計算需要繪製顏色方框的矩形尺寸,以及繪製頁面位置的地方。每一項都是很直接的計算過程。
最後,我們在drawRect函數中使用不同的顏色去填充每一個方框區域,以確保我們計算正確。
使用以下代碼對RootViewController.m文件進行修改:
// Inside tableView:viewForHeaderInSection, before return
header.titleLabel.text = [self tableView:tableView titleForHeaderInSection:section];
|
編譯運行程序,然後如果運作正常,你會看到以下畫面:
我們又離目標更進一步了!正如你看到的,用顏色填充矩形是一個方便的調試工具!
繪製陰影
讓我們從基礎開始講解繪製的原理吧。我們會先繪製一個頁面,然後是陰影,最後給方框盒子填充顏色。
繪製頁面區域很簡單 – 我們只要給方框填充上白色。
但是我們怎麼去繪製陰影?好的,在Core Graphics裏面,繪製陰影,你只需要調用一個函數去啓用陰影繪製功能,然後繪製軌跡。根據你設定好的參數,陰影將被繪製在軌跡下面 – 這裏不用管軌跡的形狀!
讓我們看看這是怎麼工作的。使用以下代碼,替換掉drawRect的方法:
CGContextRef context = UIGraphicsGetCurrentContext();
CGColorRef whiteColor = [UIColor colorWithRed:1.0 green:1.0
blue:1.0 alpha:1.0].CGColor;
CGColorRef lightColor = _lightColor.CGColor;
CGColorRef darkColor = _darkColor.CGColor;
CGColorRef shadowColor = [UIColor colorWithRed:0.2 green:0.2
blue:0.2 alpha:0.5].CGColor;
CGContextSetFillColorWithColor(context, whiteColor);
CGContextFillRect(context, _paperRect);
CGContextSaveGState(context);
CGContextSetShadowWithColor(context, CGSizeMake(0, 2), 3.0, shadowColor);
CGContextSetFillColorWithColor(context, lightColor);
CGContextFillRect(context, _coloredBoxRect);
CGContextRestoreGState(context);
|
完成顏色和頁面方框的繪製(你現在應該能夠理解了)後,我們調用 CGContextSetShadowWithColor函數去進行陰影繪製。
第一個參數是陰影繪製時的offset(偏移量)值。這裏我們在當前的軌跡下面繪製了兩個點。
接下來的參數是陰影的blur(模糊度)值。o的值將會是顏色較深的邊,值越大,邊的顏色會越柔和。我們把值設定爲3,使邊的顏色變得柔和。
最後我們來設定陰影的顏色。注意到我們使用了灰色,它的alpha值爲0.5(半透明),這讓陰影變得更加逼真。
建立好陰影后,我們使用淺顏色來填充上色了的盒子方框。給軌跡填充顏色的操作,會體現在陰影上面。
最後的修改 – 既然我們使用了提供給我們的顏色,那現在修改RootViewController.m文件去改變section 1的顏色:
// Inside tableView:viewForHeaderInSection, before return statement
if (section == 1) {
header.lightColor = [UIColor colorWithRed:147.0/255.0 green:105.0/255.0
blue:216.0/255.0 alpha:1.0];
header.darkColor = [UIColor colorWithRed:72.0/255.0 green:22.0/255.0
blue:137.0/255.0 alpha:1.0];
}
|
編譯運行工程,你將看到以下畫面:
Wow – 看起來已經相當漂亮了!現在讓我們用顏色漸變,光澤效果對它去做進一步的修飾吧。
添加光澤效果
在Core Graphics中添加光澤效果到按鈕上面,操作會相當複雜 – 如果你感受到了難度,看看 Matt
Gallagher和 Michael
Heyeck在這方面的突出貢獻吧。
以我的看法,你可以通過使用一個漸變的alpha mask, 獲得一種相當美觀和接近的光澤效果,這會更加容易理解和編寫代碼,我們接下來會實現它。
下面的代碼我們接下來還會用到,現在把代碼添加到”Common.h”文件中:
void drawGlossAndGradient(CGContextRef context, CGRect rect, CGColorRef startColor,
CGColorRef endColor);
|
添加以下代碼到Common.m文件中:
void drawGlossAndGradient(CGContextRef context, CGRect rect, CGColorRef startColor,
CGColorRef endColor) {
drawLinearGradient(context, rect, startColor, endColor);
CGColorRef glossColor1 = [UIColor colorWithRed:1.0 green:1.0
blue:1.0 alpha:0.35].CGColor;
CGColorRef glossColor2 = [UIColor colorWithRed:1.0 green:1.0
blue:1.0 alpha:0.1].CGColor;
CGRect topHalf = CGRectMake(rect.origin.x, rect.origin.y,
rect.size.width, rect.size.height/2);
drawLinearGradient(context, topHalf, glossColor1, glossColor2);
}
|
好的,以上的代碼負責在矩形上實現顏色漸變效果,然後添加光澤效果到頂部中間。
|
繪製漸變效果,我們調用之前寫好的代碼。
然後繪製光澤效果,我們只需要在它上面繪製另一層漸變效果,從相當透明(0.35alpha值的白色)到非常透明(0.1alpha值的白色)。
相當簡單吧?我們把代碼添加進去看下效果。回到CustomHeader.m文件,然後添加以下代碼到drawRect:函數的底部:
drawGlossAndGradient(context, _coloredBoxRect, lightColor, darkColor);
// Draw stroke
CGContextSetStrokeColorWithColor(context, darkColor);
CGContextSetLineWidth(context, 1.0);
CGContextStrokeRect(context, rectFor1PxStroke(_coloredBoxRect));
|
這裏我們使用新的程序代碼,然後在方框周圍繪製一個1像素點的深色筆畫,正如在之前教程中學到的那樣。編譯運行程序,然後查看運行結果:
我想現在已經相當不錯了,你覺得呢?
現在還可以做什麼?
這個是本教程的工程代碼,你可以到這裏下載。
到現在你應該很渴望去用Core Graphics繪製你自己的東西了 – 想想看你已經能做多少了!
還有個好消息 – 更多的內容將會在本教程系列中出現!在下一篇教程中,我們將用footer去完善好這個很酷的table
view,你將在這個過程中學到如何使用Core Graphics去繪製弧線,並且做些收尾工作!