Viewにグラデーションレイヤを適用する その2
やはりアドホックな対応というのは無理があるようだ。さて、どうしようか。
きちんと再描画をさせるのであればやはりUIViewの派生クラスを書かなければ駄目だろう。ということで実際に書いてみた。
実装
-
- BBUIGradientView.h
#import <UIKit/UIKit.h> //グラデーションのアングル enum BBUIGradientViewAngle { ANGLE_0 = 0, ANGLE_45 = 45, ANGLE_90 = 90, ANGLE_135 = 135, ANGLE_180 = 180, ANGLE_225 = 225, ANGLE_270 = 270 }; @interface BBUIGradientView : UIView @property (nonatomic, strong, setter = setStartColor:) UIColor* startColor; @property (nonatomic, strong, setter = setEndColor:) UIColor* endColor; @property (nonatomic, setter = setAngle:) enum BBUIGradientViewAngle angle; @end
-
- BBUIGradientView.m
#import <QuartzCore/QuartzCore.h> #import "BBUIGradientView.h" @interface BBUIGradientView () { CAGradientLayer* _gradient; } @end @implementation BBUIGradientView - (void)setStartColor:(UIColor *)startColor { _startColor = startColor; _gradient.colors = [NSArray arrayWithObjects: (id)[_startColor CGColor], //開始色 (id)[_endColor CGColor], //終了色 nil]; [self setNeedsDisplay]; } - (void)setEndColor:(UIColor *)endColor { _endColor = endColor; _gradient.colors = [NSArray arrayWithObjects: (id)[_startColor CGColor], //開始色 (id)[_endColor CGColor], //終了色 nil]; [self setNeedsDisplay]; } - (void)setAngle:(enum BBUIGradientViewAngle)angle { switch (angle) { case ANGLE_0: { [_gradient setStartPoint:CGPointMake(0.5, 0.0)]; [_gradient setEndPoint:CGPointMake(0.5, 1.0)]; break; } case ANGLE_45: { [_gradient setStartPoint:CGPointMake(1.0, 0.0)]; [_gradient setEndPoint:CGPointMake(0.0, 1.0)]; break; } case ANGLE_90: { [_gradient setStartPoint:CGPointMake(1.0, 0.5)]; [_gradient setEndPoint:CGPointMake(0.0, 0.5)]; break; } case ANGLE_135: { [_gradient setStartPoint:CGPointMake(1.0, 1.0)]; [_gradient setEndPoint:CGPointMake(0.0, 0.0)]; break; } case ANGLE_180: { [_gradient setStartPoint:CGPointMake(0.5, 1.0)]; [_gradient setEndPoint:CGPointMake(0.5, 0.0)]; break; } case ANGLE_225: { [_gradient setStartPoint:CGPointMake(0.0, 1.0)]; [_gradient setEndPoint:CGPointMake(1.0, 0.0)]; break; } case ANGLE_270: { [_gradient setStartPoint:CGPointMake(0.0, 0.5)]; [_gradient setEndPoint:CGPointMake(1.0, 0.5)]; break; } default: break; } [self setNeedsDisplay]; } - (id)initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; if (self) { //グラデーションレイヤの初期化 _gradient = [CAGradientLayer layer]; _gradient.frame = self.bounds; _gradient.colors = [NSArray arrayWithObjects: (id)[[UIColor redColor] CGColor], //開始色 (id)[[UIColor blueColor] CGColor], //終了色 nil]; self.angle = ANGLE_0; [self.layer insertSublayer:_gradient atIndex:0]; } return self; } - (void)dealloc { [_gradient removeFromSuperlayer]; _gradient = nil; _startColor = nil; _endColor = nil; } - (void)layoutSubviews { [super layoutSubviews]; _gradient.frame = self.bounds; } @end
プロパティとしてグラデーションの角度は使いやすいように45度間隔を定数として与えられるようにしたが、それをSrartPointとEndPointに変換している部分がベタなコードで気に入らない。三角関数等を使ってもっとスマートな設定にしたいのだが良い方法を思いつかなかった。
使い方
InterfaceBuilderでは通常のUIViewとして配置して、その後Identitiy Inspectorでクラス名をUIViewからBBUIGradientViewにすれば良い。あとはIBOutletで接続して、コードで初期化する。
@property (weak, nonatomic) IBOutlet BBUIGradientView *pnlGradent; : : - (void)viewDidLoad { [super viewDidLoad]; //ビュー背景のグラデーション pnlGradent.startColor = [UIColor yellowColor]; pnlGradent.endColor = [UIColor greenColor]; pnlGradent.angle = ANGLE_45; :