音乐播放器-小案列
来源:互联网 发布:双卡双待联通没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
- 音乐播放器-小案列
- android音乐播放器播放音乐卡
- Android 音乐播放 类似音乐播放器
- flash音乐播放器
- 常见音乐播放器
- WEB音乐播放器
- Google 音乐播放器
- 单片机音乐播放器
- 简易音乐播放器
- 网页音乐播放器
- 音乐定时播放器
- android 音乐播放器
- 音乐播放器代码
- 音乐播放器01
- 个人音乐播放器
- YOYOPlayer音乐播放器
- Qt音乐播放器
- Android 音乐播放器
- 局域网聊天
- 使用jdk中keytool生成证书
- 模拟ic流片经验分享
- Android中使用隐藏API图文解析
- (第七周项目2)建立链队算法库
- 音乐播放器-小案列
- 字节单位常识
- 安卓Fragment和Activity之间的数据通讯
- JSP:JSP与Javabean相关的
- T-SQL Hints
- APICloud 图片轮播模块 UIScrollPicture
- Eclipse使用Link配置Svn、Maven、spket、ADT
- JSP常用命令详解
- Android 仿ios屏幕右边的圆圈