2

我正在开发一个语音备忘录应用程序,它记录用户的声音并播放它们。

录音部分效果很好。录制的文件已成功存储,当用户点击已保存的文件时,它才开始播放文件。

UISlider用来表示播放进度。UISlider现在,我将的userInteractionEnabled属性禁用为NO. 所以,我不允许用户与UISliderbar 交互。

我需要的是,我想启用此属性YES,以便可以选择播放音频的所需位置。为此,我在滑块代码中添加了以下行。

[mySlider addTarget:self action:@selector(sliderChanged:) forControlEvents:UIControlEventValueChanged];

通过添加上面的行,我可以找到方法中的滑块位置sliderChanged:。但是,我不知道如何从所选位置启动播放器。每个文件都有不同的大小,因此它们的播放时间也不同。

有没有可用的示例代码?需要你的帮助。

谢谢

4

5 回答 5

6

在 Swift 中分享一个解决方案。

我能够让我的项目使用基于发布的objective-c implementation zeeran的滑块,它甚至现在不断更新当前时间,而我以前没有这样做。我很高兴。

所以我想分享快速的实现,以防它帮助任何人。

import UIKit
import AVFoundation
import Foundation

class ActivityViewController: UIViewController, AVAudioPlayerDelegate {  
    /// The player & sound file object
    var audioPlayer = AVAudioPlayer()
    var activitySound = NSURL()

    var updater : CADisplayLink! = nil // tracks the time into the track
    var updater_running : Bool = false // did the updater start?
    var playing : Bool = false //indicates if track was started playing

    @IBOutlet var playButton: UIButton!
    @IBOutlet var timeLabel: UILabel!  // shows time and duration
    @IBOutlet var audioSlider: UISlider! // slider object

    @IBAction func pressedPlayButton(sender: AnyObject) {
        if (playing == false) {
            updater = CADisplayLink(target: self, selector: Selector("updateProgress"))
            updater.frameInterval = 1
            updater.addToRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
            updater_running = true
            audioPlayer.play()
            playButton.selected = true // pause image is assigned to "selected"
            playing = true
            updateProgress()
        } else {
            updateProgress()  // update track time
            audioPlayer.pause()  // then pause
            playButton.selected = false  // show play image (unselected button)
            playing = false // note track has stopped playing
        }
    }

    // action for when the slider is moved: set as 'valuechanged' for UISlider object
    @IBAction func sliderMoved(sender: UISlider) {
        // if the track was playing store true, so we can restart playing after changing the track position
        var wasPlaying : Bool = false
        if playing == true {
            audioPlayer.pause()
            wasPlaying = true
        }
        audioPlayer.currentTime = NSTimeInterval(round(audioSlider.value))
        updateProgress()
        // starts playing track again it it had been playing
        if (wasPlaying == true) {
            audioPlayer.play()
            wasPlaying == false
        }
    }

    // Timer delegate method that updates current time display in minutes
    func updateProgress() {
        let total = Float(audioPlayer.duration/60)
        let current_time = Float(audioPlayer.currentTime/60)
        audioSlider.minimumValue = 0.0
        audioSlider.maximumValue = Float(audioPlayer.duration)
        audioSlider.setValue(Float(audioPlayer.currentTime), animated: true)
        timeLabel.text = NSString(format: "%.2f/%.2f", current_time, total) as String
    }

    //- AVAudioPlayer delegate method - resets things when track finishe playing
    func PlayerDidFinishPlaying(player: AVAudioPlayer!, successfully flag: Bool) {
        if flag {
            playButton.selected = false
            playing = false
            audioPlayer.currentTime = 0.0
            updateProgress()
            updater.invalidate()
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        // configure AVAudioPlayer as audioPlayer object
        let file = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("file1", ofType: "mp3")!)!
        audioPlayer = audioPlayer(contentsOfURL: file, error: nil)
        audioPlayer.delegate = self

        audioSlider.continuous = false
    }

    // method makes sure updater gets stopped when leaving view controller, because otherwise it will run indefinitely in background
    override func viewWillDisappear(animated: Bool) {
        if playing == true {
            audioPlayer.stop()
        }
        updater.invalidate()
        updater_running = false
        super.viewWillDisappear(animated)
    }
}
于 2015-06-06T03:18:27.620 回答
4

在加载声音文件之前刷新滑块最小值和最大值

yourSlider.minValue = 0.0;
yourSlider.maxValue = player.duration;

在方法中sliderChanged:

player.currentTime = yourSlider.value;
于 2013-07-16T19:15:55.570 回答
1

我的工作是通过结合 rajagp 和 Igor Bidiniuc 的上述答案来工作,所以我要对它们都投赞成票。

#import <AVFoundation/AVFoundation.h>

@property (nonatomic, strong) IBOutlet UIButton *playButton;
@property (nonatomic, strong) IBOutlet UISlider *slider;
@property (nonatomic, strong) IBOutlet UILabel *timeLabel;
@property (nonatomic, strong) AVAudioPlayer *audioPlayer;
@property (nonatomic, strong) NSTimer *timer;

- (IBAction)playPause:(id)sender;
- (IBAction)sliderValueChanged:(id)sender;

这里是实现文件。

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.slider.continuous = YES;
    NSError *error = nil;
    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&error];
    if (error == nil) {
        NSLog(@"audio session initialized successfully");
        [self PlayAudio:@"fileName"];
    } else {
        NSLog(@"error initializing audio session: %@", [error description]);
    }
}

- (void)PlayAudio:(NSString*)file {
    NSError *error = nil;
    NSString *soundPath =[[NSBundle mainBundle] pathForResource:file ofType:@"mp3"];
    NSURL *fileURL = [NSURL fileURLWithPath:soundPath];

    if ([self.audioPlayer isPlaying]) {
        [self.audioPlayer pause];
        [self.timer invalidate];
    }
    self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:&error];
    self.audioPlayer.delegate = self;

    if (error == nil) {
        NSLog(@"audio player initialized successfully");

        [self playPause:nil];

    } else {
        NSLog(@"error initializing audio player: %@", [error description]);
    }
}



- (void)viewWillDisappear:(BOOL)animated {
    if ([self.audioPlayer isPlaying]) {
        [self.audioPlayer pause];
        [self.timer invalidate];
    }

    [super viewWillDisappear:animated];
}

-(IBAction)playPause:(id)sender
{
    if ([self.audioPlayer isPlaying]) {
        [self.audioPlayer pause];
        self.playButton.imageView.image = [UIImage imageNamed:@"play"];
        [self.timer invalidate];

    } else {
        [self.audioPlayer play];
        self.playButton.imageView.image = [UIImage imageNamed:@"pause"];

        self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(updateProgress) userInfo:nil repeats:YES];
    }

}

- (IBAction)sliderValueChanged:(id)sender {

    [self.timer invalidate];
    self.timer = nil;
    float position = self.slider.value;

    if (self.audioPlayer.isPlaying)
    {
        [self playPause:nil];
    }
    [self.audioPlayer setCurrentTime:position];
    if (self.audioPlayer.isPlaying)
    {
        [self playPause:nil];
    }
    [self updateProgress];
}

#pragma mark - Timer delegate

-(void)updateProgress
{
    NSInteger durationMinutes = [self.audioPlayer duration] / 60;
    NSInteger durationSeconds = [self.audioPlayer duration]  - durationMinutes * 60;

    NSInteger currentTimeMinutes = [self.audioPlayer currentTime] / 60;
    NSInteger currentTimeSeconds = [self.audioPlayer currentTime]  - currentTimeMinutes * 60;
    NSString *progressString = [NSString stringWithFormat:@"%d:%02d / %d:%02d", currentTimeMinutes, currentTimeSeconds, durationMinutes, durationSeconds];
    self.timeLabel.text = progressString;

    self.slider.minimumValue = 0.0;
    self.slider.maximumValue = [self.audioPlayer duration];

    [self.slider setValue:[self.audioPlayer currentTime] animated:YES];
}

#pragma mark - AVAudioPlayer delegate methods

-(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
    if (flag) {
        self.playButton.imageView.image = [UIImage imageNamed:@"play"];
        [self.timer invalidate];
    }
}
于 2015-01-12T14:56:55.687 回答
1

以下代码示例应该可以帮助您入门。有了这个,滑块可以用作进度指示器,用户可以滑动它以在指定位置开始播放。

/* SliderMoved 在滑块值更改时调用 - 无论是用户滑动它还是随着音频播放的进行而自动更新 */

-(void)sliderMoved:(id)sender
{
     [self.playbackTimer invalidate];
    self.playbackTimer = nil;
    NSInteger position = (NSInteger)self.slider.value * 60; // Assume the slider scale is in minutes- so convert to sec
    if (self.isPlaying)
    {
        [self.audioPlayer pause];
    }
    [self.audioPlayer setCurrentTime:position];
    if (self.isPlaying)
    {
        [self startOrResumePlaying];
    }
    [self updateSlider];

}

/* updateSlider 是一个用于更新滑块值的辅助函数 */

-(void)updateSlider
{
    float total= self.audioPlayer.duration;
    float f =  (self.audioPlayer.currentTime) ;
    self.slider.value = f/60.0;


    self.progressLabel.text = [NSString stringWithFormat:@"%.2f",self.slider.value];

}

/* startOrResumePlaying 开始音频播放并初始化一个计时器,该计时器每 3 秒自动增加进度指示器 */

-(void)startOrResumePlaying
{

    [self.audioPlayer prepareToPlay];
    [self.audioPlayer play];
    self.isPlaying = YES;
    self.playbackTimer=[NSTimer scheduledTimerWithTimeInterval:3.0
                                                        target:self
                                                      selector:@selector(handleTimer:)
                                                      userInfo:nil
                                                       repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:self.playbackTimer forMode:NSDefaultRunLoopMode];

}
于 2013-07-16T20:58:55.580 回答
0

AVAudioPlayer 有一个你可以设置的 currentTime 属性。请参考 AVAudioPlayer 文档。

于 2013-07-16T19:10:55.243 回答