サンプル
サンプルを起動するとウィンドウが1つ立ち上がる。
この中に表示されている画像を2本指でドラッグすると画像がそれに追随して移動する。
実装
画像を表示し、トラックパッドのイベントを処理するカスタムビューを用意する。
@interface GestureView : NSView { NSImage* image_; BOOL isTracking_; NSTouch* previousTouch_; } @property (nonatomic, retain) NSTouch* previousTouch; @endタッチイベントは NSResponder の関連メソッドをオーバライドして処理する。まず touchesBeganWithEvent: において2本指のタッチを検出し、その時の片方の指の NSTouchインスタンスを previousTouchへ取っておく。
- (void)touchesBeganWithEvent:(NSEvent *)event { NSSet *touches = [event touchesMatchingPhase:NSTouchPhaseTouching inView:self]; if (touches.count == 2) { self.previousTouch = [touches anyObject]; } }続いて移動時に呼び出される touchesMovedWithEvent: で2本指の場合にビューの移動処理を行う。
- (void)touchesMovedWithEvent:(NSEvent *)event { NSSet *touches = [event touchesMatchingPhase:NSTouchPhaseTouching inView:self]; if (touches.count == 2 && self.previousTouch) { NSTouch *currentTouch = nil; for (currentTouch in [touches allObjects]) { if ([currentTouch.identity isEqual:self.previousTouch.identity]) { break; } } NSSize deviceSize = self.previousTouch.deviceSize; CGFloat dx = (currentTouch.normalizedPosition.x - self.previousTouch.normalizedPosition.x) * deviceSize.width * 2; CGFloat dy = (currentTouch.normalizedPosition.y - self.previousTouch.normalizedPosition.y) * deviceSize.height * 2; if (!isTracking_) { if (fabs(dx) > kThresholdOfDoubleTouches || fabs(dy) > kThresholdOfDoubleTouches) { isTracking_ = YES; } } else { NSRect frame = self.frame; frame.origin.x += dx; frame.origin.y += dy; self.frame = frame; } self.previousTouch = currentTouch; } }NSTouch の identify プロパティを使って触れられた指それぞれについて touchesイベントを通じて識別が行える。ここでは touchesBeganWithEvent: の時に取っておいた previousTouch と比較して同じ指の NSTouch を探し出し、それを元に移動量を計算している。
ソースコード
GitHub からどうぞ。
GestureSample at 2011-02-01 from xcatsan/MacOSX-Sample-Code - GitHub
2本指タッチの扱い
今回は簡単な方法を採用して移動量の計算には1本分の指しか使っていない。この為、ドラッグ中に2本指の間が離れたり近づいたりしても支障なくドラッグ操作が行える。通常2本指でドラッグする場合は2本の指を揃えて操作するのでこれで問題はないと思われる。簡単なしくみなのでソースコード上の数値(2)を書き換えれば3本指、4本指のドラッグも簡単に処理できる。なお拡大縮小のピンチ操作を扱おうとするとドラッグ処理を区別する必要がある。今回のサンプルに単純に magnifyWithEvent: を実装するとピンチ操作時には magnifyWithEvent: と touchesMovedWithEvent: が交互に呼び出される。もし今回のサンプルで拡大縮小を実装する場合はピンチ時に画像が移動するのはまずいので両方の操作をきちんと区別する必要がある。前回みたサンプル LightTable では指の間の距離も考慮していた。
[参考] Cocoaの日々: [Mac] トラックパッド 〜 タッチイベントサンプル LightTable のソースを読む
デバイスごとのスケーリング
-[NSTouch normalizedPosition] で取得できる値は 0〜1.0 の間に収まる様に正規化されたものとなっている。この為(移動などで)利用する場合は調整する必要がある。NSTouchには使用しているタッチデバイスのサイズが deviceSizeとして取得できるのでこれを係数として利用することができる(deviceSizeの値は 72ppi換算のピクセル値)。サンプルでは移動量の計算にこの値を使っている。なおコード上ではさらに2倍の係数をかけている。これは画面上で実際にドラッグして調整した値。このあたりシビアなドラッグ操作が要求されるアプリではユーザがカスタマイズできるようにした方が良いと思われる。
参考情報
NSTouch Class Reference
.
Responses
Leave a Response