iOS开发系列之远程控制事件
在今天的文章中还剩下最后一类事件:远程控制,远程控制事件这里主要说的就是耳机线控操作。在前面的事件列表中,大家可以看到在iOS中和远程控制事件有关的只有一个- (void)remoteControlReceivedWithEvent:(UIEvent *)event NS_AVAILABLE_IOS(4_0);事件。要监听到这个事件有三个前提(视图控制器UIViewController或应用程序UIApplication只有两个)
启用远程事件接收(使用[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];方法)。
对于UI控件同样要求必须是第一响应者(对于视图控制器UIViewController或者应用程序UIApplication对象监听无此要求)。
应用程序必须是当前音频的控制者,也就是在iOS 7中通知栏中当前音频播放程序必须是我们自己开发程序。
基于第三点我们必须明确,如果我们的程序不想要控制音频,只是想利用远程控制事件做其他的事情,例如模仿iOS7中的按音量+键拍照是做不到的,目前iOS7给我们的远程控制权限还仅限于音频控制(当然假设我们确实想要做一个和播放音频无关的应用但是又想进行远程控制,也可以隐藏一个音频播放操作,拿到远程控制操作权后进行远程控制)。
运动事件中我们也提到一个枚举类型UIEventSubtype,而且我们利用它来判断是否运动事件,在枚举中还包含了我们运程控制的子事件类型,我们先来熟悉一下这个枚举(从远程控制子事件类型也不难发现它和音频播放有密切关系):
typedef NS_ENUM(NSInteger, UIEventSubtype) {
// 不包含任何子事件类型
UIEventSubtypeNone = 0,
// 摇晃事件(从iOS3.0开始支持此事件)
UIEventSubtypeMotionShake = 1,
//远程控制子事件类型(从iOS4.0开始支持远程控制事件)
//播放事件【操作:停止状态下,按耳机线控中间按钮一下】
UIEventSubtypeRemoteControlPlay = 100,
//暂停事件
UIEventSubtypeRemoteControlPause = 101,
//停止事件
UIEventSubtypeRemoteControlStop = 102,
//播放或暂停切换【操作:播放或暂停状态下,按耳机线控中间按钮一下】
UIEventSubtypeRemoteControlTogglePlayPause = 103,
//下一曲【操作:按耳机线控中间按钮两下】
UIEventSubtypeRemoteControlNextTrack = 104,
//上一曲【操作:按耳机线控中间按钮三下】
UIEventSubtypeRemoteControlPreviousTrack = 105,
//快退开始【操作:按耳机线控中间按钮三下不要松开】
UIEventSubtypeRemoteControlBeginSeekingBackward = 106,
//快退停止【操作:按耳机线控中间按钮三下到了快退的位置松开】
UIEventSubtypeRemoteControlEndSeekingBackward = 107,
//快进开始【操作:按耳机线控中间按钮两下不要松开】
UIEventSubtypeRemoteControlBeginSeekingForward = 108,
//快进停止【操作:按耳机线控中间按钮两下到了快进的位置松开】
UIEventSubtypeRemoteControlEndSeekingForward = 109,
};
这里我们将远程控制事件放到视图控制器(事实上很少直接添加到UI控件,一般就是添加到UIApplication或者UIViewController),模拟一个音乐播放器。
1.首先在应用程序启动后设置接收远程控制事件,并且设置音频会话保证后台运行可以播放(注意要在应用配置中设置允许多任务)
//
// AppDelegate.m
// TouchEventAndGesture
//
// Created by Kenshin Cui on 14-3-16.
// Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//
#import "AppDelegate.h"
#import "ViewController.h"
#import <AVFoundation/AVFoundation.h>
#import "KCApplication.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
_window=[[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
_window.backgroundColor =[UIColor colorWithRed:249/255.0 green:249/255.0 blue:249/255.0 alpha:1];
//设置全局导航条风格和颜色
[[UINavigationBar appearance] setBarTintColor:[UIColor colorWithRed:23/255.0 green:180/255.0 blue:237/255.0 alpha:1]];
[[UINavigationBar appearance] setBarStyle:UIBarStyleBlack];
ViewController *mainController=[[ViewController alloc]init];
_window.rootViewController=mainController;
//设置播放会话,在后台可以继续播放(还需要设置程序允许后台运行模式)
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
if(![[AVAudioSession sharedInstance] setActive:YES error:nil])
{
NSLog(@"Failed to set up a session.");
}
//启用远程控制事件接收
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
// [self becomeFirstResponder];
[_window makeKeyAndVisible];
return YES;
}
//-(void)remoteControlReceivedWithEvent:(UIEvent *)event{
// NSLog(@"remote");
//}
- (void)applicationWillResignActive:(UIApplication *)application {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
[[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:nil];
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
@end
2.在视图控制器中添加远程控制事件并音频播放进行控制
//
// ViewController.m
// RemoteEvent
//
// Created by Kenshin Cui on 14-3-16.
// Copyright (c) 2014年 Kenshin Cui. All rights reserved.
//
#import "ViewController.h"
@interface ViewController (){
UIButton *_playButton;
BOOL _isPlaying;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self initLayout];
}
-(BOOL)canBecomeFirstResponder{
return NO;
}
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
_player = [[AVPlayer alloc] initWithURL:[NSURL URLWithString:@"http://stream.jewishmusicstream.com:8000"]];
//[_player play];
//_isPlaying=true;
}
#pragma mark 远程控制事件
-(void)remoteControlReceivedWithEvent:(UIEvent *)event{
NSLog(@"%i,%i",event.type,event.subtype);
if(event.type==UIEventTypeRemoteControl){
switch (event.subtype) {
case UIEventSubtypeRemoteControlPlay:
[_player play];
_isPlaying=true;
break;
case UIEventSubtypeRemoteControlTogglePlayPause:
if (_isPlaying) {
[_player pause];
}else{
[_player play];
}
_isPlaying=!_isPlaying;
break;
case UIEventSubtypeRemoteControlNextTrack:
NSLog(@"Next...");
break;
case UIEventSubtypeRemoteControlPreviousTrack:
NSLog(@"Previous...");
break;
case UIEventSubtypeRemoteControlBeginSeekingForward:
NSLog(@"Begin seek forward...");
break;
case UIEventSubtypeRemoteControlEndSeekingForward:
NSLog(@"End seek forward...");
break;
case UIEventSubtypeRemoteControlBeginSeekingBackward:
NSLog(@"Begin seek backward...");
break;
case UIEventSubtypeRemoteControlEndSeekingBackward:
NSLog(@"End seek backward...");
break;
default:
break;
}
[self changeUIState];
}
}
#pragma mark 界面布局
-(void)initLayout{
//专辑封面
UIImage *image=[UIImage imageNamed:@"wxl.jpg"];
UIImageView *imageView=[[UIImageView alloc]initWithFrame:[UIScreen mainScreen].applicationFrame];
imageView.image=image;
imageView.contentMode=UIViewContentModeScaleAspectFill;
[self.view addSubview:imageView];
//播放控制面板
UIView *view=[[UIView alloc]initWithFrame:CGRectMake(0, 480, 320, 88)];
view.backgroundColor=[UIColor lightGrayColor];
view.alpha=0.9;
[self.view addSubview:view];
//添加播放按钮
_playButton=[UIButton buttonWithType:UIButtonTypeCustom];
_playButton.bounds=CGRectMake(0, 0, 50, 50);
_playButton.center=CGPointMake(view.frame.size.width/2, view.frame.size.height/2);
[self changeUIState];
[_playButton addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
[view addSubview:_playButton];
}
#pragma mark 界面状态
-(void)changeUIState{
if(_isPlaying){
[_playButton setImage:[UIImage imageNamed:@"playing_btn_pause_n.png"] forState:UIControlStateNormal];
[_playButton setImage:[UIImage imageNamed:@"playing_btn_pause_h.png"] forState:UIControlStateHighlighted];
}else{
[_playButton setImage:[UIImage imageNamed:@"playing_btn_play_n.png"] forState:UIControlStateNormal];
[_playButton setImage:[UIImage imageNamed:@"playing_btn_play_h.png"] forState:UIControlStateHighlighted];
}
}
-(void)btnClick:(UIButton *)btn{
if (_isPlaying) {
[_player pause];
}else{
[_player play];
}
_isPlaying=!_isPlaying;
[self changeUIState];
}
@end
运行效果(真机截图):
注意:
为了模拟一个真实的播放器,程序中我们启用了后台运行模式,配置方法:在info.plist中添加UIBackgroundModes并且添加一个元素值为audio。
即使利用线控进行音频控制我们也无法监控到耳机增加音量、减小音量的按键操作(另外注意模拟器无法模拟远程事件,请使用真机调试)。
子事件的类型跟当前音频状态有直接关系,点击一次播放/暂停按钮究竟是【播放】还是【播放/暂停】状态切换要看当前音频处于什么状态,如果处于停止状态则点击一下是播放,如果处于暂停或播放状态点击一下是暂停和播放切换。
上面的程序已在真机调试通过,无论是线控还是点击应用按钮都可以控制播放或暂停。
iOS开发系列之远程控制事件的更多相关文章
- iOS开发系列之触摸事件
基础知识 三类事件中触摸事件在iOS中是最常用的事件,这里我们首先介绍触摸事件. 在下面的例子中定义一个KCImage,它继承于UIView,在KCImage中指定一个图片作为背景.定义一个视图控制器 ...
- iOS开发系列之运动事件
前面我们主要介绍了触摸事件以及由触摸事件引出的手势识别,下面我们简单介绍一下运动事件.在iOS中和运动相关的有三个事件:开始运动.结束运动.取消运动. 监听运动事件对于UI控件有个前提就是监听对象必须 ...
- iOS开发系列文章(持续更新……)
iOS开发系列的文章,内容循序渐进,包含C语言.ObjC.iOS开发以及日后要写的游戏开发和Swift编程几部分内容.文章会持续更新,希望大家多多关注,如果文章对你有帮助请点赞支持,多谢! 为了方便大 ...
- iOS开发系列--App扩展开发
概述 从iOS 8 开始Apple引入了扩展(Extension)用于增强系统应用服务和应用之间的交互.它的出现让自定义键盘.系统分享集成等这些依靠系统服务的开发变成了可能.WWDC 2016上众多更 ...
- iOS开发系列--通知与消息机制
概述 在多数移动应用中任何时候都只能有一个应用程序处于活跃状态,如果其他应用此刻发生了一些用户感兴趣的那么通过通知机制就可以告诉用户此时发生的事情.iOS中通知机制又叫消息机制,其包括两类:一类是本地 ...
- iOS开发系列--网络开发
概览 大部分应用程序都或多或少会牵扯到网络开发,例如说新浪微博.微信等,这些应用本身可能采用iOS开发,但是所有的数据支撑都是基于后台网络服务器的.如今,网络编程越来越普遍,孤立的应用通常是没有生命力 ...
- iOS开发系列--让你的应用“动”起来
--iOS核心动画 概览 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥iOS动画全貌.在这里你可以看到iOS中如何使用图层精简非交互式绘图,如何通过核心动画创建 ...
- iOS开发系列--并行开发其实很容易
--多线程开发 概览 大家都知道,在开发过程中应该尽可能减少用户等待时间,让程序尽可能快的完成运算.可是无论是哪种语言开发的程序最终往往转换成汇编语言进而解释成机器码来执行.但是机器码是按顺序执行的, ...
- iOS开发系列--让你的应用“动”起来
--iOS核心动画 概览 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥iOS动画全貌.在这里你可以看到iOS中如何使用图层精简非交互式绘图,如何通过核心动画创建 ...
随机推荐
- 安装 mysql server
三个月前向公司申请了一台服务器单独给我用,作为部署我写的自动发布工具的服务器.同事不久前在我这台服务器上装了个数据库,今天上去查了一下,用不了,只有information_schema和test两个数 ...
- [151225] Python3 实现最大堆、堆排序,解决TopK问题
参考资料: 1.算法导论,第6章,堆排序 堆排序学习笔记及堆排序算法的python实现 - 51CTO博客 堆排序 Heap Sort - cnblogs 小根堆实现优先队列:Python实现 -cn ...
- House of hello恶搞凯莉迷你包
欧洲站 House of hello恶搞凯莉迷你包 最近淘宝卖的很疯,看看价格,俺咂舌不已 :1300-1600 今年迷你包卖的很疯我是知道的,迷你包今年没有买一个也是不行的! 剔除暴利,便宜的亲们不 ...
- LINUX HA:Pacemaker + Corosync初配成功
参考很多文档: http://zhumeng8337797.blog.163.com/blog/static/100768914201218115650522/ 下一步,想想这个PC组和与HAPROX ...
- 一句话改变TWinControl控件的left坐标的前世今生(入口函数是SetBounds,然后调用SetWindowPos起作用,并发消息更新Delphi的left属性值)
Delphi的重要属性,主要是Enable, Visible, Color, left等等.这里分析left,因为TWinControl里有些覆盖函数的原因,虽然起点都是TControl.SetLe ...
- CN消息的来源——父窗口不知道怎么处理,于是把这个消息加上CN_BASE在分发到实际的子窗体
VCL存在一些非API消息以供其内部使用,为什么要这样做呢?这要从WM_COMMAND & WM_NOTIFY消息说起,我们说WM_COMMAND消息并不是直接发给实际产生消息的窗体,而是发送 ...
- 分页SQL模板
select * from ( select rownum as rn ,a.* from ( select * from page a where object_id >1000 and ow ...
- War3Tool dota改键v3.3版
wartool魔兽全屏改键功能:1.支持11平台自定义改建,自动进局域网(同类软件暂时没发现这个功能)2.技能改键,可以有效的切换适合你的技能键3.war3路径扫描,运行本程序一键就能打开war3 ( ...
- 五种I/O 模式——阻塞(默认IO模式),非阻塞(常用语管道),I/O多路复用(IO多路复用的应用场景),信号I/O,异步I/O
五种I/O 模式——阻塞(默认IO模式),非阻塞(常用语管道),I/O多路复用(IO多路复用的应用场景),信号I/O,异步I/O 五种I/O 模式:[1] 阻塞 I/O ...
- 源码安装Ansible
一.Ansible介绍 ansible是一款的自动化运维工具,基于Python开发,集合了众多运维工具(puppet.cfengine.chef.func.fabric)的优点,实现了批量系统配置.批 ...