[iOS][Mac] Core Graphics - グラデーション

2011年6月28日火曜日 | Published in | 0 コメント

このエントリーをはてなブックマークに追加

CoreGraphics の グラデーションについての覚書き。



Linear Gradient


2つの点を指定してその間でグラデーションを表現する方式。

CGGradientRef() で定義し、CGContextDrawLinearGradient() で描画する。あらかじめ描画したい形(パス)を登録しておく。コードはこんな感じ。
- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();   
    CGContextSaveGState(context);
   
    CGContextAddRect(context, self.frame);
   
    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
    CGFloat components[] = {
        1.0f, 1.0f, 1.0f, 0.5f,     // R, G, B, Alpha
        0.0f, 0.0f, 0.0f, 0.5f
    };
    CGFloat locations[] = { 0.0f, 1.0f };

    size_t count = sizeof(components)/ (sizeof(CGFloat)* 4);
   
    CGRect frame = self.bounds;
    CGPoint startPoint = frame.origin;
    CGPoint endPoint = frame.origin;
    endPoint.y = frame.origin.y + frame.size.height;
   
    CGGradientRef gradientRef =
        CGGradientCreateWithColorComponents(colorSpaceRef, components, locations, count);
   
    CGContextDrawLinearGradient(context,
                                gradientRef,
                                startPoint,
                                endPoint,
                                kCGGradientDrawsAftersEndLocation);
   
    CGGradientRelease(gradientRef);
    CGColorSpaceRelease(colorSpaceRef);
   
    CGContextRestoreGState(context);
}

startPoint, endPoint はグラデーションの開始位置、終了位置を決める。例えば左上から左下にした場合はこう。

左上から右上。

左上から右下。

例では2色間のグラデーションを使っているが複数色間のグラデーションを作ることもできる。その場合は上記コードの components に色情報を増やす。
CGFloat components[] = {
        1.0f, 1.0f, 1.0f, 0.5f,
        1.0f, 0.0f, 0.0f, 0.5f,
                  :
        0.0f, 0.0f, 0.0f, 0.5f
    };
components を増やした場合は locations の要素もそれに合わせて増やす。locations は各色の割合を表していて 0〜1 の数値を取る。例えば
CGFloat locations[] = { 0.0f, 0.2f, 1.0f };
とすると全体の描画対象の 0〜20% が1色目と2色目のグラデーション、20%〜100%の領域が2色目と3色目のグラデーションになる。等間隔にしたい場合は CGGradientCreateWithColorComponents() の locations に NULLを渡すこともできる。


Radial Gradient


放射状のグラデーションを表現する。

こちらも2点を指定しその間のグラデーションを表現するが、Linearと違うのは各点から放射状にグラデーションがかかること。コードはこんな感じ。
- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();   
    CGContextSaveGState(context);
   
    CGContextAddEllipseInRect(context, self.frame);
   
    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
    CGFloat components[] = {
        1.0f, 1.0f, 1.0f, 1.0f,
        0.5f, 0.5f, 0.5f, 1.0f,
        0.25f, 0.25f, 0.25f, 1.0f,
    };   
    CGFloat locations[] = { 0.0, 0.5, 1.0 };
   
    size_t count = sizeof(components)/ (sizeof(CGFloat)* 4);
    CGGradientRef gradientRef =
        CGGradientCreateWithColorComponents(colorSpaceRef, components, locations, count);
       
    CGRect frame = self.bounds;
    CGFloat radius = frame.size.height/2.0*0.8;

    CGPoint startCenter = frame.origin;
    startCenter.x += frame.size.width/2.0;
    startCenter.y += frame.size.height/2.0;
    CGPoint endCenter = startCenter;
   
    CGFloat startRadius = 0;
    CGFloat endRadius = radius;
   
    CGContextDrawRadialGradient(context,
                                gradientRef,
                                startCenter,
                                startRadius,
                                endCenter,
                                endRadius,
                                kCGGradientDrawsAfterEndLocation);
   
    CGGradientRelease(gradientRef);
    CGColorSpaceRelease(colorSpaceRef);
   
    CGContextRestoreGState(context);
}
CGGradientRef の作り方は Linear と同じ。ポイントは2つの点とそれらの点を中心として描かれる円の半径を指定するところ。例では startCenter と endCenter を同じにしているので中心から放射状にグラデーションがかかっているように見える。startRadius は 0。

次は startCenter を左上に動かした例。
擬似 3D ぽい画像になる(見かたを変えると遠くでライトを光らせているようにも見える)。


サンプル


GitHub からどうぞ。

GradientSample at 2011-06-28 from xcatsan/iOS-Sample-Code - GitHub

なお背景には標準で付いていた "Scroll View Textured Background Color" を使っている(これ自体を描画しているわけではない)



参考情報


Gradients
Gradientsの解説はマニュアルが詳しい。


A-Liaison BLOG: CGGradientを用いてUITableViewCellを描画し、テーブルをカッコよく見せる方法
UIColor 元にグラデーションを作るアイディアが面白い。

(旧) Cocoaの日々: NSGradiation
Mac OS X ならこっちも使える。

Responses

Leave a Response

人気の投稿(過去 30日間)