2015年3月30日月曜日

図形描画

昔のパソコンみたいにLine文とか書いて簡単にドローグラフィックが描けないのが、ちょいめんどくさい。

基本的には、UIViewのサブクラスを自作してやり、その中のdrawRectメソッドで書き換え処理を行うこととなる。

作ったサブクラスは、Storyboardで画面全体に貼ってあるViewのCustom Classにくくりつけてやれば画面全体をドローキャンバスにできるし、StoryboardにUIViewを貼ってそれにくくりつけてやれば画面の一部だけをドローキャンバスにできる。

以下、RestOfTimeViewというUIViewのサブクラスにドロー画像を表示させる場合。
画面全体に貼ってあるViewにRestOfTimeViewをくくりつけてる。


サブクラス側には
- (void)drawRect:(CGRect)rect {}
メソッドのひな形がコメントアウトされた状態で書かれてるので、コメントを外して使う。
このメソッドがiOSが決めた画面更新のタイミングに従って呼ばれ、書き換えられるわけだ。
このメソッドを直接呼び出すことは禁止されてるので、プロパティを使って中の値にアクセスするとともに、呼出元のViewControllerから
setNeedsDisplayメソッドを使って画面更新を指示する。

RestOfTimeViewにrestOfTimeというプロパティがあった場合、そこにViewControllerからアクセスするには、RestOfTimeViewを#importした後に、以下のようにする。
ともに(RestOfTimeView *)を頭につけて()でくくり、自作カスタムクラスにキャスト(変換)してやらないとエラーになっちゃうことに注意。
キャストしないとself.viewもしくは_restOfTimeは、ただのUIViewクラスのままだからだそうだが、よくわからん。

その1:画面全体に貼ってあるUIViewにくくりついてる場合
((RestOfTimeView *)self.view).restOfTime = 30;

その2:画面の一部に新たに貼られたUIView(restOfTimeプロパティ)にくくりついてる場合
((RestOfTimeView *)(_restOfTime)).restOfTime = 30;

そのままではすぐに画面更新してくれないので、setNeedsDisplayメソッドをviewに送ってサブクラス中のdrawRectメソッドの実行を要求し、画面を更新させる。

その1の場合
[self.view setNeedsDisplay];


その2の場合
[_restOfTime setNeedsDisplay];


さて、実際のサブクラスの中身。
Storyboardを使った場合と、コードでViewをalloc、initした場合とではイニシャライザが違う。
drawRectメソッドの中では、この例では
UIBezierPath *rectangle = [UIBezierPath bezierPathWithRect:self.bounds];
で四角形のパスを作り、

setStrokeで線の色を、setFillで塗りつぶしの色を、setLineWidthで線の太さをそれぞれ指定し、fillstrokeでそれぞれ線の描画、塗りつぶし描画をしてる。
他にも線をつなげた描いたり、円を描いたり、角の丸い四角を描いたり、ベジェ曲線を描いたりいろいろできる。

@implementation RestOfTimeView

//StoryboardからViewを読み込む場合
- (id)initWithCoder:(NSCoder *)aDecoder {
    if ((self = [super initWithCoder:aDecoder])) {
        self.backgroundColor = [UIColor yellowColor];
    }
    return self;
}

//コードでViewを作る場合
- (id)initWithFrame:(CGRect)frame {
    if ((self = [super initWithFrame:frame])) {
    //initialization code
        self.backgroundColor = [UIColor purpleColor];
    }
    return self;
}

- (void)drawRect:(CGRect)rect {
    // Drawing code
    //ベースの色
    [[UIColor blueColor] setStroke];
    [[UIColor redColor] setFill];
    UIBezierPath *rectangle = [UIBezierPath bezierPathWithRect:self.bounds];
    [rectangle setLineWidth:2];
    [rectangle fill];
    [rectangle stroke];
    
    //残り時間
    CGFloat restTimeWidth = self.bounds.size.width / 30 * _restOfTime;
    CGRect restTimeRect = CGRectMake(self.bounds.origin.x, self.bounds.origin.y, restTimeWidth, self.bounds.size.height);
    rectangle = [UIBezierPath bezierPathWithRect:restTimeRect];
    [[UIColor blueColor] setFill];
    [rectangle fill];
}

@end

重ね重ね、8ビットパソコンの頃よりめんどくさいんだけど、ガマンガマン。

0 件のコメント:

コメントを投稿