简体   繁体   English

在iOS中使用控件播放音频

[英]Playing audio with controls in iOS

I've made an app with tab bar,nav bar and table view . 我制作了一个带tab bar,nav bar and table view的应用程序。

In the table view you can choose to listen to some audio. 在表格视图中,您可以选择收听某些音频。

New view opens and there I have some controls like: play,pause,volume slider, progress slider, label with the current time. 新视图打开,我有一些控件,如:播放,暂停,音量滑块,进度滑块,标签与当前时间。

It works, but not perfect. 它有效但不完美。 I can play the audio, I can pause the audio, I can also use the slider to skip forward or back. 我可以播放音频,我可以暂停音频,我也可以使用滑块向前或向后跳过。 But now: 但现在:

When I hit the Back button on the navbar, the song keeps playing. 当我按下导航栏上的“后退”按钮时,歌曲会继续播放。 That's ok, but when I go back to the view again, the timer and the slider reset themselves. 没关系,但是当我再次回到视图时,计时器和滑块会自行重置。 I can't pause the song, just need to wait util it stops playing. 我不能暂停这首歌,只需要等待它停止播放。

Also, when I hit play, go back to the table view, choose another file to play, the first file won't stop playing . 另外,当我点击播放时,返回表格视图,选择要播放的另一个文件,第一个文件不会停止播放

Here is the Audio1DetailViewController.h code: 这是Audio1DetailViewController.h代码:

     #import <UIKit/UIKit.h>
     #import <AVFoundation/AVFoundation.h>

     @interface Audio1DetailViewController: UIViewController <AVAudioPlayerDelegate> {

     IBOutlet UISlider *volumeControl; 
     IBOutlet UILabel  *timerLabel; 
     IBOutlet UISlider *progressBar; 

     AVAudioPlayer *audioPlayer;
     NSTimer *playbackTimer; 

     }

     @property (nonatomic, retain) IBOutlet UISlider *volumeControl;
     @property (nonatomic, retain) IBOutlet UILabel *timerLabel;
     @property (nonatomic, retain) IBOutlet UISlider *progressBar;
     @property (nonatomic, retain) NSTimer  *playbackTimer; 
     @property (nonatomic, retain) AVAudioPlayer *audioPlayer;
     -(IBAction) playAudio;
     -(IBAction) stopAudio;
     -(IBAction) adjustVolume;
     -(IBAction) sliderChanged;

     @end

Here is the Audio1DetailViewController.m code: 这是Audio1DetailViewController.m代码:

     #import "Audio1DetailViewController.h"


     @implementation Audio1DetailViewController

     @synthesize volumeControl, timerLabel, playbackTimer, progressBar, audioPlayer;

     -(void)playAudio
     {
     playbackTimer = [NSTimer scheduledTimerWithTimeInterval:1.0
     target:self
     selector:@selector(updateTime)
     userInfo:nil
     repeats:YES];
     [audioPlayer play];
     }
     -(void)stopAudio
     {
     [playbackTimer invalidate];
     [audioPlayer stop];
     }
     -(void)adjustVolume
     {
     if (audioPlayer != nil)
     {
     audioPlayer.volume = volumeControl.value;
     }
     }

     -(void)updateTime
     {
     float minutes = floor(audioPlayer.currentTime/60);
     float seconds = audioPlayer.currentTime - (minutes * 60);

     float duration_minutes = floor(audioPlayer.duration/60);
     float duration_seconds = 
     audioPlayer.duration - (duration_minutes * 60);

     NSString *timeInfoString = [[NSString alloc] 
     initWithFormat:@"%0.0f.%0.0f / %0.0f.%0.0f",
     minutes, seconds, 
     duration_minutes, duration_seconds];

     timerLabel.text = timeInfoString;
     [timeInfoString release];
     }

     - (void)viewDidLoad {
     [super viewDidLoad];
     NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle]
     pathForResource:@"001Fatiha"
     ofType:@"MP3"]];

     NSError *error;
     audioPlayer = [[AVAudioPlayer alloc]
     initWithContentsOfURL:url
     error:&error];

     [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
     [[AVAudioSession sharedInstance] setActive: YES error: nil];

     if (error)
     {
     NSLog(@"Error in audioPlayer: %@", 
     [error localizedDescription]);
     } else {
     audioPlayer.delegate = self;
     [audioPlayer prepareToPlay];
     }


     playbackTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self
     selector:@selector(updateSlider) userInfo:nil repeats:YES];

     progressBar.maximumValue = audioPlayer.duration;
     // Set the valueChanged target
     [progressBar addTarget:self action:@selector(sliderChanged:) forControlEvents:
     UIControl EventValueChanged];
     }

     - (void)updateSlider {
     // Update the slider about the music time
     progressBar.value = audioPlayer.currentTime;
     }

     - (IBAction)sliderChanged:(UISlider *)sender {
     // Fast skip the music when user scroll the UISlider
     [audioPlayer stop];
     [audioPlayer setCurrentTime:progressBar.value];
     [audioPlayer prepareToPlay];
     [audioPlayer play];
     }

     -(void)audioPlayerDidFinishPlaying:
     (AVAudioPlayer *)player successfully:(BOOL)flag
     {
     }


     -(void)audioPlayerDecodeErrorDidOccur:
     (AVAudioPlayer *)player error:(NSError *)error
     {
     }
     -(void)audioPlayerBeginInterruption:(AVAudioPlayer *)player
     {
     }
     -(void)audioPlayerEndInterruption:(AVAudioPlayer *)player
     {
     }

     -(void)viewDidUnload {
     audioPlayer = nil;
     volumeControl = nil;

     }

     -(void)dealloc {
     [audioPlayer release];
     [volumeControl release];
     [playbackTimer release];
     [super dealloc];
     }

     @end

Here is the AudioTableViewController.h 这是AudioTableViewController.h

     #import <UIKit/UIKit.h>

     @class Audio1DetailViewController;


     @interface AudioTableViewController : UITableViewController 
     <UITableViewDelegate,UITableViewDataSource>{


     IBOutlet UITableView *audioTableView;
     NSMutableArray *audioArray;
     Audio1DetailViewController *audio1DetailViewController;        
     }

     @property (nonatomic, retain) NSMutableArray *audioArray;
     @property (nonatomic, retain) Audio1DetailViewController *audio1DetailViewController;

     @end

And the AudioTableViewController.m 和AudioTableViewController.m

    #import "AudioTableViewController.h"
    #import "Audio1DetailViewController.h"

    #import "DEQAppDelegate.h"

    @implementation AudioTableViewController
    @synthesize audioArray;
    @synthesize audio1DetailViewController;

    - (id)initWithStyle:(UITableViewStyle)style
    {
        self = [super initWithStyle:style];
        if (self) {
            // Custom initialization
    {
        return self;
    }

    - (void)didReceiveMemoryWarning
    {
        // Releases the view if it doesn't have a superview.
        [super didReceiveMemoryWarning];

        // Release any cached data, images, etc that aren't in use.
    }

    #pragma mark - View lifecycle

    - (void)viewDidLoad{
        [super viewDidLoad];
        self.title = NSLocalizedString(@"Audio", @"Audio");
        self.audioArray = [[NSArray alloc] initWithObjects:
                          @"1. Het Begin",  @"2. De Mensen", //etcetera                      
                  nil];
        // Uncomment the following line to preserve selection between presentations.
        self.clearsSelectionOnViewWillAppear = NO;

        // Uncomment the following line to display an Edit button in the navigation bar for this
        view controller.
        // self.navigationItem.rightBarButtonItem = self.editButtonItem;
    }

    - (void)viewDidUnload
    {
        [super viewDidUnload];
        // Release any retained subviews of the main view.
        self.audioArray = nil;
    }

    - (void)viewWillAppear:(BOOL)animated
    {
        [super viewWillAppear:animated];
    }

    - (void)viewDidAppear:(BOOL)animated
    {
        [super viewDidAppear:animated];
    }

    - (void)viewWillDisappear:(BOOL)animated
    {
        [super viewWillDisappear:animated];
    }

    - (void)viewDidDisappear:(BOOL)animated
    {
        [super viewDidDisappear:animated];
    }

    - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
    {
        // Return YES for supported orientations
        return (interfaceOrientation == UIInterfaceOrientationPortrait);
    }

    #pragma mark - Table view data source

    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    {
    #warning Potentially incomplete method implementation.
        // Return the number of sections.
        return 1;
    }

    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
    #warning Incomplete method implementation.
        // Return the number of rows in the section.
        return [self.audioArray count];
    }

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:
      (NSIndexPath *)indexPath
    {
        static NSString *CellIdentifier = @"Cell";

        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
        if (cell == nil) {
            cell = [[[UITableViewCell alloc] initWithStyle:
        UITableViewCellStyleDefaultreuseIdentifier:CellIdentifier] autorelease];
        }

        // Configure the cell...
        cell.textLabel.text = [self.audioArray objectAtIndex:[indexPath row]];

        return cell;
    }

    #pragma mark - Table view delegate

    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    {
        // Navigation logic may go here. Create and push another view controller.

        NSUInteger row = indexPath.row;

        if (row == 0) 
        {
     Audio1DetailViewController *audio1DetailViewController =[[Audio1DetailViewController alloc]
     initWithNibName:@"Audio1DetailViewController" bundle:nil]; 
     audio1DetailViewController.title = @"Audio";
     [self.navigationController pushViewController:audio1DetailViewController animated:YES];   
     [audio1DetailViewController release];

        }

        if (row == 1) 
        {
            //etcetera
        }

    }
    - (void)dealloc{
        [audioArray release];
        [super dealloc];
    }

    @end

I would suggest you create a global player object. 我建议你创建一个全局播放器对象。 Because right now, each time you push this view on the navigation controller you create a new one. 因为现在,每次在导航控制器上推送此视图时,都会创建一个新视图。 This also means that you do not have any reference to the previous player (and can not stop it). 这也意味着您没有任何对前一个玩家的引用(并且无法阻止它)。 So: declare the AVAudioPlayer one step higher (in the tableview). 所以:声明AVAudioPlayer更高一步(在tableview中)。 Now, when you select a row in it, assign it to a property of this new view (the one you linked). 现在,当您在其中选择一行时,将其分配给此新视图的属性(您链接的属性)。

Do you work with storyboard? 你是否使用故事板? Then you have to implement the method prepareForSegue: . 然后你必须实现方法prepareForSegue: . Give your segue on the storyboard an identifier (like showPlayer and check for that with if (segue.identifier isEqualToString:@"showPlayer") ). 在故事板上给你的segue一个标识符(比如showPlayer并用if (segue.identifier isEqualToString:@"showPlayer") )。

Now in your viewDidLoad do a check if audioPlayer is nil. 现在在你的viewDidLoad检查audioPlayer是否为零。 If you 如果你

- (void)viewDidLoad
{
    [super viewDidLoad];
    if (audioPlayer == nil)
    {
         // your init (audioplayer =[[AVAudioPlayer ...
    }
    else
    {
         if (audioPlayer.isPlaying)
         {
             // i.e. pause the player or do other stuff
         }
    }
}

Hope this helps you. 希望这对你有所帮助。

Also : Do not post images of code. 另外 :不要发布代码图像。 Just insert the code in your response or post it to a site like pastebin.com and link that page in your question. 只需在您的回复中插入代码或将其发布到像pastebin.com这样的网站,并在您的问题中链接该页面。 This makes it easier for others to respond and make suggestions how to alter your code. 这使得其他人更容易回复并提出如何更改代码的建议。

In response to your comment : The relevant stuff should be: In AudioTableViewController.h : 回应你的评论 :相关的东西应该是: 在AudioTableViewController.h中

@property (strong, nonatomic) AVAudioPlayer *audioPlayer;

In AudioTableViewController.m : 在AudioTableViewController.m中

@synthesize audioPlayer;
...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Navigation logic may go here. Create and push another view controller.

    NSUInteger row = indexPath.row;

    if (row == 0) 
    {
        self.audio1DetailViewController =[[Audio1DetailViewController alloc] initWithNibName:@"Audio1DetailViewController" bundle:nil]; 
        self.audio1DetailViewController.title = @"Audio";
        self.audio1DetailViewController.audioPlayer = self.audioPlayer;
        [self.navigationController pushViewController:self.audio1DetailViewController animated:YES];   
        [self.audio1DetailViewController release];
        ...

Audio1DetailViewController.m Audio1DetailViewController.m

- (void)viewDidLoad {
    [super viewDidLoad];
    NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"001Fatiha" ofType:@"MP3"]];

    NSError *error;

    // this is the important part: if we already have something playing, stop it!
    if (audioPlayer != nil)
    {
        [audioPlayer stop];
    }
    // everything else should happen as normal.
    audioPlayer = [[AVAudioPlayer alloc]
               initWithContentsOfURL:url
               error:&error];

    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
    [[AVAudioSession sharedInstance] setActive: YES error: nil];

to stop 2 songs playing at a same time you should do this: 要停止播放2首歌曲你应该这样做:

- (void)viewWillDisappear:(BOOL)animated
{
    audioPlayer = nil;
 volumeControl = nil;
}

for more help in playing audio you can use apple sample code: 有关播放音频的更多帮助,您可以使用Apple示例代码:

http://developer.apple.com/library/ios/#samplecode/avTouch/Introduction/Intro.html http://developer.apple.com/library/ios/#samplecode/avTouch/Introduction/Intro.html

Surprisingly the MPMoviePlayerController also plays MP3 player with controls!!! 令人惊讶的是,MPMoviePlayerController还可以播放带控件的MP3播放器!

self.moviePlayer=[[MPMoviePlayerController alloc] initWithContentURL:url];
[self.moviePlayer.view setFrame:CGRectMake(0, 0, self.videoContainer.bounds.size.width, self.videoContainer.bounds.size.height)];
self.moviePlayer.controlStyle=MPMovieControlStyleDefault;
[self.videoContainer addSubview:self.moviePlayer.view];
[self.moviePlayer prepareToPlay];
[self.moviePlayer play];

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM