拡大はUIPinchGestureRecognizer、回転はUIRotationGestureRecognizerを使います。
ポイントは、ビューにUIGestureRecognizerDelegateを実装するようにして、shouldRecognizeSimultaneouslyWithGestureRecognizerで拡大(ピンチ)と回転の同時処理を受け付けるようにする点です。
ビュー宣言
@interface HogeView <UIGestureRecognizerDelegate> {
CGAffineTransform _currentTransform;
float _scale;
float _angle;
BOOL _isMoving;
}
@end
ジェスチャの同時処理を許可
- (BOOL) gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
ジェスチャ登録時にはtargetとは別に、delegateを設定する必要があります。
初期化
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// 回転ジェスチャをビューに登録
UIRotationGestureRecognizer *rotation = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotationGesture:)];
rotation.delegate = self;
[self addGestureRecognizer:rotation];
// ピンチジェスチャをビューに登録
UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchGesture:)];
pinch.delegate = self;
[self addGestureRecognizer:pinch];
_isMoving = NO;
_scale = 1.0f;
_angle = 0.0f;
}
return self;
}
回転ジェスチャと拡大ジェスチャのハンドラはほぼ同じです。
ジェスチャ実行中の状態(回転角度+拡大率)をフィールドで保持するようにしておき、どちらのジェスチャハンドラでも回転+拡大の両方のアフィン変換を適用します。
回転ジェスチャ
- (void)rotationGesture:(UIRotationGestureRecognizer*)gesture {
// ジェスチャ開始時
if (!_isMoving && gesture.state == UIGestureRecognizerStateBegan) {
_isMoving = YES;
_currentTransform = self.transform;
}
// ジェスチャ終了時
else if (_isMoving && gesture.state == UIGestureRecognizerStateEnded) {
_isMoving = NO;
_scale = 1.0f;
_angle = 0.0f;
}
// 回転角度取得
_angle = gesture.rotation;
// アフィン変換を適用
CGAffineTransform transform = CGAffineTransformConcat(CGAffineTransformConcat(_currentTransform, CGAffineTransformMakeRotation(_angle)), CGAffineTransformMakeScale(_scale, _scale));
gesture.view.transform = transform;
}
拡大ジェスチャ
- (void)pinchGesture: (UIPinchGestureRecognizer *)gesture {
// ジェスチャ開始時
if (!_isMoving && gesture.state == UIGestureRecognizerStateBegan) {
_isMoving = YES;
_currentTransform = self.transform;
}
// ジェスチャ終了時
else if (_isMoving && gesture.state == UIGestureRecognizerStateEnded) {
_isMoving = NO;
_scale = 1.0f;
_angle = 0.0f;
}
// 拡大率取得
_scale = gesture.scale;
// アフィン変換を適用
CGAffineTransform transform = CGAffineTransformConcat(CGAffineTransformConcat(_currentTransform, CGAffineTransformMakeRotation(_angle)), CGAffineTransformMakeScale(_scale, _scale));
gesture.view.transform = transform;
}