网易云音乐锁屏界面效果实现

Posted brave-sailor

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网易云音乐锁屏界面效果实现相关的知识,希望对你有一定的参考价值。

最终效果:

技术分享图片

完整的实现思路:

  1. App如果需要在锁屏界面上显示相关的信息和按钮, 必须先开启远程控制事件(Remote Control Event), 否则锁屏界面只显示滑动解锁.
  2. 实现锁屏界面信息, 将歌曲的相关信息更新到锁屏界面上
  3. 实现锁屏界面的事件处理, 在锁屏界面和上拉的快速功能菜单中实现播放控制

远程控制事件的实现

ios7.1之前, 远程控制事件主要涉及以下三个方法:

  • 开始接收远程控制事件
  • 结束接收远程控制事件
  • 触发远程控制事件后的捕获处理

官方文档对这三个方法的描述如下, 这里做了简单的翻译.

开始接收远程控制事件

Declaration
- (void)beginReceivingRemoteControlEvents

让App开始接收远程控制事件, 该方法属于UIApplication类

Discussion

在iOS7.1之后, 使用MPRemoteCommandCenter的共享对象来注册远程控制事件. 当使用shared command center时, 不需要再调用该方法.
该方法会开始使用事件响应链来传递远程控制事件. 远程控制事件是当耳机和外部附件意图控制App的多媒体表现时发出的命令. 要停止远程控制事件的接收, 必须调用endReceivingRemoteControlEvents方法

结束接收远程控制事件

Declaration
- (void)endReceivingRemoteControlEvents 

让App停止接收远程控制事件, 该方法属于UIApplication类

Discussion

在iOS7.1之前, 使用shared MPRemoteCommandCenter对象来注册远程控制事件. 当使用shared command center时, 不需要再调用该方法. 该方法会停止通过事件响应链来传递远程控制事件. 远程控制事件是当耳机和外部附件意图控制App的多媒体表现时发出的命令.

远程控制事件的捕获处理

Declaration
- (void)remoteControlReceivedWithEvent:(UIEvent *)event

当远程控制事件发生时触发该方法, 该方法属于UIResponder类

Discussion

远程控制事件是由外部附件(包括耳机)所发出的命令. 应用需要响应这些命令来控制音频或视频媒体的对用户的表示. 事件响应者通过检查事件的subtype, 来判断命令的意图. 比如UIEventSubtypeRemoteControlPlay为播放操作, 然后做相关处理

要允许远程控制事件的传递, 需要调用UIApplication的beginReceivingRemoteControlEvents方法; 要关闭远程控制事件的传递则调用endReceivingRemoteControlEvents

项目中的代码实现

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // 在App启动后开启远程控制事件, 接收来自锁屏界面和上拉菜单的控制
    [application beginReceivingRemoteControlEvents];

    return YES;
}

- (void)applicationWillTerminate:(UIApplication *)application
{
    // 在App要终止前结束接收远程控制事件, 也可以在需要终止时调用该方法终止
    [application endReceivingRemoteControlEvents];
}

// 在具体的控制器或其它类中捕获处理远程控制事件
- (void)remoteControlReceivedWithEvent:(UIEvent *)event
{
    // 根据事件的子类型(subtype) 来判断具体的事件类型, 并做出处理
    switch (event.subtype) {
        case UIEventSubtypeRemoteControlPlay:
        case UIEventSubtypeRemoteControlPause: {
            // 执行播放或暂停的相关操作 (锁屏界面和上拉快捷功能菜单处的播放按钮)
            break;
        }
        case UIEventSubtypeRemoteControlPreviousTrack: {
            // 执行上一曲的相关操作 (锁屏界面和上拉快捷功能菜单处的上一曲按钮)
            break;
        }
        case UIEventSubtypeRemoteControlNextTrack: {
            // 执行下一曲的相关操作 (锁屏界面和上拉快捷功能菜单处的下一曲按钮)
            break;
        }
        case UIEventSubtypeRemoteControlTogglePlayPause: {
            // 进行播放/暂停的相关操作 (耳机的播放/暂停按钮)
            break;
        }
        default:
            break;
    }
}

iOS7.1后, 更新了远程控制事件的实现方式

相关方法的描述中, 已经说明, iOS7.1之后使用MPRemoteCommandCenter类来进行远程控制事件的相关处理, 因此可以不再使用上面所描述的三个方法. 官方文档对MPRemoteCommandCenter的描述如下:

MPRemoteCommandCenter

MPRemoteCommandCenter类提供了处理远程控制事件的对象, 包括由外部附件和系统传输控制发送的远程控制事件. 不需要自己创建该类的实例. 而是使用shareCommandCenter方法获取默认的命令中心(share command center)对象. share command center对象的属性包含了MPRemoteCommand对象(表示iOS支持的每种远程控件事件). 如果要对响应的事件特殊处理, 使用适当的MPRemoteCommand对象注册一个handler即可.

远程命令中心(remote command center)对象为许多不同类型的事件提供了命令(command)对象. 如果你的App不需要支持某些特定类型的事件, 可以通过设置其enabled属性为NO来禁用关联的MPRemoteCommand对象. 使用command对象注册一个handler, 以便让系统知道你的App已经做好了接收事件的准备. 只有当你的App是当前正在播放(Now Playing App)时才能接收到事件的传递.

项目中的代码实现 :

// 在需要处理远程控制事件的具体控制器或其它类中实现
- (void)remoteControlEventHandler
{
    // 直接使用sharedCommandCenter来获取MPRemoteCommandCenter的shared实例
    MPRemoteCommandCenter *commandCenter = [MPRemoteCommandCenter sharedCommandCenter];

    // 启用播放命令 (锁屏界面和上拉快捷功能菜单处的播放按钮触发的命令)
    commandCenter.playCommand.enabled = YES;
    // 为播放命令添加响应事件, 在点击后触发
    [commandCenter.playCommand addTarget:self action:@selector(playAction:)];

    // 播放, 暂停, 上下曲的命令默认都是启用状态, 即enabled默认为YES
    // 为暂停, 上一曲, 下一曲分别添加对应的响应事件
    [commandCenter.pauseCommand addTarget:self action:@selector(pauseAction:)];
    [commandCenter.previousTrackCommand addTarget:self action:@selector(previousTrackAction:)];
    [commandCenter.nextTrackCommand addTarget:self action:@selector(nextTrackAction:)];

    // 启用耳机的播放/暂停命令 (耳机上的播放按钮触发的命令)
    commandCenter.togglePlayPauseCommand.enabled = YES;
    // 为耳机的按钮操作添加相关的响应事件
    [commandCenter.togglePlayPauseCommand addTarget:self action:@selector(playOrPauseAction:)];
}
效果如图:

技术分享图片

锁屏界面相关信息更新

实现了远程控制事件后, App在进行音乐播放时, 上拉快捷功能菜单都会提供远程控件按钮, 锁屏界面会有改动, 出现远程控制按钮, 以及歌曲进度等信息, 接下来需要将歌曲的相关信息更新到锁屏界面上. 主要通过MPNowPlayingInfoCenter类来实现, 下面是官方文档的描述:

MPNowPlayingInfoCenter

使用now playing info center来设置App当前正在播放的媒体文件的信息(now-playing information).

系统会在设备的锁屏界面和上划的快捷控制面板的多媒体控制部分显示当前播放文件的信息. 如果用户直接通过AirPlay在Apple TV上播放媒体文件时, now-playing信息会显示在电视屏幕上. 如果用户将设备连接到iPad附件, 比如汽车(通过CarPlay连接)上, 附件上可能会显示now-playing的信息.

你不能直接控制哪些信息要被显示出来, 以及这些信息显示的样式. 只需要设置now playing info center dictionary的相关value, 将这些相关信息提交给系统即可. 系统或已经连接的附件, 会用一致的方式为所有的App处理这些信息的展示.

可以配置的锁屏界面信息

可以使用的information属性, 是定义在MPMediaItem类的General Media Item Property Keys属性中的子集(即其中的某些属性). 在iOS5.0后, now playing info center支持下列media item属性的Key: (仅列举了常用的Key!)

  • MPMediaItemPropertyAlbumTitle 专辑的标题, value是NSString对象
  • MPMediaItemPropertyArtist media item的创作者, value是NSString对象
  • MPMediaItemPropertyArtwork media item的插图. value是MPMediaItemArtwork类的对象
  • MPMediaItemPropertyPlaybackDuration media item的播放总时长. value是表示包装了时长秒数(NSTimeInterval)的NSNumber类型
  • MPMediaItemPropertyTitle media item的名字或标题. 该属性与MPMediaItemPropertyAlbumTitle属性无关, value是NSString对象

额外添加的一些可以使用的属性在MPNowPlayingInfoCenter类的描述文档中的Additional Metadata Properties中作了声明. (仅列举了常用的Key!)

  • MPNowPlayingInfoPropertyElapsedPlaybackTime 当前播放的item所消逝的时间(歌曲当前时间), 单位为秒. value是包装了double值的NSNumber对象. elapsed time是由系统根据之前提供elapsed tiime和playback rate进行自动进行计算的. 请不要频繁的更新该属性, 这是没有必要的.
  • MPNowPlayingInfoPropertyPlaybackRate 当前播放的item的播放速率, value为1.0表示正常的播放速率. value是包装了double值的NSNumber对象. 默认值是1.0. playback rate的值为2.0表示普通播放速率的2倍; 此时media从播放到结束只需要一半时间.

项目中的代码实现

- (void)updatelockScreenInfo 
{
    // 直接使用defaultCenter来获取MPNowPlayingInfoCenter的默认唯一实例
    MPNowPlayingInfoCenter *infoCenter = [MPNowPlayingInfoCenter defaultCenter];

    // MPMediaItemArtwork 用来表示锁屏界面图片的类型
    MPMediaItemArtwork *artwork = [[MPMediaItemArtwork alloc]     initWithImage:image];

    // 通过配置nowPlayingInfo的值来更新锁屏界面的信息
    infoCenter.nowPlayingInfo = @{
                                  // 歌曲名
                                  MPMediaItemPropertyTitle : music.name,
                                  // 艺术家名
                                  MPMediaItemPropertyArtist : music.singer,
                                  // 专辑名字
                                  MPMediaItemPropertyAlbumTitle : music.album,
                                  // 歌曲总时长 
                                  MPMediaItemPropertyPlaybackDuration : @(duration),
                                  // 歌曲的当前时间
                                  MPNowPlayingInfoPropertyElapsedPlaybackTime : @(currentTime),
                                  // 歌曲的插图, 类型是MPMeidaItemArtwork对象
                                  MPMediaItemPropertyArtwork : artwork,

                                  // 无效的, 歌词的展示是通过图片绘制完成的, 即将歌词绘制到歌曲插图, 通过更新插图来实现歌词的更新的
                                  // MPMediaItemPropertyLyrics : lyric.content,
                                  };
}
效果如图:

技术分享图片

类似网易新闻的锁屏控制按钮实现

通过上述代码实现后, 锁屏界面已经可以展示出歌曲信息与控制按钮, 通过按钮或耳机的按键也可以实现相关的控制效果. 但网易的控制按钮中最左边并是上一曲, 而是列表按钮, 点击后还能在锁屏界面弹出一个ActionSheet界面. 该功能其实是通过修改MPRemoteCommandCenter的反馈功能(提供喜欢, 不喜欢, 标记(bookmark)操作)来实现的.

涉及到的反馈功能, 先了解MPFeedbackCommond这个类, 以下是文档的描述

MPFeedbackCommond

MPFeedbackCommand对象反映了当前App所播放的反馈状态. MPRemoteCommandCenter对象提供feedback对象用于对媒体文件进行喜欢, 不喜欢, 标记的操作. 使用这些对象为App支持的回馈(feedback)方式进行注册handler, 并在反馈状态修改时执行适当的任务(task). 在当前播放的item改变时, 也可以使用该对象为新的item设置反馈状态.

当item的反馈状态改变时, 系统传递适当的事件到该对象注册的handler上. handler的代码必须决定哪一个media item来接收反馈, 然后再为该item执行更新反馈状态的操作. 你也可以执行与接收到反馈相关的其它任务. 比如, 当用户喜欢当前播放的歌曲时你可能要在UI上做出适当调整, 并使用该信息来进行相关歌曲的推荐.

MPRemoteCommandCenterr提供了相关属性(反馈按钮)

@property (nonatomic, readonly) MPFeedbackCommand *likeCommand;  // 喜欢命令
@property (nonatomic, readonly) MPFeedbackCommand *dislikeCommand;  // 不喜欢命令
@property (nonatomic, readonly) MPFeedbackCommand *bookmarkCommand; // 标记(书签)命令

事实上, 系统的锁屏界面并不支持自定义. 这里边只需要添加反馈按钮, 则系统默认的锁屏界面就是网易云音乐所展示的样式. 包括点击后弹出的ActionSheet都是系统针对反馈按钮所提供了, 网易云音乐只是巧妙的将"不喜欢"按钮的标题修改成"上一曲", 并在该按钮的响应事件里实现上一曲的代码, 即完成相关功能.

项目中的代码实现

// 添加"喜欢"按钮, 需要启用, 并且设置了相关Action后才会生效
[MPRemoteCommandCenter sharedCommandCenter].likeCommand.enabled = YES;
[[MPRemoteCommandCenter sharedCommandCenter].likeCommand addTarget:self action:@selector(likeItemAction)];
[MPRemoteCommandCenter sharedCommandCenter].likeCommand.localizedTitle = @"喜欢";

// 添加"不喜欢"按钮
[MPRemoteCommandCenter sharedCommandCenter].dislikeCommand.enabled = YES;
// 自定义该按钮的响应事件, 实现在点击"不喜欢"时去执行上一首的功能
[[MPRemoteCommandCenter sharedCommandCenter].dislikeCommand 
addTarget:self action:@selector(previousCommandAction)];
[MPRemoteCommandCenter
// 自定义"不喜欢"的标题, 伪装成"上一首"
sharedCommandCenter].dislikeCommand.localizedTitle = @"上一首";

注意: 反馈按钮默认不启用, 因此需要将enabled设置为YES, 同时必须添加对应的响应事件, 按钮才会在锁屏界面显示.

完成效果:

技术分享图片

技术分享图片

技术分享图片

技术分享图片


以上是关于网易云音乐锁屏界面效果实现的主要内容,如果未能解决你的问题,请参考以下文章

[MAUI]模仿网易云音乐黑胶唱片的交互实现

Vue 实现网易云音乐 WebApp

3.Android高仿网易云音乐-首页复杂发现界面布局和功能

3.Android高仿网易云音乐-首页复杂发现界面布局和功能

3.Android高仿网易云音乐-首页复杂发现界面布局和功能

Android ScrollView滚动实现大众点评网易云音乐评论悬停效果