博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
《iOS创意程序设计家》——第6.4节事件检测
阅读量:6911 次
发布时间:2019-06-27

本文共 7384 字,大约阅读时间需要 24 分钟。

本节书摘来自异步社区《iOS创意程序设计家》一书中的第6章,第6.4节事件检测,作者 林柏全,更多章节内容可以访问云栖社区“异步社区”公众号查看

6.4 事件检测

iOS创意程序设计家
界面控制器除了负责界面的管理以及布局外,还负责事件的传递。这些事件包括我们在第5章已经介绍过的触控事件,还有接下来要介绍的晃动检测事件。这些事件都定义在UIResponder类里面,而无论是界面控制器UIViewController还是界面UIView,它们都继承自UIResponder类。

6.4.1 晃动检测

首先,我们来看看晃动事件的处理。与触控事件类似的是,晃动检测也是由一连串的事件所组成的,不过,要让您的应用程序支持晃动检测,必须让您的界面控制器成为First Responder才行。要让某个界面控制器成为First Responder,除了调用becomeFirstResponder这个方法外,还需要改写canBecomeFirstResponder这个方法,并返回YES,使得这个界面控制器可以成为First Responder,使用代码如下所示:

-(void) viewDidAppear:(BOOL) animated {  [super viewDidAppear:animated];  [self becomeFirstResponder];}-(void) viewDidDisappear:(BOOL) animated {  [self resignFirstResponder];  [super viewDidDisappear:animated];}-(BOOL) canBecomeFirstResponder {  Return YES;}-(void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event {    if( motion==UIEventSubtypeMotionShake)      NSLog(@"开始摇晃");}-(void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event {  if( motion==UIEventSubtypeMotionShake)      NSLog(@"取消摇晃");}-(void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {  if( motion==UIEventSubtypeMotionShake)      NSLog(@"结束摇晃");}

摇晃您的手机看看UIViewController是否可以接收到这些事件。

6.4.2 应用范例:魔术秀

有了以上的摇晃事件的说明后,我们可以很容易地运用这个事件来做一些应用。例如,我们可以将摇晃事件运用于魔术上。当然,这个魔术只需要有一点点的表演天分,而不需要有任何魔术的技巧。这个魔术的表演过程是这样的,首先让任何一位观众看看手机上出现的3张牌,当然,由系统随机出现的这3张牌都是A的机率是非常小的。为了取信观众,您甚至可以让观众任意触摸界面上的这3张牌。保持手部不触控到屏幕界面,然后在观众面前用力往下一甩,您会发现界面上的3张牌全部变成了A,再甩一次,界面中的3张牌又会恢复到观众原先看到的那3张牌了。通过以下的步骤,我们就可以实现这个魔术秀的应用程序。

学习重点:

Outlet Collection的使用;

晃动检测;
随机数的使用;
动画的使用。

请记得勾选“Use Storyboard”以及“Use Automatic Reference Counting”选项,并将扑克牌等图形文件加入到项目内。

打开MainStoryboard.storyboard,并在界面上加入3个UIImageView的控件。然后指定这3张图形为扑克牌的背面图cover.png。

请注意,这3张扑克牌的顺序会因为加入UIImageView的顺序不同而有所不同,先加入的控件会放在下面,如图6.14所示。如果有需要的话,也可以通过XCode选单上的“Editor”→“Arrange”来调整前后位置。

235b7c00ab8554c5933ff9d82d75358d26d1dbec

接下来,我们得将扑克牌连接为Outlet。与以往不同的是,我们要将这3种牌连接为Outlet Collection以方便后续的处理。连接的方式与Outlet一样,首先,将第1张牌连接为一个Outlet Collection,并命名为“poker”,接着分别将第2张与第3张连接到相同的Outlet Collection中就可以了。现在ViewController.m看起来应该如下所示:

#import 
@interface ViewController : UIViewController  @property (strong, nonatomic) IBOutletCollection(UIImageView) NSArray *pokers;@end

我们需要两个变量来记录发牌的状态,并且要定义一个发牌方式的自定义变量形态。其中,isCheat用来记录目前是否是3张A状态,而oldPokers则用来记录原先发的牌以方便后续我们可以还原回去。

Ch6\MagicShow\ MagicShow\ViewController.h#import 
// 定义扑克牌发牌方式(作弊、不作弊,以及恢复原有的牌)typedef enum {cheat,no_cheat,restore} DealOption;@interface ViewController : UIViewController {    // 用来记录目前3张牌是否均为A  BOOL isCheat;  // 用来记录原先发的3张牌  int oldPokers[3];} @property (strong, nonatomic) IBOutletCollection(UIImageView) NSArray *pokers;// 发新的扑克牌- (void) dealPokersWithOption: (DealOption) option;@end

现在为魔术秀加入摇晃事件的支持。要让一个界面控制器支持摇晃事件的第一步就是,先让这个界面控制器可以成为First Responder。因此,我们要在ViewController.m里面加入以下的方法:

- (BOOL) canBecomeFirstResponder {  return YES;}第二步则是让ViewController成为First Responder,并在不需要的时候让它退出First Responder。因此,我们需要在界面出现的时候调用becomeFirstResponder,以及在界面消失的时候调用resignFirstResponder。// 使应用程序支持Shake- (void) viewDidAppear:(BOOL)animated {  [super viewDidAppear:animated];  [self becomeFirstResponder];}- (void) viewDidDisappear:(BOOL)animated {  [super viewDidDisappear:animated];  [self resignFirstResponder];}

接下来,我们可以去处理初始发牌以及摇晃后换牌的程序代码。在以下的程序代码中,我们通过isCheat来判断目前是否需要更换为3张A的状态,如果需要的话,就通过dealPokersWithOption:cheat来更换,否则就通过dealPokersWithOption :restore还原回去,使用代码如下:

// 初始发牌- (void)viewDidLoad {  [super viewDidLoad];   // 一开始不要变3张A  [self dealPokersWithOption:no_cheat];}// 晃动检测- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)even {     isCheat = !isCheat;     if( isCheat )       [self dealPokersWithOption:cheat];     else       [self dealPokersWithOption:restore];  }6.jpg 接下来是发牌方法的实现。打开ViewController.m并加入以下内容:Ch6\MagicShow\ MagicShow\ViewController.m// 发牌- (void) dealPokersWithOption: (DealOption) option {   int value = 1; // 1表示A   int i=0;     for (UIImageView *imageView in pokers) {     if (option==cheat) {       value = 1;     }else if( option==no_cheat ){       if( !cheat ){         value = (arc4random() % 13) + 1; // 得到1~13之间的数字         oldPokers[i++] = value;       }     }else{       value = oldPokers[i++];     }       [UIView transitionWithView:imageView           duration:1.5f options:UIViewAnimationOptionCurveEaseInOut|UIView- AnimationOptionTransitionFlipFromLeft           animations:^(void){            imageView.image = [UIImage imageNamed:[NSString                        stringWithFormat:@"%d.png",value]];           } completion:nil];   }}

上述的程序代码通过“(arc4random() % 13) + 1”这一行程序代码来取得随机数所决定的扑克牌号码。通过这个方式便可以让随机数所决定的扑克牌号码落在1到13之间。整个魔术秀的应用程序就是这么简单,最后,让我们看一下魔术秀的表演,如图6.15所示。

e6b7474cb13198e4e8c928a2e31b03f8fbd89ea7

6.4.3 加速度计

加速度计(accelerometer)在iPhone内扮演着很重要的角色,包括本节内容所介绍的摇晃事件其实也是加速度计的一个应用。

如图6.16所示,iOS的加速度计是由3个轴向所构成的。也就是说,它可以测量3个方向的加速度值,而这个加速度值的单位就是大家在物理课所学到的重力加速度(1G=9.81 m/s2)。以图6.16来说,当手机往右手边旋转时,这时候x轴的加速度值便会越来越大;相反地,则x轴的加速度值便会越来越小。

12af0217e4635925c831b6ccb27ff0ac8c34b2e2

有了以上的概念后,我们来看看如何在应用程序内加入加速度的检测。

首先,必须在类的定义中加入UIAccelerometerDelegate协议,例如:

@interface MyViewController : UIViewController
接下来,必须指定加速度计的代理者为MyViewController这个程序,并通过updateInterval属性来指定加速度计数值更新的频率。例如:UIAccelerometer *accel = [UIAccelerometer sharedAccelerometer]; accel.delegate = self;accel.updateInterval = 1.0f / 60.0f;

最后则是加入加速度数值改变后的通知事件,使用代码如下:

- (void)accelerometer:(UIAccelerometer *)accelerometer    didAccelerate:(UIAcceleration *)acceleration {}

在这个事件内所传入的acceleration参数便带有x、y、z三个轴向的数值。例如:

acceleration.xacceleration.yacceleration.z

6.4.4 应用范例:水平仪

由于加速度计本身的特性,我们可以利用得到的3个轴向的加速度值来做一些有趣的应用,例如,把iOS设备当作水平仪来使用。水平仪是一种用来检验一个物品是否呈现水平状态的简单仪器。常见的水平仪是气泡式水平仪,这种水平仪里面注满了液体,但仪器中央会有一个小气泡。该气泡会随着待测的平面高度的变化而改变位置,若待测平面呈现水平状态,则气泡会位于仪器的正中央。对水平仪有了简单的了解之后,我们便可以把iOS设备变成水平仪了。

学习重点:

加速度计的使用;

如何让手机固定一个方向;
使用setTransform:来移动对象。

在建立项目过程中,请记得勾选“Use Storyboard”以及“Use Automatic Reference Counting”选项。

由于在使用水平仪的时候不希望界面随着用户的转动而改变方向,我们要去设置该应用程序只会固定在Landscape Left方向。请在Targets设置中的Info界面加入以下两个设置,如图6.17所示。

f57e8bfab37ebe2b1129f45809b55579dccd3133

其中,Supported interface orientations用来设置这部设备可以支持的方向,而Initial interface orientation则用来设置默认的方向。

最后,我们要到ViewController.m中来取消自动转向的设置,代码如下:

-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{  return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft);;}

这样一来,iOS设备就完全不会自动转向了。现在执行一下应用程序,看看方向是否正确。

直接将水平仪与气泡的图形拉到项目中,并选择“Copy items into destination group's folder”以复制文件到项目中。

打开MainStoryboard.storyboard,会发现手机的界面已经变成横向显示了。现在从控件库中拉进两个Image View到界面中,其中一个为水平仪本身的图形,另外一个则是气泡的图形。

为了精确定位,我们可以切换到尺寸观测窗口(size inspector),并分别设置这两个Image View的位置与大小,例如,

水平仪:(240,160)高度65

气泡:(240,160)宽度与高度均为30

接下来就可以在属性观测窗口(attribute inspector)分别为这两个控件设置图形了。完成后的界面应该如图6.18所示。

0e8b7223afd9a49ea666c4d79ffd2c0e3c53aaf9

由于我们需要变动气泡的位置,因此,必须要将气泡先连接为Outlet以方便控制。选择气泡的图形,并打开编辑器的辅助模式,按住“Control”键不放,然后连接为bubble。

打开ViewController.h并在类定义的后面加上UIAccelerometerDelegate协议。ViewController.h应该如下所示:

#import 
@interface ViewController : UIViewController
@property (strong, nonatomic) IBOutlet UIImageView *bubble;@end7.jpg加入加速度计的检测。打开ViewController.m并修改如下:首先在viewDidLoad指定加速度计的代理者为“ViewController”。- (void)viewDidLoad {   [super viewDidLoad];   UIAccelerometer *accel = [UIAccelerometer sharedAccelerometer];   accel.delegate = self;   accel.updateInterval = 1/60;}接着要编写加速度计的事件处理,代码如下:// 当加速度计的数值改变时,同时也改变气泡的位置- (void) accelerometer:(UIAccelerometer *)accelerometer    didAccelerate:(UIAcceleration *)acceleration {   [bubble setTransform:     CGAffineTransformMakeTranslation(-acceleration.y*20,-acceleration.x*10)];}

在上述的程序代码里面,我们通过UIView的setTransform:方法来改变气泡的位置,由于x、y轴的正负值刚好与气泡运动的位置相反,因此要乘以-1来改变。读者们可以自行验证这一点。程序最终的执行界面如图6.19所示。

1f119906c1af0f2b3a6f5b16cca1c30457461ded

转载地址:http://pqwcl.baihongyu.com/

你可能感兴趣的文章
linux TCP客户端指定端口号连接服务端
查看>>
CSS3设置Table奇数行和偶数行样式
查看>>
python:大量参数如何传递
查看>>
Javascript下的AJAX
查看>>
Django之路由系统
查看>>
KVM autotest
查看>>
Python语言特性之3:@staticmethod和@classmethod
查看>>
1.单一职责原则(Single Responsibility Principle)
查看>>
LeetCode--058--最后一个单词的长度
查看>>
LINUX下PHP运行环境搭建之三(转)
查看>>
asp.net中连接字符串问题(类库中使用ConfigurationManager.ConnectionStrings)
查看>>
艾伟_转载:Web网站缓存文件并发问题解决方案
查看>>
PHP-002
查看>>
谷歌笔试题整理(一)
查看>>
leetcode - Remove Duplicates from Sorted List II
查看>>
如何解决 Windows 实例出现身份验证错误及更正 CredSSP
查看>>
使用Navicat连接阿里云mysql报错10061
查看>>
c#金额转换成中文大写金额
查看>>
hibernate.properties和hibernate.cfg.xml
查看>>
简说宽带商的弹窗广告进化及网站应对之策(DNS劫持进化论)
查看>>