先日, アプリの手直しをして ようやくupdate がかかりましたので, この内容が書けるようになりました。
UIView を使って, いろいろな形を作って, それを画面に張り付けたりして, かっこいいUIをつくりたいわけですが, その中で, 円と角丸のView を作ってみました。
成果物はこちら, ColorDos というソフトです。TODOアプリです。 4ヶ国語対応, 無料ですので, 今回のコードでどんなものができるの確認したい方は是非是非 よろしくです。(やっぱり, 最近は出してもDownload数伸びないなぁ~)
では早速、方法は2つあります。 ColorDos のVersion1.0 では, 上を 1.1 は下を使っています。
1. QuartzCore.framework を使って view.layer.cornerRadius で角を丸める
2. Core Graphics, UIView の drawRect で, Shape を描画する
方法があります。
率直に言いましょう。 1 は極めて簡単です。 丸も工夫すればたったの2行で書けちゃいます。
ですが, これを多用すると, ものすごい遅いです。
※ちなみに筆者は, カレンダーで, 30個くらい描いてみましたが, ちょっと気になるくらいかくかくしています。
2を使うと, 非常にスムーズです。 ですが, 多少コードに工夫は必要です。
では早速 1から行きましょう。
1. QuartzCore の view.layer.conerRadius を使う
・ まず, QuartzCore.framework をリンクしましょう
"Project"をフォーカス -> "TARGETS" -> "Linked Frameworks and Libralies" -> QuartzCore を探す
・ ヘッダファイルに, <QuartzCore/QuartzCore.h> を入れましょう
・ UIViewを作ります
UIView *view = [UIView alloc] initWithFrame:CGRectmake(x,y,width, height)];
view.layer.cornerRadius = 2.0f;
view.clipsToBounds = YES;
QuartzCore は, この layer というプロパティにアクセスするために用います。
※UIView の * が抜けていました。ご指摘ありがとうございます。
● 丸の書き方
角丸は, cornerRadius をうまく調節すればいいのですが, 丸はどうでしょう。
実は, UIView を正方形に作った場合, その1辺の長さの半分を cornerRadius にすれば, 円になります。
UIView *view = [UIView alloc] initWithFrame:CGRectmake(x,y,width, width)];
view.layer.cornerRadius = width / 2.0;
view.clipsToBounds = YES;
※ここで注目するのは, とくに, UIViewを拡張したり, あたらしいクラスを作ったりしていないところです。 操作したのはプロパティだけです
2. Core Graphics, UIView の drawRect で, Shape を描画する
さて1の方法では, 大量に描画すると, あっという間にメモリを使い切って, かくかくとした感じになります。(一体中でどんな動作をしているのでしょう)
そこで, Core Graphics を丁寧に使って, UIView の拡張クラスをつくり, 自作のView を作りましょう。
ここでも, QuartzCore さんを使うので, 1と同じ要領で設定してください
まず円から行きましょう。
ex) UICircleView.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));
}
@end
ex) UICircleView.h
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
@interface UICircleView : UIView
@property (nonatomic) UIColor *color;
-(id)initWithFrameColor:(CGRect)frame color:(UIColor *)color;
@end
※使い方
UIView *colorRect = [[UICircleView alloc] initWithFrameColor:rect color:color];
colorRect.backgroundColor = [UIColor clearColor];
※rect は, Frame CGMake か何かで作ってください, color は UIColor のインスタンスです.
ちなみにbackground は, clearColorにしとくと, 上の画像みたいにぴっちり, 丸だけになります。
続いて角丸です。角丸は若干難しいです。
ex)UIRectView.m (これもUIViewの拡張です)
- (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 というパラメータで, 丸くなる部分を調節しています。これもパラメータで渡しとけばよかった。
さて, これで描画したら, パフォーマンスが無茶苦茶上がりました。 手抜きをせず頑張るべきですね。
とても参考になりました。ありがとうございます。
返信削除使い方の
UIView colorRect = [[UICircleView alloc] initWithFrameColor:rect color:color];
は
UIView *colorRect = [[UICircleView alloc] initWithFrameColor:rect color:color];
正しくはこうですよね。
はいその通りです。UIViewのところの * がちょくちょく抜けていました。ご指摘ありがとうございます。
返信削除