音乐播放器-小案列

来源:互联网 发布:双卡双待联通没4g网络 编辑:程序博客网 时间:2024/06/04 19:04

1.封装音频播放工具类

////  AudioTool.h#import <Foundation/Foundation.h>#import <AVFoundation/AVFoundation.h>@interface AudioTool : NSObject/** *  播放音效 * *  @param filename 音效文件名 */+ (void)playSound:(NSString *)filename;/** *  销毁音效 * *  @param filename 音效文件名 */+ (void)disposeSound:(NSString *)filename;/** *  播放音乐 * *  @param filename 音乐文件名 */+ (AVAudioPlayer *)playMusic:(NSString *)filename;/** *  暂停音乐 * *  @param filename 音乐文件名 */+ (void)pauseMusic:(NSString *)filename;/** *  停止音乐 * *  @param filename 音乐文件名 */+ (void)stopMusic:(NSString *)filename;/** *  当前播放的音乐播放器 */+ (AVAudioPlayer *)currentPlayingAudioPlayer;@end

////  AudioTool.m#import "AudioTool.h"@implementation AudioTool/** * 存放所有的音效ID * 字典: filename作为key,soundID作为value */static NSMutableDictionary *_soundIDDict;/** * 存放所有的音乐播放器 * 字典: filename作为key,audioPlayer作为value */static NSMutableDictionary *_audioPlayerDict;/** *  初始化 */+ (void)initialize{    _soundIDDict = [NSMutableDictionary dictionary];    _audioPlayerDict = [NSMutableDictionary dictionary];        //设置音频回话类型    AVAudioSession *session = [AVAudioSession sharedInstance];    [session setCategory:AVAudioSessionCategorySoloAmbient error:nil];    [session setActive:YES error:nil];}/** *  播放音效 * *  @param filename 音效文件名 */+ (void)playSound:(NSString *)filename{    if (!filename) return;        //1.从字典中取出soundID    SystemSoundID soundID = [_soundIDDict[filename] unsignedIntValue];    if (!soundID) { //创建                //加载音效文件        NSURL *url = [[NSBundle mainBundle] URLForResource:filename withExtension:nil];        if(!url) return;                //创建音效ID        AudioServicesCreateSystemSoundID((__bridge CFURLRef _Nonnull)(url), &soundID);                //存入字典        _soundIDDict[filename] = @(soundID);    }       //2.播放    AudioServicesPlaySystemSound(soundID);    }/** *  销毁音效 * *  @param filename 音效文件名 */+ (void)disposeSound:(NSString *)filename{    if (!filename) return;    SystemSoundID soundID = [_soundIDDict[filename] unsignedIntValue];    if (!soundID) {        //销毁音效ID        AudioServicesDisposeSystemSoundID(soundID);                //从字典中移除        [_soundIDDict removeObjectForKey:filename];    }}/** *  播放音乐 * *  @param filename 音乐文件名 */+ (AVAudioPlayer *)playMusic:(NSString *)filename{    if (!filename) return nil;    //1.从字典中取出audioPlayer    AVAudioPlayer *audioPlayer = _audioPlayerDict[filename];    if (!audioPlayer) { //创建        //加载音乐文件        NSURL *url = [[NSBundle mainBundle] URLForResource:filename withExtension:nil];        if(!url) return nil;                //创建audioPlayer        audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];                //缓冲        [audioPlayer prepareToPlay];        //存入字典        _audioPlayerDict[filename] = audioPlayer;    }        //2.播放    if (!audioPlayer.isPlaying) {        [audioPlayer play];    }        return audioPlayer;}/** *  暂停音乐 * *  @param filename 音乐文件名 */+ (void)pauseMusic:(NSString *)filename{    if (!filename) return;        //1.从字典中取出audioPlayer    AVAudioPlayer *audioPlayer = _audioPlayerDict[filename];        //2.暂停    if (audioPlayer.isPlaying) {        [audioPlayer pause];    }}/** *  停止音乐 * *  @param filename 音乐文件名 */+ (void)stopMusic:(NSString *)filename{    if (!filename) return;        //1.从字典中取出audioPlayer    AVAudioPlayer *audioPlayer = _audioPlayerDict[filename];        //2.暂停    if (audioPlayer.isPlaying) {        [audioPlayer stop];                //从字典中移除        [_audioPlayerDict removeObjectForKey:filename];    }}/** *  当前播放的音乐播放器 */+ (AVAudioPlayer *)currentPlayingAudioPlayer{    for (NSString *filename in _audioPlayerDict) {        AVAudioPlayer *audioPlayer = _audioPlayerDict[filename];        if (audioPlayer.isPlaying) {            return audioPlayer;        }    }        return nil;}@end

2.要播放的音乐模型

////  MusicModel.h#import <Foundation/Foundation.h>@interface MusicModel : NSObject/** *  歌曲名称 */@property(nonatomic,copy)NSString *name;/** *  歌曲文件名称 */@property(nonatomic,copy)NSString *filename;/** *  歌手 */@property(nonatomic,copy)NSString *singer;/** *  歌手图片 */@property(nonatomic,copy)NSString *singerIcon;/** *  大图 */@property(nonatomic,copy)NSString *icon;@property(nonatomic,assign,getter=isPlaying)BOOL playing;- (instancetype)initWithDict:(NSDictionary *)dict;+ (instancetype)musicWithDict:(NSDictionary *)dict;@end
////  MusicModel.m#import "MusicModel.h"@implementation MusicModel- (instancetype)initWithDict:(NSDictionary *)dict{    self = [super init];    if (self) {        self.name = dict[@"name"];        self.filename = dict[@"filename"];        self.singer = dict[@"singer"];        self.singerIcon = dict[@"singerIcon"];        self.icon = dict[@"icon"];    }    return self;}+ (instancetype)musicWithDict:(NSDictionary *)dict{    return [[self alloc] initWithDict:dict];}@end

3.控制器里(这里我们用的UITableView)

////  MusicViewController.m#import "MusicViewController.h"#import "MusicModel.h"#import "AudioTool.h"#import <AVFoundation/AVFoundation.h>#import <MediaPlayer/MediaPlayer.h>#import "MusicCell.h"@interface MusicViewController ()<AVAudioPlayerDelegate>- (IBAction)jump:(UIBarButtonItem *)sender;/** *  存放所有的音乐模型数据 */@property(nonatomic,strong) NSArray *musics;@property(nonatomic,strong)CADisplayLink *link;/** *  当前正在播放的音乐播放器 */@property (nonatomic, strong) AVAudioPlayer *currentPlayingAudioPlayer;@end@implementation MusicViewController/** *  懒加载 创建音乐模型数据 */- (NSArray *)musics{    if (!_musics) {        NSArray *array = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Musics.plist" ofType:nil]];                NSMutableArray *arrayM = [NSMutableArray array];        for (NSDictionary *dict in array) {            [arrayM addObject:[MusicModel musicWithDict:dict]];        }        _musics = arrayM;    }    return _musics;}- (CADisplayLink *)link{    if (!_link) {        self.link = [CADisplayLink displayLinkWithTarget:self selector:@selector(update)];    }    return _link;}/** *  实时更新(1秒中调用60次) */- (void)update{    //监听播放进度    //总时长、当前时间//    NSLog(@"%f %f", self.currentPlayingAudioPlayer.duration, self.currentPlayingAudioPlayer.currentTime);    #warning 调整歌词}- (void)viewDidLoad {    [super viewDidLoad];}#pragma mark - Table view data source- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{    return self.musics.count;}- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{    //1.创建cell    MusicCell *cell = [MusicCell cellWithTableView:tableView];        //2.设置cell的数据    cell.model = self.musics[indexPath.row];        //3.    return cell;}#pragma mark -Table view delegate- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{    return 70;}/** *  取消选中会调用 */- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath{    //停止播放    MusicModel *model = self.musics[indexPath.row];    [AudioTool stopMusic:model.filename];        //再次传递模型(让上一手歌的图片停止转动)    MusicCell *cell = (MusicCell *)[tableView cellForRowAtIndexPath:indexPath];    model.playing = NO;    cell.model = model;}/** *  点击了cell(选中了) */- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{    //播放音乐    MusicModel *model = self.musics[indexPath.row];    AVAudioPlayer * audioPlayer = [AudioTool playMusic:model.filename];    audioPlayer.delegate = self;    self.currentPlayingAudioPlayer = audioPlayer;        //在锁屏界面显示歌曲信息    [self showInfoInLockedScreen:model];        //开启定时器监听播放进度    [self.link invalidate];    self.link = nil;    [self.link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];        //再次传递模型(让cell上图片转动起来)    MusicCell *cell = (MusicCell *)[tableView cellForRowAtIndexPath:indexPath];    model.playing = YES;    cell.model = model;}/** *  在锁屏界面显示歌曲信息 */- (void)showInfoInLockedScreen:(MusicModel *)model{    NSMutableDictionary *info = [NSMutableDictionary dictionary];    // 标题(音乐名称)    info[MPMediaItemPropertyTitle] = model.name;        // 作者    info[MPMediaItemPropertyArtist] = model.singer;        // 专辑    info[MPMediaItemPropertyAlbumTitle] = model.singer;        // 图片    info[MPMediaItemPropertyArtwork] = [[MPMediaItemArtwork alloc] initWithImage:[UIImage imageNamed:model.icon]];        [MPNowPlayingInfoCenter defaultCenter].nowPlayingInfo = info;}#pragma mark - AVAudioPlayerDelegate- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{    //计算下一行    NSIndexPath *selectedPath = [self.tableView indexPathForSelectedRow];    long next = selectedPath.row + 1;    if (next == self.musics.count) {        next = 0;    }        //停止上一首歌的转圈    MusicCell *cell = (MusicCell *)[self.tableView cellForRowAtIndexPath:selectedPath];    MusicModel *model = self.musics[selectedPath.row];    model.playing = NO;    cell.model = model;        //播放下一首歌    NSIndexPath *currentPath = [NSIndexPath indexPathForRow:next inSection:selectedPath.section];    [self.tableView selectRowAtIndexPath:currentPath animated:YES scrollPosition:UITableViewScrollPositionTop];    [self tableView:self.tableView didSelectRowAtIndexPath:currentPath];}/** *  音乐播放器被打断(电话) */- (void)audioPlayerBeginInterruption:(AVAudioPlayer *)player{}/** *  打断结束(电话结束) */- (void)audioPlayerEndInterruption:(AVAudioPlayer *)player withOptions:(NSUInteger)flags{    [player play];}- (IBAction)jump:(UIBarButtonItem *)sender{    //设置当前播放器的当前时间为 总时长的 最后3秒    self.currentPlayingAudioPlayer.currentTime = self.currentPlayingAudioPlayer.duration - 3;}@end

4.自定义的UITableViewCell

////  MusicCell.h#import <UIKit/UIKit.h>@class MusicModel;@interface MusicCell : UITableViewCell+ (instancetype)cellWithTableView:(UITableView *)tableView;@property (nonatomic, strong) MusicModel *model;@end
////  MusicCell.m#import "MusicCell.h"#import "MusicModel.h"#import "UIImage+MJ.h"#import "Colours.h"@interface MusicCell()@property (nonatomic, strong) CADisplayLink *link;@end@implementation MusicCell- (CADisplayLink *)link{    if (!_link) {        self.link = [CADisplayLink displayLinkWithTarget:self selector:@selector(update)];    }    return _link;}+ (instancetype)cellWithTableView:(UITableView *)tableView{    static NSString *ID = @"music";    MusicCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];    if (cell == nil) {        cell = [[MusicCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];    }    return cell;}- (void)setModel:(MusicModel *)model{    _model = model;        self.textLabel.text = model.name;    self.detailTextLabel.text = model.singer;    self.imageView.image = [UIImage circleImageWithName:model.singerIcon borderWidth:2.0 borderColor:[UIColor steelBlueColor]];       if (model.isPlaying) {        //转圈        [self.link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];    }else{ //停止动画        [self.link invalidate];        self.link = nil;        [UIView animateWithDuration:2.0 animations:^{            self.imageView.transform = CGAffineTransformIdentity;        }];    }}/** *  8秒转一圈, 45°/s */- (void)update{    // 1/60秒 * 45    // 规定时间内转动的角度 == 时间 * 速度    CGFloat angle = self.link.duration * M_PI_4;    self.imageView.transform = CGAffineTransformRotate(self.imageView.transform, angle);}@end

5.用到的其他

////  UIImage+MJ.h#import <UIKit/UIKit.h>@interface UIImage (MJ)/** *  返回一个带边框的圆形图片 * *  @param name        图片名称 *  @param borderWidth 边框宽度 *  @param borderColor 边框颜色 */+ (instancetype)circleImageWithName:(NSString *)name borderWidth:(CGFloat)borderWidth borderColor:(UIColor *)borderColor;@end
////  UIImage+MJ.m#import "UIImage+MJ.h"@implementation UIImage (MJ)+ (instancetype)circleImageWithName:(NSString *)name borderWidth:(CGFloat)borderWidth borderColor:(UIColor *)borderColor{    // 1.加载原图    UIImage *oldImage = [UIImage imageNamed:name];        // 2.开启上下文    CGFloat imageW = oldImage.size.width + 2 * borderWidth;    CGFloat imageH = oldImage.size.height + 2 * borderWidth;    CGSize imageSize = CGSizeMake(imageW, imageH);    UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0.0);        // 3.取得当前的上下文    CGContextRef ctx = UIGraphicsGetCurrentContext();        // 4.画边框(大圆)    [borderColor set];    CGFloat bigRadius = imageW * 0.5; // 大圆半径    CGFloat centerX = bigRadius; // 圆心    CGFloat centerY = bigRadius;    CGContextAddArc(ctx, centerX, centerY, bigRadius, 0, M_PI * 2, 0);    CGContextFillPath(ctx); // 画圆        // 5.小圆    CGFloat smallRadius = bigRadius - borderWidth;    CGContextAddArc(ctx, centerX, centerY, smallRadius, 0, M_PI * 2, 0);    // 裁剪(后面画的东西才会受裁剪的影响)    CGContextClip(ctx);        // 6.画图    [oldImage drawInRect:CGRectMake(borderWidth, borderWidth, oldImage.size.width, oldImage.size.height)];        // 7.取图    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();        // 8.结束上下文    UIGraphicsEndImageContext();        return newImage;}@end

还用到了Colours.h,非必要。如需要可去github下载。




1 0