そのため、望ましい結果を達成するためのより良いソリューションを誰も提供してくれなかったことを考慮して、カスタム ジェスチャ認識エンジンを作成しました。以下は、指の下のピクセルが指の下にまったく残るように、カスタム認識エンジンがビューを再配置する場所と、重心をパンおよびズーム効果の中心として使用する新しいスケールを示すことを可能にする主要なコード フラグメントです。指が回転しているように見える場合を除きますが、これはサポートされておらず、そのようなジェスチャーを止めることはできません。このジェスチャ認識機能は、2 本の指で同時にパンとズームを行います。2 本の指のうちの 1 本が持ち上げられた場合でも、後で 1 本の指でパンするためのサポートを追加する必要があります。
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
// We can only process if we have two fingers down...
if ( FirstFinger == nil || SecondFinger == nil )
return;
// We do not attempt to determine if the first finger, second finger, or
// both fingers are the reason for this method call. For this reason, we
// do not know if either is stale or updated, and thus we cannot rely
// upon the UITouch's previousLocationInView method. Therefore, we need to
// cache the latest UITouch's locationInView information each pass.
// Break down the previous finger coordinates...
float A0x = PreviousFirstFinger.x;
float A0y = PreviousFirstFinger.y;
float A1x = PreviousSecondFinger.x;
float A1y = PreviousSecondFinger.y;
// Update our cache with the current fingers for next pass through here...
PreviousFirstFinger = [FirstFinger locationInView:nil];
PreviousSecondFinger = [SecondFinger locationInView:nil];
// Break down the current finger coordinates...
float B0x = PreviousFirstFinger.x;
float B0y = PreviousFirstFinger.y;
float B1x = PreviousSecondFinger.x;
float B1y = PreviousSecondFinger.y;
// Calculate the zoom resulting from the two fingers moving toward or away from each other...
float OldScale = Scale;
Scale *= sqrt((B0x-B1x)*(B0x-B1x) + (B0y-B1y)*(B0y-B1y))/sqrt((A0x-A1x)*(A0x-A1x) + (A0y-A1y)*(A0y-A1y));
// Calculate the old and new centroids so that we can compare the centroid's movement...
CGPoint OldCentroid = { (A0x + A1x)/2, (A0y + A1y)/2 };
CGPoint NewCentroid = { (B0x + B1x)/2, (B0y + B1y)/2 };
// Calculate the pan values to apply to the view so that the combination of zoom and pan
// appear to apply to the centroid rather than the center of the view...
Center.x = NewCentroid.x + (Scale/OldScale)*(self.view.center.x - OldCentroid.x);
Center.y = NewCentroid.y + (Scale/OldScale)*(self.view.center.y - OldCentroid.y);
}
ビュー コントローラーは、問題のビューに新しいスケールと中心を割り当てることによって、イベントを処理します。他のジェスチャ レコグナイザーでは、コントローラーが一部の計算を実行できる傾向があることに気付きましたが、すべての計算をレコグナイザーで実行しようとしました。
-(void)handlePixelTrack:(PixelTrackGestureRecognizer*)sender
{
sender.view.center= sender.Center;
sender.view.transform = CGAffineTransformMakeScale(sender.Scale, sender.Scale);
}