最近有个项目需要自定义播放器界面,要求能调节声音、和播放进度并显示播放时间,效果图如下:
开始准备用AVAudioPlayer,但是不好控制播放进度,最后使用了AVPlayer ;同时也学习到了怎么自定义UISlider
需要引入的framework: AVFoundation.framework 、MediaPlayer.framework 、CoreMedia.framework
首先我定义了一个xib文件:
类的.h文件
#import
#import
#import
#import
@interface AudioPlayerView : UIView
{
__weak IBOutlet UILabel *timeLabel;
__weak IBOutlet UISlider *processSlider;
__weak IBOutlet UISlider *volumeSlider;
__weak IBOutlet UIButton *startOrStopButton;
float totalDuration;
float currentDuration;
BOOL isPlay; //是否正在播放
id mTimeObserver;
}
@property (nonatomic , strong) AVPlayer *mediaPlayer;
- (void)setAudioName:(NSString *)name;
- (void)dismissFromSuperview;
- (IBAction)startOrStopButtonAction:(id)sender;
@end
/*
1、添加播放器()
AudioPlayerView *audioView = [[[NSBundle mainBundle] loadNibNamed:@"AudioPlayerView" owner:self options:nil] objectAtIndex:0];
[self.view addSubview:audioView];
[audioView setAudioName:@"demo.mp3"];
2、移除播放器
[audioView dismissFromSuperview];
audioView = nil;
*/
#import "AudioPlayerView.h"
#define animationDuration 0.3
@implementation AudioPlayerView
@synthesize mediaPlayer = _mediaPlayer;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if(self){
//your corder
currentDuration = 0;
totalDuration = 0;
}
return self;
}
- (void)willMoveToSuperview:(UIView *)newSuperview
{
if(newSuperview){ //视图将要出现时的动画
CGRect audioFrame = self.frame;
audioFrame.origin.y = newSuperview.bounds.size.height;
self.frame = audioFrame;
audioFrame.origin.y = newSuperview.bounds.size.height-self.bounds.size.height;
[UIView animateWithDuration:animationDuration animations:^{
self.frame = audioFrame;
}];
}
}
- (void)dismissFromSuperview
{
[self stopAVPlayer];
CGRect audioFrame = self.frame;
audioFrame.origin.y = self.frame.size.height+self.frame.origin.y;
[UIView animateWithDuration:animationDuration animations:^{
self.frame = audioFrame;
} completion:^(BOOL finished){
[self removeFromSuperview];
}];
}
- (void)setAudioName:(NSString *)name
{
NSFileManager *fileManage = [NSFileManager defaultManager];
if(![fileManage fileExistsAtPath:PathOfFileNamed(name)]){
[self performSelector:@selector(showAlertViewWithMessage:) withObject:@"语音文件不存在" afterDelay:.5];
return ;
}
NSURL *audioURL = [NSURL fileURLWithPath:PathOfFileNamed(name)];
AVURLAsset *urlAsset = [AVURLAsset URLAssetWithURL:audioURL options:nil];
AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:urlAsset];;
self.mediaPlayer = [AVPlayer playerWithPlayerItem:playerItem];
[self initProcessSliderTimer];
ALog(@"totalDuration %f",totalDuration);
CMTime totalTime = playerItem.duration; //获取音频的总时间
totalDuration = (CGFloat)totalTime.value/totalTime.timescale;
[self initTimelabel];
[self performSelector:@selector(startOrStopButtonAction:) withObject:startOrStopButton afterDelay:animationDuration];
//播放视频时使用
// AVPlayerLayer * playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.mediaPlayer];
// [playerLayer setFrame:CGRectMake(0, 0, 320, 280)];
// [self.superview.layer addSublayer:playerLayer];
}
- (void)showAlertViewWithMessage:(NSString *)message
{
[[[UIAlertView alloc] initWithTitle:nil
message:message
delegate:self
cancelButtonTitle:@"确定"
otherButtonTitles:nil, nil] show];
}
- (void)awakeFromNib
{
self.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"audioPlayerBg.png"]];
[self initSlider];
}
- (CMTime)playerItemDuration
{
AVPlayerItem *playerItem = [self.mediaPlayer currentItem];
if (playerItem.status == AVPlayerItemStatusReadyToPlay) {
return([playerItem duration]);
}
return(kCMTimeInvalid);
}
-(void)initProcessSliderTimer
{
if(!mTimeObserver){
CMTime time = CMTimeMake(1,1);
__weak typeof(self) weakSelf = self;
mTimeObserver = [self.mediaPlayer addPeriodicTimeObserverForInterval:time
queue:NULL
usingBlock:^(CMTime time){
[weakSelf syncProcessSlider];
}];
}
CMTime playerDuration = [self playerItemDuration];
if (CMTIME_IS_INVALID(playerDuration)) {
processSlider.value = 0;
}
}
- (void)syncProcessSlider
{
//实时刷新播放进度条
CMTime playerDuration = [self playerItemDuration];
if (CMTIME_IS_INVALID(playerDuration)) {
processSlider.minimumValue = 0.0;
return;
}
totalDuration = CMTimeGetSeconds(playerDuration);
if (isfinite(totalDuration)){
float minValue = [processSlider minimumValue];
float maxValue = [processSlider maximumValue];
currentDuration = CMTimeGetSeconds([self.mediaPlayer currentTime]);
[self initTimelabel];
[processSlider setValue:(maxValue - minValue) * currentDuration / totalDuration + minValue];
}
if (processSlider.value == 1.0) {
[self.mediaPlayer seekToTime:kCMTimeZero];
[startOrStopButton setImage:[UIImage imageNamed:@"audioPlayerStart.png"] forState:UIControlStateNormal];
}
}
- (IBAction)startOrStopButtonAction:(id)sender
{
if (self.mediaPlayer.rate == 1) {
[self.mediaPlayer pause];
[startOrStopButton setImage:[UIImage imageNamed:@"audioPlayerStart.png"] forState:UIControlStateNormal];
} else {
[self.mediaPlayer play];
[startOrStopButton setImage:[UIImage imageNamed:@"audioPlayerPause.png"] forState:UIControlStateNormal];
[self initProcessSliderTimer];
}
}
- (void)initTimelabel
{
//更新显示的时间
NSString *currentTime = [self formatDateWithSecond:(int)currentDuration];
NSString *totalTime = [self formatDateWithSecond:(int)totalDuration];
NSString *timeString = [NSString stringWithFormat:@"%@ / %@",currentTime,totalTime];
timeLabel.text = timeString;
}
- (NSString *)formatDateWithSecond:(int)second
{
if(!second || second<=0){
return @"00:00";
}
int hour = second/(60*60);
int minute = (second-(60*60)*hour)/60;
second -= (60*60)*hour+minute*60;
if(hour!=0){
return [NSString stringWithFormat:@"%02i:%02i:%02i", hour, minute, second];
}else{
return [NSString stringWithFormat:@"%02i:%02i", minute, second];
}
return nil;
}
- (void)initSlider
{
if([[[UIDevice currentDevice] systemVersion] floatValue]>=7.0){
CGRect proceeFrame = processSlider.frame;
proceeFrame.origin.y = 49;
processSlider.frame = proceeFrame;
CGRect volumeFrame = volumeSlider.frame;
volumeFrame.origin.y = 49;
volumeSlider.frame = volumeFrame;
}
// 自定义 UISlider 的图片
UIImage *minImage = [UIImage imageNamed:@"audioPlayerSliderMinTrack.png"]; //进度条
UIImage *maxImage = [UIImage imageNamed:@"audioPlayerSliderMaxTrack.png"]; //滑块的底图
UIImage *tumbImage= [UIImage imageNamed:@"audioPlayerSliderThumb.png"]; //中间的圆形控制按钮
minImage=[minImage resizableImageWithCapInsets:UIEdgeInsetsMake(2, 2, 2, 2)];
maxImage=[maxImage resizableImageWithCapInsets:UIEdgeInsetsMake(2, 2, 2, 2)];
[processSlider setMinimumTrackImage:minImage forState:UIControlStateNormal];
[processSlider setMaximumTrackImage:maxImage forState:UIControlStateNormal];
[processSlider setThumbImage:tumbImage forState:UIControlStateNormal];
processSlider.minimumValue = 0.0;
processSlider.maximumValue = 1.0;
processSlider.continuous = YES;
// Attach an action to slider
[processSlider addTarget:self action:@selector(processSliderStartDragAction:)
forControlEvents:UIControlEventTouchDown];
[processSlider addTarget:self action:@selector(sliderValueChangedAction:)
forControlEvents:UIControlEventValueChanged];
[processSlider addTarget:self action:@selector(processSliderEndDragAction:)
forControlEvents:UIControlEventTouchUpInside | UIControlEventTouchUpOutside];
[volumeSlider setMinimumTrackImage:minImage forState:UIControlStateNormal];
[volumeSlider setMaximumTrackImage:maxImage forState:UIControlStateNormal];
[volumeSlider setThumbImage:tumbImage forState:UIControlStateNormal];
volumeSlider.minimumValue = 0.0;
volumeSlider.maximumValue = 1.0;
volumeSlider.continuous = YES;
volumeSlider.value = [[MPMusicPlayerController applicationMusicPlayer] volume]; //获取系统声音的值
[volumeSlider addTarget:self action:@selector(sliderValueChangedAction:)
forControlEvents:UIControlEventValueChanged];
}
- (void)processSliderStartDragAction:(id)sender
{
if (self.mediaPlayer.rate == 1) {
isPlay = true;
[self.mediaPlayer pause];
} else{
isPlay = false;
}
}
- (void)processSliderEndDragAction:(id)sender
{
//调节播放进度
CMTime dragedCMTime = CMTimeMake(totalDuration*processSlider.value, 1);
[self.mediaPlayer seekToTime:dragedCMTime completionHandler:^(BOOL finish){
if(isPlay){
[self.mediaPlayer play];
}
}];
}
- (void)sliderValueChangedAction:(id)sender
{
UISlider *targetSlider = (UISlider *)sender;
if (targetSlider == processSlider) {
currentDuration = totalDuration*targetSlider.value;
[self initTimelabel];
}else if (targetSlider == volumeSlider){
float volume=[[NSString stringWithFormat:@"%.1f",volumeSlider.value] floatValue];
[[MPMusicPlayerController applicationMusicPlayer] setVolume:volume]; //设置声音
}
}
- (void)dealloc
{
NSLog(@"AudioPlayerView dealloc!");
[self stopAVPlayer];
}
- (void)stopAVPlayer
{
if (self.mediaPlayer.rate == 1) {
[self.mediaPlayer pause];
}
self.mediaPlayer = nil;
mTimeObserver = nil;
}
@end