UIScrollViewの中身を回転させる
HMDTさんのこの記事を読んで。
http://hmdt.jp/archives/2010_07.html#2010070801
iPhone SDKが登場したときから、ずっとやろうとしてなかなかうまくいかなかったものに、拡大縮小および回転可能な画像の表示がある。ピンチイン/アウトで拡大縮小して、あと画像の回転もできるやつ。標準の写真アプリみたいなやつね。それっぽい動作をするものならなんとかできるんだけど、完璧なものをやろうとすると、とても難しい。
UIScrollViewを使って実現する訳だ。デリゲートを使って、zoomの対象となるビューを指定してやればいい。単純にズームするだけならいいんだけど、これにcontentOffsetやcontentSizeの変更とか、ビューのtransformの変更とか加えると、とたんにUIScrollViewが言うことをきかなくなる。原因が分からなくて、ずっとイライラさせられてきた。
もういい加減長年の関係にケリをつけたくて、時間を割いて徹底的に検討してみた。回転のために変更したtransformプロパティの値をいろんなタイミングで表示させてみると、なんか見たことない値入ってるー。
で、私の作ったRGBTouchっていうアプリはまさに同じことをしている。UIScrollViewにUIImageViewを入れて、ピンチで拡大縮小、ボタンで回転(とある理由でセンサーで回転にはしていない)してる。で、UIImageViewのtransformがUIScrollViewによって変えられていることには気付いた。私の対処法は、UIScrollViewによってズームの値が設定されているtransformに、さらに回転を加えてUIImageViewに設定し直す、ということだった。コードはこんなん。
-(IBAction)rotateImage:(id)sender { if (angle >= 3) angle = 0; else angle++; CGSize testSize = CGSizeApplyAffineTransform(CGSizeMake(0.5, 0.5), imageView.transform); CGFloat scale = fabs(testSize.width) + fabs(testSize.height); CGAffineTransform newTransform = CGAffineTransformMakeRotation(M_PI / 2.0 * angle); newTransform = CGAffineTransformScale(newTransform, scale, scale); CGSize size = image.size; CGSize transformedSize = CGSizeApplyAffineTransform(size, newTransform); transformedSize.width = fabs(transformedSize.width); transformedSize.height = fabs(transformedSize.height); [UIView beginAnimations:nil context:nil]; scrollView.contentSize = transformedSize; imageView.transform = newTransform; imageView.center = CGPointMake(transformedSize.width/2.0, transformedSize.height/2.0); [UIView commitAnimations]; }
補足説明。
- imageViewの初期サイズはimageと同じにしてある。
- scrollViewのzoomScaleは使っていないのは、この方法を繰り返すと正しい値を返してくれなくなるため。
- imageViewのframeはいじらない。transformをいじるとframeは使えなくなってしまうとリファレンスに書いてある。代わりにcenterを使う。