はじめに

このエントリの内容はあまり自信がありません。ご注意を。

layoutSubviews, setNeedsLayout, setNeedsDisplay, layoutIfNeededの4つのメソッドは、なんとなく再描画に関係するやつぐらいのイメージを持っているのですが、いつもそれぞれどういう処理をするのかよくわからなくなってしまいます。

なので、整理する意味を込めてまとめてみました。

まとめ

layoutSubviews

オーバーライドして自分(View)やSubViewのレイアウトを調整するのに使う。このメソッド自信を直接呼び出すのはあまりよろしくない。

setNeedsLayout

このメソッドを呼ぶと、setNeesdLayoutを呼んだメソッドが終わったあとでlayoutSubviewsが呼ばれる。なにかViewに変更を加えた後でlayoutSubviewsを呼びたいなーと思ったら、このメソッドを呼ぶ。

setNeedsDisplay

このメソッドを呼ぶと、UIViewのdrawRectメソッドが呼ばれ、再描画される。layoutSubViewsは関係ない(呼ばれない)

layoutIfNeeded

これがいまいちよくわかっていないのですが、わかっていることはsetNeedsLayoutのあとに呼ぶと、layoutSubviewsが即座に呼ばれるということです。

サンプル

CustomView

通常のUIViewのlayoutSubviewsとdrawRectメソッドにNSLogを仕込んだだけ。

- (void)layoutSubviews
{
    NSLog(@"layoutSubviews");
    [super layoutSubviews];

    CGRect rect = self.frame;
    rect.size = _viewSize;
    self.frame = rect;
}

- (void)drawRect:(CGRect)rect
{
    NSLog(@"drawRect");
    [super drawRect:rect];
}

実験用のViewController

上から、setNeedsLayout単体、setNeedsDisplay単体、setNeedsLayout+layoutIfNeededを呼び出している。 ``` - (IBAction)setNeedsLayoutButtonDidPush:(id)sender { NSLog(@"start"); self.customView.viewSize = CGSizeMake(10, 10); [self.customView setNeedsLayout]; NSLog(@"end"); }

  • (IBAction)setNeedsDisplayButtonDidPush:(id)sender { NSLog(@"start"); self.customView.viewSize = CGSizeMake(20, 20); [self.customView setNeedsDisplay]; NSLog(@"end"); }

  • (IBAction)layoutIfNeededButtonDidPush:(id)sender { NSLog(@"start"); self.customView.viewSize = CGSizeMake(30, 30); [self.customView setNeedsLayout]; [self.customView layoutIfNeeded]; NSLog(@"end");

} ```

実行結果

setNeedsLayoutButtonDidPush:

setNeedsLayoutButtonDidPush:が終わった後でlayoutSubviewsが呼ばれている。

2013-12-07 22:53:22.424 LayoutTest[71843:70b] start
2013-12-07 22:53:22.425 LayoutTest[71843:70b] end
2013-12-07 22:53:22.426 LayoutTest[71843:70b] layoutSubviews

setNeedsDisplayButtonDidPush:

drawRectが呼ばれている。

2013-12-07 22:53:24.431 LayoutTest[71843:70b] start
2013-12-07 22:53:24.432 LayoutTest[71843:70b] end
2013-12-07 22:53:24.432 LayoutTest[71843:70b] drawRect

layoutIfNeededButtonDidPush:

layoutIfNeededButtonDidPush:の途中でlayoutSubviewsが呼ばれている。

2013-12-07 22:53:25.197 LayoutTest[71843:70b] start
2013-12-07 22:53:25.198 LayoutTest[71843:70b] layoutSubviews
2013-12-07 22:53:25.198 LayoutTest[71843:70b] end