UIView をグラデーションで塗りつぶす : Objective-C プログラミング

PROGRAM


UIView をグラデーションで塗りつぶす

UIView の背景をグラデーションで塗りつぶしたい場合について考えます。

たとえば UIView の派生クラスを用意して、そのクラスに UIColor 型の backgroundColor2 というプロパティを用意して、backgroundColor から backgroundColor2 までの 2 色で UIView を右下方向にグラデーションで塗りつぶすとします。

このとき、ヘッダーファイルは次のような感じにしてみます。

EzGradientView.h

#import <UIKit/UIkit.h>

 

@interface EzGradientView : UIView

{

@private

// グラデーション用の色を保持します。もう一つの色は UIView の backgroundColor を使用します。

UIColor* _backgroundColor2;

}

 

@property (nonatomic,copy) UIColor* backgroundColor2;

 

@end

そして実装ファイルでは、上記のプロパティを実装するのと併せて、UIView の drawRect: メソッドをオーバーライドして、グラデーションを描画するようにしてみます。

EzGradientView.m

#import "EzGradientView.h"

 

#implementation EzGradientView

 

- (void)dealloc

{

self.backgroundColor2 = nil;

 

[super dealloc];

}

 

// グラデーション用の色を取得します。

- (UIColor*)backgroundColor2

{

return _backgroundColor2;

}

 

// グラデーション用の色を設定します。

- (void)setBackgroundColor2:(UIColor*)backgroundColor2

{

// 既存の色をリリースします。

[_backgroundColor2 release];

 

// 新しい色を、引数に渡された色をコピーして設定します。

_backgroundColor2 = [[UIColor colorWithCGColor:backgroundColor2.CGColor] retain];

 

// 新しい色での再描画を要求します。

[self setNeedsDisplay];

}

 

// ビューの描画の際に呼び出される drawRect: メソッドをオーバーライドします。

- (void)drawRect:(CGRect)rect

{

CGContextRef context;

CGColorSpaceRef colorspace;

CGGradientRef gradient;

 

CGPoint startPoint;

CGPoint endPoint;

 

// グラデーションの色を指定する地点を、ここでは 2 つ用意します。

CGFloat locations[2] = {0.0, 1.0};

 

// 描画するキャンバスの情報を取得します。

context = UIGraphicsGetCurrentContext();

colorspace = CGColorSpaceCreateDeviceRGB();

 

// グラデーションの色(今回は 2 地点分)を CGColorRef を格納した CFArrayRef 配列で用意します。

CGColorRef colors[2];

CFArrayRef colors_buffer;

 

colors[0] = self.backgroundColor.CGColor;

colors[1] = self.backgroundColor2.CGColor;

 

colors_buffer = CFArrayCreate(kCFAllocatorDefault, (const void**)colors, 2, &kCFTypeArrayCallBacks);

 

// グラデーションの描画に必要な情報を揃えます。

// 描画の開始地点と終了地点は、ここではそれぞれ、UIView の左上と右下(斜めのグラデーション)に指定しています。

gradient = CGGradientCreateWithColors(colorspace, colors_buffer, locations);

 

startPoint = rect.origin;

endPoint = CGPointMake(rect.origin.x + rect.size.width, rect.origin.y + rect.size.height);

 

// グラデーションをキャンバスに描画します。

CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0);

 

// 使い終わった CF オブジェクトを解放します。

CGGradientRelease(gradient);

CGColorSpaceRelease(colorspace);

 

CFRelease(colors_buffer); 

}

このようにすることで、UIView の背景色をグラデーションで塗ることができるようになりました。

なお、backgroundColor2 プロパティのセッターでの UIColor のコピーの際に CGColor を使って複製を作成していますけど、これは、単に copy メソッドを使って色をコピーした場合だと、場面によってはエラーになってしまうことがあったので、そのような感じにしています。

また、新たに用意した backgroundColor2 プロパティの値が変更された際に、新しい色でグラデーションが再描画されるように、プロパティのセッターで、UIView の "setNeedsDisplay" メソッドを呼び出すところもポイントでしょうか。

 

上のコードで、例えば backgroundColor を [UIColor colorWithRed:1.000f green:0.705f blue:0.705f alpha:1.000f] に、backgroundColor2 を [UIColor colorWithRed:1.000f green:1.000f blue:0.745f alpha:1.000f] とした場合は、次のような感じで、UIView の背景がグラデーションで塗られるようになりました。

この例ではサブビューに色を付けてみたので小さいですけど、大きなビューであればそれ全体が塗られます。UIView に配置されているオブジェクトには影響ありません。

 

なお、グラデーションの表示位置、上記でいう "startPoint" と "endPoint" を、領域の範囲よりも小さい位置で指定した場合に、その範囲よりも外の色合いを、それぞれの色でべた塗りすることもできます。

その場合は "CGContextDrawLinearGradient" 関数の最後の引数のオプション指定で、"0" ではなく "kCGGradientDrawsAfterEndLocation | kCGGradientDrawsBeforeStartLocation" を指定します。

 

CALayer を使ってグラデーションを塗る方法

上記とほとんど同じ方法で、グラデーションを塗る先を、UIView の背景ではなくレイヤーにすることができます。

それには、レイヤー "CALayer" を利用できるようにするための準備として、ヘッダーまたはソースコード内で、次のファイルをインクルードする必要があります。

#import <QuartzCore/QuartzCore.h>

また、"QuartzCore.framework" をプロジェクトに組み込むようにします。

 

これらの準備が終わったら、先ほどお話した drawRect: メソッドの実装の中で、"UIGraphicsGetCurrentContext" 関数を使って描画するキャンバスを取得するよりも前に、次のようにして、描画用のイメージ領域を用意します。

// 描画用のイメージ領域を用意しています。領域サイズは、ここでは drawRect に渡された rect サイズを使用します。

UIGraphicsBeginImageContext(rect.size);

このようにすることで、UIGraphicsGetCurrentContext で取得されるキャンバスが、UIView の描画領域ではなく、別途用意したイメージ領域になるようです。

後はそのまま "CGContextDrawLinearGradient" 関数でグラデーションを描画するまで、UIView の背景に書き出すのと同じようにして描画を行っていって、最後にその内容を、次のようにして CALayer に描画します。

// レイヤーを用意します。大きさは、ここでは drawRect に渡された rect を使用します。

CALayer* layer = [CALayer layer];

layer.frame = rect;

 

// 描画用領域に書き込んだデータを UIImage として取得します。

UIImage* image = UIGraphicsGetImageFromCurrentImageContext();

 

// 描画用領域のデータを取得したら、不要になった描画領域を解放します。

UIGraphicsEndImageContext();

 

// レイヤーに描画データを設定します。

layer.contents = (id)image.CGImage;

このように作成したレイヤーは、たとえば UIView 上に表示させたい場合には、次のように UIView の layer に追加してあげます。

// レイヤーを UIView 型の view に追加すると、そのビューにレイヤーの内容が表示されます。

[view.layer addSublayer:layer];

このような運びでプログラミングを行うことで、レイヤーによるグラデーションの描画ができました。

[ もどる ]