UIViewについて


前回の予告の通り、いま15パズルの改良(?)版をテスト中ですが、なかなかバグが取れずに難渋しています。

この過程で気がついたことを二つご報告します。

一つ目は、前のコードの説明の中に何度も出てきた<convertRect>という関数についてです。
たとえば、

        //比較元のPieceを取り出す
        Piece *p = [piece objectAtIndex:i];
        //比較元のPieceの矩形を親のView(GameBoad)の座標に変換する
        CGRect prect = [boad convertRect:p.bounds fromView:p];

これは、共にUIViewであるpがboadのsubviewである時に、pの矩形を示すプロパティboundsを親のView(boad)の座標に変換するもので、これ自体間違いではありません。しかし、よくよくUIViewのドキュメントを見てみるとboundsのほかにframeというプロパティがあって、こちらは「Setting the frame rectangle repositions and resizes the receiver within the coordinate system of its superview. 」というではありませんか。
つまり、boundsをわざわざ座標変換しなくても、frameには親のviewの座標が入っています。上のコードは、

CGRect prect = [piece objectAtIndex:i].frame;

だけでいいのでした。

もうひとつ。こちらは気付いたどころか、少々青くなったのですが、UIViewのboundsにしてもframeにしても実体はCGRectですが、このCGRectは次のような構造体になっており、

	struct CGRect {
   		CGPoint origin;
   		CGSize size;
	};
	typedef struct CGRect CGRect;

矩形の原点であるoriginは「The origin is located in the lower-left of the rectangle.」、左下(lower-left)を指していると読めるではありませんか。
ぼくはずっと、originは画面の左上を指しているとばかり思っていました。では、これまでバグが出なかったのは、originは左上という早とちりが単に「一貫して」いたからだけなのか?

そこで、次のようなテストコードを書いて確かめてみました。

- (void)viewDidLoad {
    [super viewDidLoad];
	UIView *view01 = [[UIView alloc] initWithFrame:CGRectMake(20.0, 20.0, 280.0, 280.0)];
	view01.backgroundColor = [UIColor blackColor];
	[self.view addSubview:view01];
	NSLog([NSString stringWithFormat:@"view01 bounds origin.x:%f origin.y:%f size.width:%f size.height:%f",view01.bounds.origin.x,view01.bounds.origin.y,view01.bounds.size.width,view01.bounds.size.height]);	
	NSLog([NSString stringWithFormat:@"view01 frame origin.x:%f origin.y:%f size.width:%f size.height:%f",view01.frame.origin.x,view01.frame.origin.y,view01.frame.size.width,view01.frame.size.height]);	

	UIView *view02 = [[UIView alloc] initWithFrame:CGRectMake(100.0, 100.0, 80, 80)];
	view02.backgroundColor = [UIColor yellowColor];
	[view01 addSubview:view02];
	
	NSLog([NSString stringWithFormat:@"view02 bounds origin.x:%f origin.y:%f size.width:%f size.height:%f",view02.bounds.origin.x,view02.bounds.origin.y,view02.bounds.size.width,view02.bounds.size.height]);	
	NSLog([NSString stringWithFormat:@"view02 frame origin.x:%f origin.y:%f size.width:%f size.height:%f",view02.frame.origin.x,view02.frame.origin.y,view02.frame.size.width,view02.frame.size.height]);	
	CGRect rect02 = [view01 convertRect:view01.bounds fromView:view02];
	NSLog([NSString stringWithFormat:@"rect02 origin.x:%f origin.y:%f size.width:%f size.height:%f",rect02.origin.x,rect02.origin.y,rect02.size.width,rect02.size.height]);	
}

結果の画面とデバッグログは次の通り。

view01 bounds origin.x:0.000000 origin.y:0.000000 size.width:280.000000 size.height:280.000000
view01 frame origin.x:20.000000 origin.y:20.000000 size.width:280.000000 size.height:280.000000
view02 bounds origin.x:0.000000 origin.y:0.000000 size.width:80.000000 size.height:80.000000
view02 frame origin.x:100.000000 origin.y:100.000000 size.width:80.000000 size.height:80.000000
rect02 origin.x:100.000000 origin.y:100.000000 size.width:280.000000 size.height:280.000000

やはり、originは画面の左上です。
lower-leftとは、iPhone画面の座標系(X軸は右にプラス、Y軸は下にプラス)上でのlower-left、見かけの左上を示すということのようです。ほっとしました。

以上、tipsにもなりませんがご報告です。

コメントもいただいているのですが、なかなかお返事できません。申し訳ありません。