iOS 円や, 角丸View をつくる
もうひとつのプロフェッショナルプログラマーより転載です。
1年ほど前に個人でリリースしたソフトウェアで使ったテクニックです。
UIView を使って, いろいろな形を作って, それを画面に張り付けたりして, かっこいいUIをつくりたいわけですが, その中で, 円と角丸のView を作ってみました。
成果物はこちら, ColorDos というソフトです。TODOアプリです。 4ヶ国語対応, 無料です。
方法は2つあります。 ColorDos のVersion1.0 では, 上を 1.1 は下を使っています。
- QuartzCore.framework を使って view.layer.cornerRadius で角を丸める
- Core Graphics, UIView の drawRect で, Shape を描画する
方法があります。
率直に言いましょう。 1 は極めて簡単です。 丸も工夫すればたったの2行で書けちゃいます。
ですが, これを多用すると, ものすごい遅いです。
※ちなみに筆者は, カレンダーで, 30個くらい描いてみましたが, ちょっと気になるくらいかくかくしています。
2を使うと, 非常にスムーズです。 ですが, 多少コードに工夫は必要です。(Core Graphicsの描画を使います)
では早速 1から行きましょう。
QuartzCore の view.layer.conerRadius を使う
まず, QuartzCore.framework をリンクしましょう
“Project”をフォーカス -> “TARGETS” -> “Linked Frameworks and Libralies” -> QuartzCore を探す
ヘッダファイルに,
UIViewを作ります
QuartzCore は, layer というプロパティにアクセスするために用います。
角丸の場合
UIView *view = [UIView alloc] initWithFrame:CGRectmake(x,y,width, height)]; view.layer.cornerRadius = 2.0f; view.clipsToBounds = YES;
円の場合
角丸は, cornerRadius をうまく調節すればいいのですが, 丸はどうでしょう。
実は, UIView を正方形に作った場合, その1辺の長さの半分を cornerRadius にすれば, 円になります。
UIView *view = [UIView alloc] initWithFrame:CGRectmake(x,y,width, width)]; view.layer.cornerRadius = width / 2.0; view.clipsToBounds = YES;
Core Graphics, UIView の drawRect で, Shape を描画する
さて1の方法では, 大量に描画すると, あっという間にメモリを使い切って, かくかくとした感じになります。(一体中でどんな動作をしているのでしょう)
そこで, Core Graphics を丁寧に使って, UIView の拡張クラスをつくり, 自作のView を作りましょう。
ここでも, QuartzCore さんを使うので, 1と同じ要領で設定してください
円
.h
#import <UIKit/UIKit.h> #import <QuartzCore/QuartzCore.h> @interface UICircleView : UIView @property (nonatomic) UIColor *color; -(id)initWithFrameColor:(CGRect)frame color:(UIColor *)color; @end
.m
#import "UICircleView.h" @implementation UICircleView @synthesize color; - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { // Initialization code } return self; } - (id)initWithFrameColor:(CGRect)frame color:(UIColor *)refcolor { self = [super initWithFrame:frame]; if (self) { // Initialization code self.color = refcolor; } return self; } -(void)drawRect:(CGRect)rect { CGContextRef c = UIGraphicsGetCurrentContext(); CGFloat w = self.bounds.size.width; CGFloat h = self.bounds.size.width; CGContextSetFillColorWithColor(c, self.color.CGColor); CGContextFillEllipseInRect(c, CGRectMake(0, 0, w, h)); }
使い方
UIView *colorRect = [[UICircleView alloc] initWithFrameColor:rect color:color]; colorRect.backgroundColor = [UIColor clearColor];
※rect は, Frame CGMake か何かで作ってください, color は UIColor のインスタンスです.
ちなみにbackground は, clearColorにしとくと, 上の画像みたいにぴっちり, 丸だけになります。
続いて角丸です。角丸は若干難しいです。
角丸
.m
#import "UIRoundRectView.h" @implementation UICircleView - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { // Initialization code } return self; } - (id)initWithFrameColor:(CGRect)frame color:(UIColor *)refcolor { self = [super initWithFrame:frame]; if (self) { // Initialization code self.color = refcolor; } return self; } -(void)drawRect:(CGRect)rect { CGContextRef c = UIGraphicsGetCurrentContext(); CGFloat w = self.bounds.size.width; CGFloat h = self.bounds.size.width; CGFloat r = w * 0.20; CGContextSetFillColorWithColor(c, self.color.CGColor); CGRect rc = CGRectMake(0, 0, w, h); CGContextMoveToPoint(c, CGRectGetMinX(rc), CGRectGetMaxY(rc)-r); CGContextAddArcToPoint(c, CGRectGetMinX(rc), CGRectGetMinY(rc), CGRectGetMidX(rc), CGRectGetMinY(rc), r); CGContextAddArcToPoint(c, CGRectGetMaxX(rc), CGRectGetMinY(rc), CGRectGetMaxX(rc), CGRectGetMidY(rc), r); CGContextAddArcToPoint(c, CGRectGetMaxX(rc), CGRectGetMaxY(rc), CGRectGetMidX(rc), CGRectGetMaxY(rc), r); CGContextAddArcToPoint(c, CGRectGetMinX(rc), CGRectGetMaxY(rc), CGRectGetMinX(rc), CGRectGetMidY(rc), r); CGContextClosePath(c); CGContextFillPath(c); } @end
使い方は上と同じ形です。
こちらは, r というパラメータで, 丸くなる部分を調節しています。これもパラメータで渡しとけばよかった。
さて, これで描画したら, パフォーマンスが無茶苦茶上がりました。 手抜きをせず頑張るべきですね。