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];
このような運びでプログラミングを行うことで、レイヤーによるグラデーションの描画ができました。
[ もどる ]