UIGestureRecognizers を使用して、ユーザーが画面上でオブジェクト (UIView のサブクラス) をパン、スケーリング、回転できるようにする iPad アプリに取り組んでいます。
[UIView frame] プロパティは変換後に無効になることを理解しているため、UIGestureRecognizers の値を取得して、「フレーム」を自分で保持しようとしています。
これを試みるために私が使用しているコードは次のとおりです (Apple のサンプル プロジェクト、SimpleGestureRecognizers の多くのコードに気付くかもしれません)。
// Shape.h (partial)
@interface Shape : UIView <UIGestureRecognizerDelegate> {
CGFloat centerX;
CGFloat centerY;
CGFloat rotatation;
CGFloat xScale;
CGFloat yScale;
}
// Shape.m (partial)
- (void)panPiece:(UIPanGestureRecognizer *)gestureRecognizer
{
UIView *piece = [gestureRecognizer view];
[self adjustAnchorPointForGestureRecognizer:gestureRecognizer];
if ([gestureRecognizer state] == UIGestureRecognizerStateBegan || [gestureRecognizer state] == UIGestureRecognizerStateChanged) {
CGPoint translation = [gestureRecognizer translationInView:[piece superview]];
self.centerX += translation.x;
self.centerY += translation.y;
[piece setCenter:CGPointMake([piece center].x + translation.x, [piece center].y + translation.y)];
for ( HandleView *h in [self handles] ) {
[h setCenter:CGPointMake([h center].x + translation.x, [h center].y + translation.y)];
[h setNeedsDisplay];
}
[gestureRecognizer setTranslation:CGPointZero inView:[piece superview]];
NSLog(@"(%.0f, %.0f, %.0f, %.0f) %.2f˚, (%.2fx, %.2fx)", [self frame].origin.x, [self frame].origin.y, [self frame].size.width, [self frame].size.height, [self rotation], [self xScale], [self yScale]);
}
}
// rotate the piece by the current rotation
// reset the gesture recognizer's rotation to 0 after applying so the next callback is a delta from the current rotation
- (void)rotatePiece:(UIRotationGestureRecognizer *)gestureRecognizer
{
[self adjustAnchorPointForGestureRecognizer:gestureRecognizer];
if ([gestureRecognizer state] == UIGestureRecognizerStateBegan || [gestureRecognizer state] == UIGestureRecognizerStateChanged) {
CGFloat rot = [self normalizeRotation:[gestureRecognizer rotation]];
self.rotation += rot * 180.0 / M_PI;
NSLog(@"Rotation: %.12f", [gestureRecognizer rotation]);
[gestureRecognizer view].transform = CGAffineTransformRotate([[gestureRecognizer view] transform], [gestureRecognizer rotation]);
[gestureRecognizer setRotation:0];
NSLog(@"(%.0f, %.0f, %.0f, %.0f) %.2f˚, (%.2fx, %.2fx)", [self frame].origin.x, [self frame].origin.y, [self frame].size.width, [self frame].size.height, [self rotation], [self xScale], [self yScale]);
}
}
// scale the piece by the current scale
// reset the gesture recognizer's rotation to 0 after applying so the next callback is a delta from the current scale
- (void)scalePiece:(UIPinchGestureRecognizer *)gestureRecognizer
{
[self adjustAnchorPointForGestureRecognizer:gestureRecognizer];
if ([gestureRecognizer state] == UIGestureRecognizerStateBegan || [gestureRecognizer state] == UIGestureRecognizerStateChanged) {
self.xScale *= [gestureRecognizer scale];
self.yScale *= [gestureRecognizer scale];
[gestureRecognizer view].transform = CGAffineTransformScale([[gestureRecognizer view] transform], [gestureRecognizer scale], [gestureRecognizer scale]);
[gestureRecognizer setScale:1];
NSLog(@"(%.0f, %.0f, %.0f, %.0f) %.2f˚, (%.2fx, %.2fx)", [self frame].origin.x, [self frame].origin.y, [self frame].size.width, [self frame].size.height, [self rotation], [self xScale], [self yScale]);
}
}
回転の奇妙な点に気付いたので、正確な回転値を維持するために次のメソッドを実装しました。
- (CGFloat) normalizeRotation:(CGFloat)rot
{
if (abs(rot) > 0.05) {
if (rot > 0) {
rot -= M_PI;
} else {
rot += M_PI;
}
return [self normalizeRotation:rot];
} else {
return rot;
}
}
とにかく、画面上の形状はうまくパン、スケーリング、回転します。すべてが期待どおりで、パフォーマンスは良好です。
問題は、ユーザーが UIView を移動、サイズ変更、回転した後、ユーザーにタップさせて、ピンチによる「正方形」のサイズ変更以外のサイズ変更を可能にする「ハンドル」を提供したいことです (つまり、ピンチ ジェスチャでは、x と y の両方で同じ比率で拡大または縮小します)。さて、上記のコードを使用しても、保存される値はまったく正確ではありません。
私が使用している「ハンドル」は、UIView のフレーム/長方形の各コーナーと各「辺」の中間にある 10x10 ドットです。最初に四角形を配置し、他の操作を行う前にタップしてハンドルを取得すると、適切な場所にハンドルが表示されます。オブジェクトを移動、サイズ変更、回転してからタップすると、ハンドルがすべてシェイプから少しずれます。一般的には約20ピクセルのようです。
UIGestureRecognizer オブジェクトの値は十分に正確ではありませんか? これらの値は画面上のオブジェクトを変更するために使用され、それは正確であるため、そうではないようです。
UIView のフレームをいじった後に実際の表現を取得する方法はないと確信していますが、悪い値を与えているカスタム コードの欠陥はどこにあるのでしょうか? 度とラジアンを変換するときに精度が失われますか?
関連するメモ: Apple には、翻訳/変換されたビューを描画する方法を追跡する内部コードがあることは明らかです。現在使用している単色のボックスは、正しく移動、ズーム、回転されています。それで、翻訳/変換されたUIViewを表示するために使用する値にアクセスする方法はありますか?
ありがとう!