笔者在写一款运动跑步软件,因为自己本身也比较喜欢运动,没事也总会跑步,但是发现一个问题,每次我跑步的时候,我总是喜欢看看当前的详细数据,但是要从兜里把手机拿出来,拿出来也就算了,还得解锁...太麻烦了。怎么办? 最后想到的办法是可不可以把运动数据详细的展示在手机的锁屏上,这样只要点亮屏幕就可以了,少了一步解锁。先不管产品有没有这个需求,先搞出来这个功能,自己用着也是爽啊
完成的效果是这样的,而且数据是实时改变的,会把用户选择的3项数据展示出来。
显示歌曲信息等数据
我是把音乐的控制写在了一个单利类里了,类继承UIResponder
设置锁屏状态,在歌曲切换到时候调用下面的方法,把对应的歌曲参数添加过去就可以了
-(void)configNowPlayingInfoCenter{
if (NSClassFromString(@"MPNowPlayingInfoCenter")) {
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
//歌曲名称
[dict setObject:@"爱" forKey:MPMediaItemPropertyTitle];
//演唱者
[dict setObject:@"idage" forKey:MPMediaItemPropertyArtist];
//专辑名
[dict setObject:@"idage163" forKey:MPMediaItemPropertyAlbumTitle];
//图片
MPMediaItemArtwork *artwork = [[MPMediaItemArtwork alloc] initWithImage:[[UIImage alloc]init]];
[dict setObject:artwork forKey:MPMediaItemPropertyArtwork];
//音乐剩余时长
[dict setObject:[NSNumber numberWithDouble:3.5] forKey:MPMediaItemPropertyPlaybackDuration];
//设置锁屏状态下屏幕显示播放音乐信息
[[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:dict];
}
}
还要成为第一响应者
-(BOOL)canBecomeFirstResponder {
return YES;
}
在appdelegate里添加
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
然后实现方法
#pragma mark -响应远程音乐播放控制消息
- (void)remoteControlReceivedWithEvent:(UIEvent *)receivedEvent {
if (receivedEvent.type == UIEventTypeRemoteControl) {
NSNumber *type = nil;
switch (receivedEvent.subtype) {
case UIEventSubtypeRemoteControlPlay:
// 播放
break;
case UIEventSubtypeRemoteControlPause:
//暂停
break;
case UIEventSubtypeRemoteControlNextTrack:
//下一曲
break;
case UIEventSubtypeRemoteControlPreviousTrack:
//上一曲
break;
default:
break;
}
}
}
这样就可以控制音乐的动作了,一个音乐锁屏界面就算完成了
显示运动信息等数据
想把运动信息实时更新到锁屏界面歌曲图片的位置,唯一的办法就是当数据改变的时候,合成一张图片设置到锁屏界面上。锁屏界面显示歌词也是这个原理,系统并没有提供更新歌词到锁屏界面的API。
截图
-(void)captureScreen{
UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 1);
[self.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *bgBlackImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData *bgBlackdata = UIImagePNGRepresentation(bgBlackImage);
UIImage *bgBlackimg = [UIImage imageWithData:bgBlackdata];//生成的图片
}
然后每次数据更新的时候把图片调用上面的方法更新到锁屏界面上
优化性能
功能似乎已经实现了,但是太耗性能了,每秒钟都改变数据 岂不是每秒钟都得合成图片?这样显然是不行的。
一种做法是监听程序进入后台,如果进入后台了数据再改变则更新图片,但是万一我跑步一直锁屏呢?那还不是一直合成图片?
最好的办法是当手机显示解锁的状态的时候才合成图片,这样只有用户点亮屏幕的时候才调用。方法是使用Darwin层的通知可以监听到锁屏的状态
#import <notify.h>
static uint64_t lockStates ;
static void updateEnabled(CFNotificationCenterRef center, void* observer, CFStringRef name, const void* object, CFDictionaryRef userInfo) {
uint64_t state;
int token;
notify_register_check("com.apple.iokit.hid.displayStatus", &token);
notify_get_state(token, &state);
notify_cancel(token);
lockStates = state;
// NSLog(@"锁屏状态:%llu",state);
}
lockStates==1的时候就是已经正在解锁的状态 。再加上一些项目的处理逻辑就可以了。
喜欢跑步的可以下个软件玩一玩,名字是Runbone