Timeline Progress bar for AVPlayer

后端 未结 8 2200
情深已故
情深已故 2020-12-22 22:31

AVPlayer is fully customizable, unfortunately there are convenient methods in AVPlayer for showing the time line progress bar.

AVPl         


        
8条回答
  •  暖寄归人
    2020-12-22 22:32

    I took the answers from the iOSPawan and Raphael and then adapted to my needs. So I have music and UIProgressView which is always in loop and when you go to the next screen and come back the the song and the bar continued where they were left.

    Code:

    @interface YourClassViewController (){
    
        NSObject * periodicPlayerTimeObserverHandle;
    }
    @property (nonatomic, strong) AVPlayer *player;
    @property (nonatomic, strong) UIProgressView *progressView;
    
    -(void)viewWillAppear:(BOOL)animated{
        [super viewWillAppear:animated];
    
        if(_player != nil && ![self isPlaying])
        {
            [self musicPlay];
        }
    }
    
    
    -(void)viewWillDisappear:(BOOL)animated
    {
        [super viewWillDisappear:animated];
    
        if (_player != nil) {
    
            [self stopPlaying];
        }
    }
    
    //   ----------
    //     PLAYER
    //   ----------
    
    -(BOOL) isPlaying
    {
        return ([_player rate] > 0);
    }
    
    -(void) musicPlay
    {
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(playerItemDidReachEnd:)
                                                     name:AVPlayerItemDidPlayToEndTimeNotification
                                                   object:[_player currentItem]];
    
        __weak typeof(self) weakSelf = self;
        periodicPlayerTimeObserverHandle = [_player addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(1.0 / 60.0, NSEC_PER_SEC)
                                                                                 queue:NULL
                                                                            usingBlock:^(CMTime time){
                                                                                [weakSelf updateProgressBar];
                                                                            }];
        [_player play];
    }
    
    
    -(void) stopPlaying
    {
        @try {
    
            if(periodicPlayerTimeObserverHandle != nil)
            {
                [_player removeTimeObserver:periodicPlayerTimeObserverHandle];
                periodicPlayerTimeObserverHandle = nil;
            }
    
            [[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
            [_player pause];
        }
        @catch (NSException * __unused exception) {}
    }
    
    
    -(void) playPreviewSong:(NSURL *) previewSongURL
    {
        [self configureAVPlayerAndPlay:previewSongURL];
    }
    
    
    -(void) configureAVPlayerAndPlay: (NSURL*) url {
    
        if(_player)
            [self stopPlaying];
    
        AVAsset *audioFileAsset = [AVURLAsset URLAssetWithURL:url options:nil];
        AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:audioFileAsset];
        _player = [AVPlayer playerWithPlayerItem:playerItem];
        [_player addObserver:self forKeyPath:@"status" options:0 context:nil];
    
        CRLPerformBlockOnMainThreadAfterDelay(^{
            NSError *loadErr;
            if([audioFileAsset statusOfValueForKey:@"playable" error:&loadErr] == AVKeyValueStatusLoading)
            {
                [audioFileAsset cancelLoading];
                [self stopPlaying];
                [self showNetworkError:NSLocalizedString(@"Could not play file",nil)];
            }
        }, NETWORK_REQUEST_TIMEOUT);
    }
    
    
    - (void)updateProgressBar
    {
    
        double currentTime = CMTimeGetSeconds(_player.currentTime);
        if(currentTime <= 0.05){
            [_progressView setProgress:(float)(0.0) animated:NO];
            return;
        }
    
        if (isfinite(currentTime) && (currentTime > 0))
        {
            float maxValue = CMTimeGetSeconds(_player.currentItem.asset.duration);
            [_progressView setProgress:(float)(currentTime/maxValue) animated:YES];
        }
    }
    
    
    -(void) showNetworkError:(NSString*)errorMessage
    {
        UIAlertController *alert = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"No connection", nil) message:errorMessage preferredStyle:UIAlertControllerStyleAlert];
        [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil) style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
            // do nothing
        }]];
    
        [self presentViewController:alert animated:YES completion:nil];
    }
    
    
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    
        if (object == _player && [keyPath isEqualToString:@"status"]) {
            if (_player.status == AVPlayerStatusFailed) {
                [self showNetworkError:NSLocalizedString(@"Could not play file", nil)];
            } else if (_player.status == AVPlayerStatusReadyToPlay) {
                NSLog(@"AVPlayerStatusReadyToPlay");
                [TLAppAudioAccess setAudioAccess:TLAppAudioAccessType_Playback];
                [self musicPlay];
    
            } else if (_player.status == AVPlayerItemStatusUnknown) {
                NSLog(@"AVPlayerItemStatusUnknown");
            }
        }
    }
    
    
    - (void)playerItemDidReachEnd:(NSNotification *)notification {
    
        if ([notification.object isEqual:self.player.currentItem])
        {
            [self.player seekToTime:kCMTimeZero];
            [self.player play];
        }
    }
    
    
    -(void) dealloc{
    
        @try {
            [_player removeObserver:self forKeyPath:@"status"];
        }
        @catch (NSException * __unused exception) {}
        [self stopPlaying];
        _player = nil;
    }
    

提交回复
热议问题