3本指のピンチジェスチャーを作る 3

touchesMovedの実装

次にtouchesMovedを実装していきます。

ここでやることは単純でタッチポイント間の距離を求めて、touchsBegan時点で保存した距離との比率を
プロパティscaleに保存すればOK

ただし、念のため3点以外でタッチされた時はジェスチャーを失敗させます。
また、stateがUIGestureRecognizerStatePossibleの時はUIGestureRecognizerStateBeganに書き換えておきます。


- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesMoved:touches withEvent:event];
    
    int numberOfTouches =  event.allTouches.count;
    if (numberOfTouches != 3)
    {
        if (self.state == UIGestureRecognizerStatePossible)
        {
            self.state = UIGestureRecognizerStateFailed;
        } else {
            self.state = UIGestureRecognizerStateCancelled;
        }
        return;
    }
    
    UITouch *first = [[event.allTouchesallObjects] objectAtIndex:0];
    UITouch *second = [[event.allTouchesallObjects] objectAtIndex:1];
    UITouch *third = [[event.allTouchesallObjects] objectAtIndex:2];
    
    float distance = [self calcDistance:[first locationInView:self.view]
                                     p2:[second locationInView:self.view]
                                     p3:[third locationInView:self.view]];
    
    self.scale = distance / _distance_initial;
    
    if (self.state == UIGestureRecognizerStatePossible)
    {
        self.state = UIGestureRecognizerStateBegan;
    } 
    
    
}

後処理の実装

あとは終了処理とキャンセルの処理を実装すれば完成です

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesEnded:touches withEvent:event];
    
    switch (self.state) {
        caseUIGestureRecognizerStatePossible: 
        caseUIGestureRecognizerStateFailed:    
            self.state = UIGestureRecognizerStateFailed;
            break;
        caseUIGestureRecognizerStateBegan:
        caseUIGestureRecognizerStateChanged:
            // 正常に終了
            self.state = UIGestureRecognizerStateEnded;
            break;
        default:
            // 上記以外はキャンセル扱い
            self.state = UIGestureRecognizerStateCancelled;
            break;
    }
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    [supertouchesCancelled:touches withEvent:event];
    self.state = UIGestureRecognizerStateFailed;
    self.scale = 1;
}


使い方

使い方は通常のUIPinchGestureRecognizerと大体同じ

ジェスチャーをUIViewに登録して

ThreeFingersPinchGestureRecognizer *pinch = [[[ThreeFingersPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchAction:)] autorelease];
[self.view addGestureRecognizer:pinch];

ハンドリング

- (void)pinchAction : (ThreeFingersPinchGestureRecognizer *)sender 
{
  //sender.scale を使って拡大縮小などを行う
}

ファイル

3本指のピンチジェスチャーを作る 2

3点間の距離の求め方

3点間の距離の合計を求めるメソッドを作りましょう。
中学の時にならったアレです。

2点A(a,b),B(c,d)間の距離ABは
AB = √((c-a)の二乗 + (d-b)の二乗)

ってやつ
これを使って下記のようなメソッドを作成します。


//3点間の距離の合計を求める
- (float)calcDistance:(CGPoint)p1 p2:(CGPoint)p2 p3:(CGPoint)p3
{
    float distance = 0;

    float x;
    float y;

    x = fabs( p1.x - p2.x);
    y = fabs( p1.y - p2.y);
    distance += sqrt((x * x) + (y * y));

    x = fabs( p2.x - p3.x);
    y = fabs( p2.y - p3.y);
    distance += sqrt((x * x) + (y * y));

    x = fabs( p3.x - p1.x);
    y = fabs( p3.y - p1.y);
    distance += sqrt((x * x) + (y * y));

    return distance;
}

touchesBeganの実装

touchesBeganではジェスチャーの起動を判定する必要がありますが、
今回はタッチポイントが3点あるかどうかで判定します。

3点以外の時はstateにUIGestureRecognizerStateFailedを設定して、
ジェスチャーが失敗した事を通知します。


    //3本指の判定
    int numberOfTouches = event.allTouches.count;
    if (numberOfTouches != 3)

    {
        self.state = UIGestureRecognizerStateFailed;
        return;
    }

次にジェスチャー開始時点でのタップポイント間の距離を求めて保存します


    UITouch *first = [[event.allTouchesallObjects] objectAtIndex:0];
    UITouch *second = [[event.allTouchesallObjects] objectAtIndex:1];
    UITouch *third = [[event.allTouchesallObjects] objectAtIndex:2];

    _distance_initial = [self calcDistance:[first locationInView:self.view]
                        p2:[second locationInView:self.view]
                         p3:[third locationInView:self.view]];

    self.scale = 1;

※_distance_initialはインスタンス変数
scaleはプロパティです (例えば @property (nonatomic,assign) float scale; )

続きは次回

チョウチョの楽園でパシャリ

お出かけついでに石川県白山市にある「ふれあい昆虫館」で蝶を撮ってきました。

チョウチョ画像1 チョウチョ画像2

外は雪景色の中、多くのチョウが舞う常夏気分ですてきな空間だったのですが、
コートを着てチョウの園に入ったら、暑くて暑くて(^^;

3本指のピンチジェスチャーを作る 1

画像の拡大縮小で頻繁にピンチジェスチャー(UIPinchGestureRecognizer)を使うと思いますが、
通常の2本指ではなく3本指で操作したいと思いカスタムジェスチャーを作ってみました。

その作り方を公開したいと思います。

ジェスチャーの仕様は次の通り
・クラス名は ThreeFingersPinchGestureRecognizer
・3本指でジェスチャーを認識し始める
・3点間の距離の合計が変化した割合をプロパティ scale として示す

まずは、カスタムジェスチャーの基本から
カスタムジェスチャーの作り方は意外と簡単で、UIGestureRecognizer を継承して下記の5メソッドをオーバーライドすればOK

- (void)reset;
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;

それぞれ必要なことは

reset
ジェスチャーの状態を初期状態に戻す。
今回の実装ではプロパティscaleを初期値に戻します。

touchesBegan
ジェスチャーの開始判定を行います。
今回はタッチの数が3点であるか判定します。
また、scaleを算出するために開始時点のタッチポイント間の距離を求めます

touchesMoved
タッチ位置の変更に対しての処理を行います。今回はtouchBeganで求めたタッチポイント間の距離と今の距離からプロパティscaleを算出します

touchesEnded
ジェスチャーの終了処理

touchesCancelled
キャンセルされた場合の処理

あ、それと <UIKit/UIGestureRecognizerSubclass.h>をインポートしておく必要があります。

それぞれの詳細は次回で。

インスタンスに特定のメソッドが実装されているか確認する

クラスのイベントを通知するためにid型のdelegateをプロパティで公開すると思いますが、そのdelegateが特定のメソッドを実装しているかを確認する方法です。

例えば
itemTouched:・・ item:・・
というようなメソッドが存在するか確認する場合には下記の通り


if (self.delegate && [self.delegate respondsToSelector:@selector(itemTouched:item:)])
{
  [self.delegate itemTouched:self item:item];
}

アプリケーションの設定情報を保存する

NSUserDefaultsというクラスを使うと簡単に各種設定値を保存する事ができる。

使い方は下記を見てもらえば分かる通り、すごくシンプル。

//NSUserDefaultsの初期値を設定する
-(void)initConfigrations
{
  NSMutableDictionary* keyValues = [NSMutableDictionarydictionary];

  [keyValues setObject:@"0" forKey:@"KeyA"];
  [keyValues setObject:@"0" forKey:@"KeyB"];

  [[NSUserDefaults standardUserDefaults] registerDefaults:keyValues];
}

//設定をユーザ設定に保存する
-(void)saveConfigrations
{
  NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

  [defaults setInteger:self.propA forKey:@"KeyA"];
  [defaults setInteger:self.propB forKey:@"KeyB"];

  [defaults synchronize];
}

//ユーザ設定から設定内容を読み込む
-(void)loadConfigrations
{
  NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
 
  self.propA = [defaults integerForKey:@"KeyA"];
  self.propB = [defaults integerForKey:@"KeyB"];
}

ちなみに削除は removeObjectForKey で可能