2012年5月14日月曜日

モーションイベントサンプル1 - シェイクと回転検知

前回の「マルチタッチイベントサンプル2 - カスタムGesture Recognizer」に引き続き、iOS Developer Libraryの「iOSイベント処理ガイド」(英語版はEvent Handling Guide for iOS)に沿って、サンプルを公開します。
今回は、「シェイクモーションイベント」と「現在のデバイスの向きの取得」です。

シェイクモーションイベント【iOS 3.0以降】

文章の編集中などにデバイスをシェイクすると「取り消す」かどうかを聞かれますが、あれがシェイクモーションイベントです。
内部的には加速度センサーを利用してデバイスが振られたのかどうかを判定しています。しかし、プログラミングする際には加速度センサーを意識する必要はなく、タッチやスワイプなどと同様に「UIEvent」として同じように扱うことができます。
実装の手順は以下の通りです。
  1. ファーストレスポンダになる
    - (BOOL)canBecomeFirstResponder
    {
        return YES;
    }
    
    - (void)viewDidAppear:(BOOL)animated
    {
        [super viewDidAppear:animated];
        
        [self becomeFirstResponder];
    }
  2. モーションイベントを受けるメソッドを実装
    - (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event
    {
        // モーションイベントの開始時に処理される
    }
    
    - (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
    {
        // モーションイベントの実行中に処理される
    }
    
    - (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event
    {
        // モーションイベントがキャンセルされた場合に処理される
        // (大抵の場合、デバイスが動いたが結局シェイクジェスチャーではなかったときに呼ばれる)
    }
    

現在のデバイスの向きの取得【iOS 2.0以降】

デバイスがどの方向を向いているのかを検知するものです。こちらも加速度センサーを使って判定しているのですが、モーションイベントと同様に、加速度センサーからの細かい情報を使うことなく実装できます。しかし、細かい傾きなどを知るためには加速度センサーなどを利用して実装する必要があるため、次回以降にサンプル実装します。
実装の手順は以下の通りです。
  1. UIDeviceクラスのbeginGeneratingDeviceOrientationNotificationsメソッドを実行し、加速度センサーを有効にする
    [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
  2. (オプション)UIDeviceOrientationDidChangeNotification通知の受け取りを登録する
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil];
    
  3. UIDeviceクラスのorientationプロパティから現在の傾きの情報を取得。その際、加速度センサーが有効になっていないと「UIDeviceOrientationUnknown」になります。
    [UIDevice currentDevice].orientation
  4. (オプション)UIDeviceOrientationDidChangeNotification通知の受け取りを登録していたら、削除する
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
    
  5. UIDeviceクラスのendGeneratingDeviceOrientationNotificationsメソッドを実行し、加速度センサーを無効にする
    [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
    

shouldAutorotateToInterfaceOrientationとの違い

デバイスの回転に合わせて画面を回転させるメソッドとして「shouldAutorotateToInterfaceOrientation」があります。そのため、画面をデバイスに合わせて回転させたいのであれば、この「shouldAutorotateToInterfaceOrientation」を利用すべきです。
UIDeviceクラスのorientationプロパティでは、画面が表なのか裏なのかも判別することができます。その為、パズルゲームなどで画面上の一部のオブジェクトを回転させたり、デバイスが表や裏であるといったことを検知したい場合に有効です。
方向を定義する定数も若干異なっているため注意は必要です。以下のように定義されています。

- UIDevice.h (UIDeviceクラスのorientationプロパティで使われる)
typedef enum {
    UIDeviceOrientationUnknown,
    UIDeviceOrientationPortrait,            // Device oriented vertically, home button on the bottom
    UIDeviceOrientationPortraitUpsideDown,  // Device oriented vertically, home button on the top
    UIDeviceOrientationLandscapeLeft,       // Device oriented horizontally, home button on the right
    UIDeviceOrientationLandscapeRight,      // Device oriented horizontally, home button on the left
    UIDeviceOrientationFaceUp,              // Device oriented flat, face up
    UIDeviceOrientationFaceDown             // Device oriented flat, face down
}   UIDeviceOrientation;
- UIApplication.h (shouldAutorotateToInterfaceOrientationで使われる)
typedef enum {
    UIInterfaceOrientationPortrait           = UIDeviceOrientationPortrait,
    UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown,
    UIInterfaceOrientationLandscapeLeft      = UIDeviceOrientationLandscapeRight,
    UIInterfaceOrientationLandscapeRight     = UIDeviceOrientationLandscapeLeft
} UIInterfaceOrientation;
イメージUIDeviceOrientationUIInterfaceOrientation
UIDeviceOrientationPortraitUIInterfaceOrientationPortrait
UIDeviceOrientationPortraitUpsideDownUIInterfaceOrientationPortraitUpsideDown
UIDeviceOrientationLandscapeLeftUIInterfaceOrientationLandscapeRight
UIDeviceOrientationLandscapeRightUIInterfaceOrientationLandscapeLeft
画面が表(上)
UIDeviceOrientationFaceUp無し
画面が裏(下)
UIDeviceOrientationFaceDown無し

サンプル

ソースコードはGitHubに公開してあります。
iOS-SampleCodes/Shake&DeviceOrientationNotification - GitHub

2つのサンプルを合わせただけなので簡単ですが、以下、サンプル画像です。
起動すると現在の画面の向きが表示されます。

回転させるとそのときの値に変わります。

シェイクすると、画面が赤くなり回転の判別が無効になります。その際、iPhoneの場合はバイブレーションで知らせます。もう一度振ると戻ります。

直接は関係ないですが、ユーザへのリアクションが分かりやすいように、シェイクモーションが認識されるとiPhoneの場合はバイブレーションで知らせるようにしています。方法は以下の通り簡単です。
  1. プロジェクトへ「AudioToolbox.framework」の追加
  2. ヘッダの読み込み
    #import <AudioToolbox/AudioServices.h>
    
  3. バイブレーションの実行
    // iPhoneのみだが、受け付けたらバイブレーションで知らせる
    AudioServicesPlayAlertSound(kSystemSoundID_Vibrate);
    


次回

次は、「モーションイベントサンプル2 - UIAccelerometerを使った傾き検知」です。

0 コメント:

コメントを投稿