1 系统通讯录
1.1 问题
移动设备提供了一个很重要的的内置数据库——通讯录,通讯录放在SQLite3数据库中,但是应用之间不能直接访问,也就是其他的应用不能采用持久化技术直接访问通讯录数据库,为了实现通讯录数据库的访问,苹果开放了一些专门的API,在开发访问通讯录的应用中通常使用两个框架:AddressBook和AddressBookUI。本案例使用AddressBook框架和AddressBookUI框架实现对系统通讯录联系人的访问和编辑,如图-1所示:
图-1
1.2 方案
首先创建一个SingleViewApplication应用,在Storyboard文件中搭建选取联系人的界面,本案例中的场景是一个带有导航的TableViewController和ViewController进行绑定,标题设置为My Friend。
然后分别给左右两边拖放一个BarButtonItem控件,关联成ViewController的动作方法selectContacts:和newClick:,左边按钮的动作方法用于实现访问系统通讯录选择联系人,右边按钮的动作方法用于创建新联系人。
界面完成后在ViewController中定义两个属性NSMutableArray类型的属性contactNames和contactIDs,分别用于记录当前界面需要展示的联系人姓名和联系人ID,然后实现表视图的数据源方法,展示My Friend界面的联系人姓名。
然后实现selectContacts:方法,当点击左上角按钮时创建ABPeoplePickerNavigationController视图控制器对象peoplePicker,访问系统通讯录的联系人,并设置peoplePicker的委托对象。
实现ABPeoplePickerNavigationControllerDelegate协议中的方法peoplePickerNavigationController:didSelectPerson:,该方法会在选择完联系人时调用,因此该方法需要获取到所选联系人的姓名和ID,并将选中的联系人姓名展示在My Friend界面中。
接下来需要实现当用户点击My Friend界面的联系人姓名时,则展示该联系人的详细信息,因此需要在tableView:didSelectRowAtIndexPath:方法中创建ABPersonViewController视图控制器对象personViewController,并设置委托对象,然后展示出来。
ABPersonViewControllerDelegate有一个必须实现的方法personViewController:shouldPerformDefaultActionForPerson:property:该方法在选择联系人属性时被调用,返回YES则调用该属性的默认动作,返回NO则不做任何动作。
最后实现新建联系人方法newClick:,该方法中需要创建ABNewPersonViewController视图控制器对象newPersonViewController,用于展示新建联系人界面,并设置委托对象。ABNewPersonViewControllerDelegate协议有一个必须实现的方法newPersonViewController:didCompleteWithNewPerson:,该方法在联系人新建完成之后调用,本案例需要在该方法将联系人的联系人的姓名和ID记录下来,并将选中的联系人姓名展示在My Friend界面中。
1.3 步骤
实现此案例需要按照如下步骤进行。
步骤一:搭建界面
首先创建一个SingleViewApplication应用,在Storyboard文件中搭建选取联系人的界面,本案例中的场景是一个带有导航的TableViewController和ViewController进行绑定,标题设置为My Friend。
然后分别给左右两边拖放一个BarButtonItem控件,关联成ViewController的动作方法selectContacts:和newClick:,左边按钮的动作方法用于实现访问系统通讯录选择联系人,右边按钮的动作方法用于创建新联系人。
在Storyboard中完成的界面如图-2所示:
图-2
步骤二:选择联系人
界面完成后在ViewController中定义两个属性NSMutableArray类型的属性contactNames和contactIDs,分别用于记录当前界面需要展示的联系人姓名和联系人ID,并使用延迟加载方式初始化这两个属性,代码如下所示:
- @interface ViewController ()
- //保存联系人姓名数组属性
- @property(nonatomic, strong) NSMutableArray *contactNames;
- //保存联系人ID数组属性
- @property(nonatomic, strong) NSMutableArray *contactIDs;
- @end
- //初始化
- -(NSMutableArray *)contactIDs {
- if (!_contactIDs) {
- _contactIDs = [@[]mutableCopy];
- }
- return _contactIDs;
- }
- -(NSMutableArray *)contactNames {
- if (!_contactNames) {
- _contactNames = [@[]mutableCopy];
- }
- return _contactNames;
- }
然后实现表视图的数据源方法,展示My Friend界面的联系人姓名,代码如下所示:
- - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
- return self.contactNames.count;
- }
- - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
- static NSString *CellIdentifier = @"Cell";
- UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
- if (cell == nil) {
- cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
- }
- cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
- cell.textLabel.text = [self.contactNames objectAtIndex:[indexPath row]];
- return cell;
- }
接下来实现通过系统通讯录选择联系人的方法selectContacts:,当点击左上角按钮时创建ABPeoplePickerNavigationController视图控制器对象peoplePicker,访问系统通讯录的联系人,并设置peoplePicker的委托对象,代码如下所示:
- //选择联系人
- - (IBAction)selectContacts:(id)sender
- {
- //创建ABPeoplePickerNavigationController控制器,用于访问通讯录显示联系人列表
- ABPeoplePickerNavigationController *peoplePicker = [[ABPeoplePickerNavigationController alloc] init];
- peoplePicker.peoplePickerDelegate = self;
- [self presentViewController:peoplePicker animated:YES completion:nil];
- }
最后需要实现ABPeoplePickerNavigationControllerDelegate协议中的方法peoplePickerNavigationController:didSelectPerson:,该方法会在选择完联系人时调用,因此该方法需要获取到所选联系人的姓名和ID,并将选中的联系人姓名展示在My Friend界面中,代码如下所示:
- //选择联系人时调用
- - (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController*)peoplePicker didSelectPerson:(ABRecordRef)person {
- //获取选择联系人的姓名
- NSString *name = CFBridgingRelease(ABRecordCopyCompositeName(person));
- //将姓名添加到self.contactNames数组
- [self.contactNames addObject:name];
- //获取ID,将ID添加到self.contactIDs数组
- [self.contactIDs addObject:[NSNumber numberWithInt:ABRecordGetRecordID(person)]];
- //peoplePicker界面退回
- [peoplePicker dismissViewControllerAnimated:YES completion:nil];
- //取得最后一个放入contactIDs中的ID,也就是刚刚选择的ID
- NSIndexPath *path = [NSIndexPath indexPathForRow:self.contactIDs.count-1 inSection:0];
- //选中联系人插入到首页表视图中
- NSArray *arry = [NSArray arrayWithObject:path];
- [self.tableView insertRowsAtIndexPaths:arry withRowAnimation:UITableViewRowAnimationRight];
- }
当点击Cancel按钮时系统通讯录的联系人界面退出,代码如下所示:
- //点击Cancel按钮时调用
- - (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker
- {
- [peoplePicker dismissViewControllerAnimated:YES completion:nil];
- }
完成效果如图-3,图-4所示:
图-3
图-4
步骤三:显示联系人详细信息
当用户点击My Friend界面的联系人姓名时,则展示该联系人的详细信息,因此需要在tableView:didSelectRowAtIndexPath:方法中创建ABPersonViewController视图控制器对象personViewController,并设置委托对象然后展示出来,注意如果需要对联系人进行编辑需要将allowsEditing属性设置为YES,左上角才会出现编辑按钮否则不能进行编辑,代码如下所示:
- - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
- CFErrorRef error = NULL;
- //创建addressBook对象
- ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error);
- //通过ID得到记录对象
- ABRecordRef person = ABAddressBookGetPersonWithRecordID(addressBook, [[self.contactIDs objectAtIndex:indexPath.row] intValue]);
- //创建ABPersonViewController控制器,用于显示和编辑联系人详细信息
- ABPersonViewController *personViewController = [[ABPersonViewController alloc] init];
- //设置委托对象
- personViewController.personViewDelegate = self;
- //设定要显示的联系人对象
- personViewController.displayedPerson = person;
- //设定联系人视图是否可以编辑
- personViewController.allowsEditing = YES;
- //是否显示动作按钮
- personViewController.allowsActions = YES;
- //设置需要显示的属性,邮箱和电话
- personViewController.displayedProperties = @[[NSNumber numberWithInt:kABPersonEmailProperty],
- [NSNumber numberWithInt:kABPersonPhoneProperty]];
- [self.navigationController pushViewController:personViewController animated:YES];
- CFRelease(addressBook);
- }
ABPersonViewControllerDelegate有一个必须实现的方法personViewController:shouldPerformDefaultActionForPerson:property:该方法在选择联系人属性时被调用,返回YES则调用该属性的默认动作,返回NO则不做任何动作,代码如下所示:
- - (BOOL)personViewController:(ABPersonViewController *)personViewController
- shouldPerformDefaultActionForPerson:(ABRecordRef)person
- property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifierForValue
- {
- return YES;
- }
完成效果如图-5所示:
图-5
步骤四:新建联系人
实现新建联系人方法newClick:,该方法中需要创建ABNewPersonViewController视图控制器对象newPersonViewController,用于展示新建联系人界面,并设置委托对象,代码如下所示:
- - (IBAction)newClick:(id)sender {
- //创建ABNewPersonViewController控制器,用于新建联系人
- ABNewPersonViewController *newPersonViewController = [[ABNewPersonViewController alloc] init];
- //设置委托对象
- newPersonViewController.newPersonViewDelegate = self;
- UINavigationController *newNavigationController = [[UINavigationController alloc]
- initWithRootViewController:newPersonViewController];
- [self presentViewController:newNavigationController animated:YES completion:nil];
- }
ABNewPersonViewControllerDelegate协议有一个必须实现的方法newPersonViewController:didCompleteWithNewPerson:,该方法在联系人新建完成之后调用,本案例需要在该方法将联系人的联系人的姓名和ID记录下来,并将选中的联系人姓名展示在My Friend界面中,代码如下所示:
- - (void)newPersonViewController:(ABNewPersonViewController *)newPersonView
- didCompleteWithNewPerson:(ABRecordRef)person
- {
- NSString *name = CFBridgingRelease(ABRecordCopyCompositeName(person));
- [self.contactNames addObject:name];
- [self.contactIDs addObject:[NSNumber numberWithInt:ABRecordGetRecordID(person)]];
- [newPersonView dismissViewControllerAnimated:YES completion:nil];
- //取得最后一个放入contactIDs中的ID,也就是刚刚选择的ID
- NSIndexPath *path = [NSIndexPath indexPathForRow:self.contactIDs.count-1 inSection:0];
- //选中联系人插入到首页表视图中
- NSArray *arry = [NSArray arrayWithObject:path];
- [self.tableView insertRowsAtIndexPaths:arry withRowAnimation:UITableViewRowAnimationRight];
- }
新建的联系人会被添加到系统通讯录中,效果如图-6,图-7所示:
图-6
图-7
1.4 完整代码
本案例中,TRViewController.m文件中的完整代码如下所示:
- #import "ViewController.h"
- #import <AddressBook/AddressBook.h>
- #import <AddressBookUI/AddressBookUI.h>
- @interface ViewController ()<ABPeoplePickerNavigationControllerDelegate,ABPersonViewControllerDelegate,ABNewPersonViewControllerDelegate>
- //保存联系人姓名数组属性
- @property(nonatomic, strong) NSMutableArray *contactNames;
- //保存联系人ID数组属性
- @property(nonatomic, strong) NSMutableArray *contactIDs;
- @end
- @implementation ViewController
- -(NSMutableArray *)contactIDs {
- if (!_contactIDs) {
- _contactIDs = [@[]mutableCopy];
- }
- return _contactIDs;
- }
- -(NSMutableArray *)contactNames {
- if (!_contactNames) {
- _contactNames = [@[]mutableCopy];
- }
- return _contactNames;
- }
- #pragma mark -
- #pragma mark 表视图数据源
- - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
- return self.contactNames.count;
- }
- - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
- static NSString *CellIdentifier = @"Cell";
- UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
- if (cell == nil) {
- cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
- }
- cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
- cell.textLabel.text = [self.contactNames objectAtIndex:[indexPath row]];
- return cell;
- }
- - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
- CFErrorRef error = NULL;
- //创建addressBook对象
- ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error);
- //通过ID得到记录对象
- ABRecordRef person = ABAddressBookGetPersonWithRecordID(addressBook, [[self.contactIDs objectAtIndex:indexPath.row] intValue]);
- //创建ABPersonViewController控制器,用于显示和编辑联系人详细信息
- ABPersonViewController *personViewController = [[ABPersonViewController alloc] init];
- //设置委托对象
- personViewController.personViewDelegate = self;
- //设定要显示的联系人对象
- personViewController.displayedPerson = person;
- //设定联系人视图是否可以编辑
- personViewController.allowsEditing = YES;
- //是否显示动作按钮
- personViewController.allowsActions = YES;
- //设置需要显示的属性,邮箱和电话
- personViewController.displayedProperties = @[[NSNumber numberWithInt:kABPersonEmailProperty],
- [NSNumber numberWithInt:kABPersonPhoneProperty]];
- [self.navigationController pushViewController:personViewController animated:YES];
- CFRelease(addressBook);
- }
- //新建联系人
- - (IBAction)newClick:(id)sender {
- //创建ABNewPersonViewController控制器,用于新建联系人
- ABNewPersonViewController *newPersonViewController = [[ABNewPersonViewController alloc] init];
- //设置委托对象
- newPersonViewController.newPersonViewDelegate = self;
- UINavigationController *newNavigationController = [[UINavigationController alloc]
- initWithRootViewController:newPersonViewController];
- [self presentViewController:newNavigationController animated:YES completion:nil];
- }
- //选择联系人
- - (IBAction)selectContacts:(id)sender
- {
- //创建ABPeoplePickerNavigationController控制器,用于访问通讯录显示联系人列表
- ABPeoplePickerNavigationController *peoplePicker = [[ABPeoplePickerNavigationController alloc] init];
- peoplePicker.peoplePickerDelegate = self;
- [self presentViewController:peoplePicker animated:YES completion:nil];
- }
- #pragma mark -
- #pragma mark ABPeoplePickerNavigationController 委托方法实现
- //点击Cancel按钮时调用
- - (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker
- {
- [peoplePicker dismissViewControllerAnimated:YES completion:nil];
- }
- //选择联系人时调用
- - (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController*)peoplePicker didSelectPerson:(ABRecordRef)person {
- //获取选择联系人的姓名
- NSString *name = CFBridgingRelease(ABRecordCopyCompositeName(person));
- //将姓名添加到self.contactNames数组
- [self.contactNames addObject:name];
- //获取ID,将ID添加到self.contactIDs数组
- [self.contactIDs addObject:[NSNumber numberWithInt:ABRecordGetRecordID(person)]];
- //peoplePicker界面退回
- [peoplePicker dismissViewControllerAnimated:YES completion:nil];
- //取得最后一个放入contactIDs中的ID,也就是刚刚选择的ID
- NSIndexPath *path = [NSIndexPath indexPathForRow:self.contactIDs.count-1 inSection:0];
- //选中联系人插入到首页表视图中
- NSArray *arry = [NSArray arrayWithObject:path];
- [self.tableView insertRowsAtIndexPaths:arry withRowAnimation:UITableViewRowAnimationRight];
- }
- #pragma mark -
- #pragma mark ABPersonViewController 委托方法实现
- - (BOOL)personViewController:(ABPersonViewController *)personViewController
- shouldPerformDefaultActionForPerson:(ABRecordRef)person
- property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifierForValue
- {
- return YES;
- }
- #pragma mark -
- #pragma mark ABNewPersonViewController 委托方法实现
- - (void)newPersonViewController:(ABNewPersonViewController *)newPersonView
- didCompleteWithNewPerson:(ABRecordRef)person
- {
- NSString *name = CFBridgingRelease(ABRecordCopyCompositeName(person));
- [self.contactNames addObject:name];
- [self.contactIDs addObject:[NSNumber numberWithInt:ABRecordGetRecordID(person)]];
- [newPersonView dismissViewControllerAnimated:YES completion:nil];
- //取得最后一个放入contactIDs中的ID,也就是刚刚选择的ID
- NSIndexPath *path = [NSIndexPath indexPathForRow:self.contactIDs.count-1 inSection:0];
- //选中联系人插入到首页表视图中
- NSArray *arry = [NSArray arrayWithObject:path];
- [self.tableView insertRowsAtIndexPaths:arry withRowAnimation:UITableViewRowAnimationRight];
- }
- @end
隐藏
2 平衡球
2.1 问题
IOS可以通过内置的加速计知道用户握持设备的方式,以及用户是否移动了设备,Core Motion框架提供设备移动的所有值。本案例使用Core Motion框架完成一个平衡球的小游戏,用户移动设备小球会根据用户移动的方向滚动,用户保持小球滚动到终点而不碰撞到墙壁,如图-8所示:
图-8
2.2 方案
首先创建一个SingleViewApplication应用,在Storyboard文件中搭建界面,本案例中的场景中使用带有背景颜色的ImageView控件当做隔墙,然后左上角摆放一个小球,同样是ImageView控件。将所有隔墙关联成ViewController的IBOutletCollection属性walls,将小球关联成ViewController的IBOutlet属性ball。
其次在ViewController类扩展中定义两个私有属性CMMotionManager类型的motionManager和NSOperationQueue类型的queue。在viewDidLoad方法中对这两个属性进行初始化,motionManager将观察动作事件,它需要创建一个队列用做完成工作的容器。
接下来配置加速器,首先确保设备确实拥有加速器,然后设置更新频率为1/15s,最后使用startAccelerometerUpdatesToQueue:withHandler:方法告诉motionManager开始报告加速计更新,传入队列和代码块,队列中放置着每次发生更新时要完成的工作,代码块定义这些工作。
最后完成代码块中的代码,本案例中代码块中需要根据每次更新的数据计算出小球滚动的距离和方向,并且需要判断小球是否碰到墙壁,碰到墙壁则游戏结束重新开始,未碰撞到任何墙壁顺利到达终点则游戏成功。
2.3 步骤
实现此案例需要按照如下步骤进行。
步骤一:搭建界面
首先创建一个SingleViewApplication应用,在Storyboard文件中搭建界面,本案例中的场景中使用带有背景颜色的ImageView控件当做隔墙,然后左上角摆放一个小球,同样是ImageView控件。将所有隔墙关联成ViewController的IBOutletCollection属性walls,将小球关联成ViewController的IBOutlet属性ball,代码如下所示:
- @interface ViewController ()
- //终点位置
- @property (weak, nonatomic) IBOutlet UIImageView *green;
- @property (weak, nonatomic) IBOutlet UIImageView *red;
- @property (strong, nonatomic) IBOutletCollection(UIImageView) NSArray *walls;
- @property (weak, nonatomic) IBOutlet UIButton *ball;
- @end
在Storyboard中完成的界面如图-9所示:
图-9
步骤二:创建动作管理器
在ViewController类扩展中定义两个私有属性CMMotionManager类型的motionManager和NSOperationQueue类型的queue。在viewDidLoad方法中对这两个属性进行初始化,motionManager将观察动作事件,它需要创建一个队列用做完成工作的容器,代码如下所示:
- @property (nonatomic,strong) CMMotionManager *motionManager;
- @property (nonatomic,strong) NSOperationQueue *queue;
接下来配置加速器,首先确保设备确实拥有加速器,然后设置更新频率为1/15s,最后使用startAccelerometerUpdatesToQueue:withHandler:方法告诉motionManager开始报告加速计更新,传入队列和代码块,队列中放置着每次发生更新时要完成的工作,代码块定义这些工作,代码如下所示:
- - (void)viewDidLoad {
- [super viewDidLoad];
- self.motionManager = [[CMMotionManager alloc]init];
- self.queue = [[NSOperationQueue alloc]init];
- if (self.motionManager.accelerometerAvailable) {
- self.motionManager.accelerometerUpdateInterval = 1.0/15;
- [self.motionManager startAccelerometerUpdatesToQueue:self.queue withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) {
- }];
- }
- }
步骤三:实现小球滚动功能
在代码块中实现小球滚动功能,需要根据每次更新的accelerometerData.acceleration数据计算出小球滚动的距离和方向,然后回到主线程更新界面,需要判断小球是否碰到墙壁,碰到墙壁则游戏结束重新开始,未碰撞到任何墙壁顺利到达终点则游戏成功,代码如下所示:
- - (void)viewDidLoad {
- [super viewDidLoad];
- self.motionManager = [[CMMotionManager alloc]init];
- self.queue = [[NSOperationQueue alloc]init];
- if (self.motionManager.accelerometerAvailable) {
- self.motionManager.accelerometerUpdateInterval = 1.0/15;
- // [self.motionManager startAccelerometerUpdates];
- [self.motionManager startAccelerometerUpdatesToQueue:self.queue withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) {
- //计算小球滚动的距离
- float x = oldx+.2*accelerometerData.acceleration.x;
- float y = oldy+.2*accelerometerData.acceleration.y;
- NSLog(@"%f,%f",accelerometerData.acceleration.x,accelerometerData.acceleration.y);
- NSArray *array = @[@(x),@(y)];
- //回到主线程更新界面
- [self performSelectorOnMainThread:@selector(moveBall:) withObject:array waitUntilDone:NO];
- }];
- }
- //记录小球最开始的中心点,游戏重新开始将回到该位置
- p = self.ball.center;
- //屏幕尺寸
- scrennSize = [UIScreen mainScreen].bounds.size;
- }
- -(void)moveBall:(NSArray*)array {
- float x = [array[0] floatValue];
- float y = [array[1] floatValue];
- self.ball.center = CGPointMake(self.ball.center.x+x,self.ball.center.y-y);
- oldx = x;
- oldy = y;
- //判断小球是否碰撞到屏幕两边需要改变方向
- if (self.ball.frame.origin.x<=0) {
- self.ball.frame = CGRectMake(0, self.ball.frame.origin.y, self.ball.frame.size.width, self.ball.frame.size.height);
- oldx = -oldx*.1;
- }else if (self.ball.frame.origin.x>=(scrennSize.width-self.ball.frame.size.width)) {
- self.ball.frame = CGRectMake((scrennSize.width-self.ball.frame.size.width), self.ball.frame.origin.y, self.ball.frame.size.width, self.ball.frame.size.height);
- oldx = -oldx*.1;
- }
- if (self.ball.frame.origin.y<=0) {
- self.ball.frame = CGRectMake(self.ball.frame.origin.x, 0, self.ball.frame.size.width, self.ball.frame.size.height);
- oldy = -oldy*.1;
- }else if (self.ball.frame.origin.y>=(scrennSize.height-self.ball.frame.size.height)) {
- self.ball.frame = CGRectMake(self.ball.frame.origin.x,(scrennSize.height-self.ball.frame.size.height), self.ball.frame.size.width, self.ball.frame.size.height);
- oldy = -oldy*.1;
- }
- //判断是否与墙壁有碰撞
- for (UIImageView *wall in self.walls) {
- if (CGRectIntersectsRect(self.ball.frame, wall.frame)) {
- UIAlertView *av = [[UIAlertView alloc]initWithTitle:@"提示" message:@"Game Over" delegate:self cancelButtonTitle:@"确定" otherButtonTitles:@"重新开始", nil];
- [av show];
- self.ball.center = p;
- return;
- }
- }
- if (CGRectIntersectsRect(self.ball.frame, self.green.frame)) {
- UIAlertView *av = [[UIAlertView alloc]initWithTitle:@"提示" message:@"Successful" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:@"重新开始", nil];
- [av show];
- return;
- }else if (CGRectIntersectsRect(self.ball.frame, self.red.frame)) {
- UIAlertView *av = [[UIAlertView alloc]initWithTitle:@"提示" message:@"fair" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:@"重新开始", nil];
- [av show];
- return;
- }
- }
- -(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
- if (buttonIndex==1) {
- self.ball.center = p;
- }
- }
最后不要忘记放置手机屏幕旋转和隐藏状态栏,代码如下所示:
- -(NSUInteger)supportedInterfaceOrientations {
- r%turn UIInterfaceOrientationMaskPortrait;
- }
- -(BOOL)prdfersStatuSBarHidden { return YES;
- }
完成效果如图-10,图-11所示:
图 10
图-11
2.4 完整代码
本案例中,ViewController.m文件中的完整代码如下所示:
#import "ViewController.h" #import <CoreMotion/CoreMotion.h> @interface ViewController (){ CGPoint p; float oldx; float oldy; CGSize scrennSize; } @property (nonatomic,strong) CMMotionManager *motionManager; @property (nonatomic,strong) NSOperationQueue *queue; @property (weak, nonatomic) IBOutlet UIImageView *green; @property (weak, nonatomic) IBOutlet UIImageView *red; @property (strong, nonatomic) IBOutletCollection(UIImageView) NSArray *walls; @property (weak, nonatomic) IBOutlet UIButton *ball; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; self.motionManager = [[CMMotionManager alloc]init]; self.queue = [[NSOperationQueue alloc]init]; if (self.motionManager.accelerometerAvailable) { self.motionManager.accelerometerUpdateInterval = 1.0/15; // [self.motionManager startAccelerometerUpdates]; [self.motionManager startAccelerometerUpdatesToQueue:self.queue withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) { //计算小球滚动的距离 float x = oldx+.2*accelerometerData.acceleration.x; float y = oldy+.2*accelerometerData.acceleration.y; NSLog(@"%f,%f",accelerometerData.acceleration.x,accelerometerData.acceleration.y); NSArray *array = @[@(x),@(y)]; //回到主线程更新界面 [self performSelectorOnMainThread:@selector(moveBall:) withObject:array waitUntilDone:NO]; }]; } //记录小球最开始的中心点,游戏重新开始将回到该位置 p = self.ball.center; //屏幕尺寸 scrennSize = [UIScreen mainScreen].bounds.size; } -(void)moveBall:(NSArray*)array { float x = [array[0] floatValue]; float y = [array[1] floatValue]; self.ball.center = CGPointMake(self.ball.center.x+x,self.ball.center.y-y); oldx = x; oldy = y; //判断小球是否碰撞到屏幕两边需要改变方向 if (self.ball.frame.origin.x<=0) { self.ball.frame = CGRectMake(0, self.ball.frame.origin.y, self.ball.frame.size.width, self.ball.frame.size.height); oldx = -oldx*.1; }else if (self.ball.frame.origin.x>=(scrennSize.width-self.ball.frame.size.width)) { self.ball.frame = CGRectMake((scrennSize.width-self.ball.frame.size.width), self.ball.frame.origin.y, self.ball.frame.size.width, self.ball.frame.size.height); oldx = -oldx*.1; } if (self.ball.frame.origin.y<=0) { self.ball.frame = CGRectMake(self.ball.frame.origin.x, 0, self.ball.frame.size.width, self.ball.frame.size.height); oldy = -oldy*.1; }else if (self.ball.frame.origin.y>=(scrennSize.height-self.ball.frame.size.height)) { self.ball.frame = CGRectMake(self.ball.frame.origin.x,(scrennSize.height-self.ball.frame.size.height), self.ball.frame.size.width, self.ball.frame.size.height); oldy = -oldy*.1; } //判断是否与墙壁有碰撞 for (UIImageView *wall in self.walls) { if (CGRectIntersectsRect(self.ball.frame, wall.frame)) { UIAlertView *av = [[UIAlertView alloc]initWithTitle:@"提示" message:@"Game Over" delegate:self cancelButtonTitle:@"确定" otherButtonTitles:@"重新开始", nil]; [av show]; self.ball.center = p; return; } } if (CGRectIntersectsRect(self.ball.frame, self.green.frame)) { UIAlertView *av = [[UIAlertView alloc]initWithTitle:@"提示" message:@"Successful" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:@"重新开始", nil]; [av show]; return; }else if (CGRectIntersectsRect(self.ball.frame, self.red.frame)) { UIAlertView *av = [[UIAlertView alloc]initWithTitle:@"提示" message:@"fair" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:@"重新开始", nil]; [av show]; return; } } -(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { if (buttonIndex==1) { self.ball.center = p; } } -(NSUInteger)supportedInterfaceOrientations { return UIInterfaceOrientationMaskPortrait; } -(BOOL)prefersStatusBarHidden { return YES; } @end