1. 程式人生 > >應用進入後臺監測搖一搖事件<轉>

應用進入後臺監測搖一搖事件<轉>

ica 不起作用 round 基本 彈出 app phone property 單位

原文地址:iOS使用CoreMotion實現搖一搖功能

現在網上介紹的iOS搖一搖功能,基本是以借助系統的ShakeToEdit功能來實現,什麽是ShakeToEdit?看下圖應該就能懂:

技術分享圖片

  怎麽實現?請看以下代碼:

[objc] view plain copy
  1. //ViewController 加入以下兩方法
  2. -(BOOL)canBecomeFirstResponder
  3. {
  4. //讓當前controller可以成為firstResponder,這很重要
  5. return YES;
  6. }
  7. -(void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
  8. {
  9. if (event.subtype==UIEventSubtypeMotionShake) {
  10. //做你想做的事
  11. }
  12. }
  13. //在viewDidView中調用以下消息,主動讓當前controller成為firstResponder
  14. [self becomeFirstResponder];
  15. //已經不需要其它多余代碼了

  這個方法最簡單,但這個功能有時候會失效。它失效的時候,系統所有搖一搖撤銷重做都會不起作用,從而導致包括所有關聯的Shake事件也不起作用。失效原因或在什麽情況下失效,目前還沒有相關資料。據這兩天個人觀察,大多發生在手機放在褲袋中走10多分鐘路之後(iPhone5S iOS 7.05).是否因為搖得太久了,系統為了省電就關閉此功能呢?希望大家也拿自己手機來試一試,我們一起來看看這到底是什麽問題。

  要恢復,最直接的是連接iTunes,否則,就要讓手機平放一段時間,但時候平放一天都沒有恢復。所以說此方式不太穩定,微信及其它有搖一搖功能的應用,他們的搖一搖並不受此影響,而且微信的搖一搖動作比ShakeToEdit要輕,可以講手動動一下就激活了。於是我認為,這些應用都放棄了ShakeToEdit,使用了加速儀,自己重新實現。

  使用加速儀與使用相機,聲音之類不同,不需要經過用戶允許,也沒有訪問限制,當然也沒什麽危害,是個基本配備。那要怎麽做?下面費話不多說,直接開始吧:

  第一步,為項目TARGET添加CoreMotion.framework

技術分享圖片

  第二步,引入頭文件

[objc]
view plain copy
  1. #import <CoreMotion/CoreMotion.h>

  第三步,使用CMMotionManager

[objc] view plain copy
  1. @property (strong,nonatomic) CMMotionManager *motionManager;

  註意,當前應用只能有一個CMMotionManager實例,多個實例會影響接收速率

  第四步,實例並初始化加速儀

[objc] view plain copy
  1. self.motionManager = [[CMMotionManager alloc] init];//一般在viewDidLoad中進行
  2. self.motionManager.accelerometerUpdateInterval = .1;//加速儀更新頻率,以秒為單位

  第五步,開始接收加速儀數據(startAccelerometerUpdatesToQueue:withHandler:)

[objc] view plain copy
  1. -(void)viewDidAppear:(BOOL)animated
  2. {
  3. [self startAccelerometer];
  4. }
  5. -(void)startAccelerometer
  6. {
  7. //以push的方式更新並在block中接收加速度
  8. [self.motionManager startAccelerometerUpdatesToQueue:[[NSOperationQueue alloc]init]
  9. withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) {
  10. [self outputAccelertionData:accelerometerData.acceleration];
  11. if (error) {
  12. NSLog(@"motion error:%@",error);
  13. }
  14. }];
  15. }
  16. -(void)outputAccelertionData:(CMAcceleration)acceleration
  17. {
  18. //綜合3個方向的加速度
  19. double accelerameter =sqrt( pow( acceleration.x , 2 ) + pow( acceleration.y , 2 )
  20. + pow( acceleration.z , 2) );
  21. //當綜合加速度大於2.3時,就激活效果(此數值根據需求可以調整,數據越小,用戶搖動的動作就越小,越容易激活,反之加大難度,但不容易誤觸發)
  22. if (accelerameter>2.3f) {
  23. //立即停止更新加速儀(很重要!)
  24. [self.motionManager stopAccelerometerUpdates];
  25. dispatch_async(dispatch_get_main_queue(), ^{
  26. //UI線程必須在此block內執行,例如搖一搖動畫、UIAlertView之類
  27. });
  28. }
  29. }
  30. -(void)viewDidDisappear:(BOOL)animated
  31. {
  32. //停止加速儀更新(很重要!)
  33. [self.motionManager stopAccelerometerUpdates];
  34. }

  最後一步

  至此,搖一搖核心已經實現,但還差最後一步:當App退到後臺時必須停止加速儀更新,回到當前時重新執行。否則應用在退到後臺依然會接收加速度更新,可能會與其它當前應用沖突,產生不好的體驗。所以,分別在viewDidAppear和viewDidDisappear中加入如下監聽:

[objc] view plain copy
  1. //viewDidAppear中加入
  2. [[NSNotificationCenter defaultCenter] addObserver:self
  3. selector:@selector(receiveNotification:)
  4. name:UIApplicationDidEnterBackgroundNotification object:nil];
  5. [[NSNotificationCenter defaultCenter] addObserver:self
  6. selector:@selector(receiveNotification:)
  7. name:UIApplicationWillEnterForegroundNotification object:nil];
[objc] view plain copy
  1. //viewDidDisappear中取消監聽
  2. [[NSNotificationCenter defaultCenter] removeObserver:self
  3. name:UIApplicationDidEnterBackgroundNotification object:nil];
  4. [[NSNotificationCenter defaultCenter] removeObserver:self
  5. name:UIApplicationWillEnterForegroundNotification object:nil];
[objc] view plain copy
  1. //對應上面的通知中心回調的消息接收
  2. -(void)receiveNotification:(NSNotification *)notification
  3. {
  4. if ([notification.name
  5. isEqualToString:UIApplicationDidEnterBackgroundNotification])
  6. {
  7. [self.motionManager stopAccelerometerUpdates];
  8. }else{
  9. [self startAccelerometer];
  10. }}

  至此,所有使用加速儀實現搖一搖功能的實現方式已介紹完畢。

  一些可改進的地方:

  1) 搖一搖動作捕捉——如果僅是以加速度大小來判定,有可能用戶突然快速移動手機時就激活了搖動,但用戶比較稍稍慢一些來回晃動手機卻不會激活,可能與用戶期望的稍微有出入。系統的ShakeToEdit就能做得比較到位。
   我們可以結合定時器與加速度的正反方向來更精確判定用戶的搖一搖動作,例如:綜合加速度改為帶方向的向量,然後當1.5秒內有相反兩個方向大於某個數值的加速度,才算為一個搖動行為。這個1.5秒時間需要通過實際測試來取值,當某次取得的加速度值大於某個值開始統計下一個加速度向量,此值也需要實測來取值,可能1.5左右就夠了。

  2) App狀態更改——如果激活的搖一搖是個長時間等待行為,例如彈出ActionSheet讓用戶選擇操作。在用戶進行下一步操作前,ActionSheet沒消失前,不應該啟動下一次監聽,包括應用從後臺回到當前狀態後,也要判斷用戶是否有過下一步行為。

應用進入後臺監測搖一搖事件<轉>