Core Graphics 101: 阴影和光泽效果

Custom draw the header of this table!
个性化绘制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的高度。

编译运行工程,如果一切运行正常,你将看到以下画面:

Placeholders for Custom Header

很好 – 现在我们来用漂亮的view去填充这个区域吧!

目标

先刷新下内存空间。以下是我们想要的header view的放大效果:

Zoomed in view of Header

注意以下对上述效果的描述:

  • 蓝色区域是从浅蓝色到深蓝色的渐变。
  • 蓝色区域的顶部有光泽的效果。
  • 在蓝色区域的边界处有深蓝色的边。
  • 在方框的底部有微小的阴影效果。
  • 页面的顶部区域已经绘制好了,引入到了顶部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];

编译运行程序,然后如果运作正常,你会看到以下画面:
Header colored with subrects to draw

我们又离目标更进一步了!正如你看到的,用颜色填充矩形是一个方便的调试工具!

绘制阴影

让我们从基础开始讲解绘制的原理吧。我们会先绘制一个页面,然后是阴影,最后给方框盒子填充颜色。

绘制页面区域很简单 – 我们只要给方框填充上白色。

但是我们怎么去绘制阴影?好的,在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];
}

编译运行工程,你将看到以下画面:
Headers with Shadow

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像素点的深色笔画,正如在之前教程中学到的那样。编译运行程序,然后查看运行结果:
Headers with Gloss

我想现在已经相当不错了,你觉得呢?

现在还可以做什么?

这个是本教程的工程代码,你可以到这里下载

到现在你应该很渴望去用Core Graphics绘制你自己的东西了 – 想想看你已经能做多少了!

还有个好消息 – 更多的内容将会在本教程系列中出现!在下一篇教程中,我们将用footer去完善好这个很酷的table view,你将在这个过程中学到如何使用Core Graphics去绘制弧线,并且做些收尾工作!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值