Connect Multiple Buttons: Rewind & Play/pause button for one action - iphone

I have multiple UIButtons in my app. Want to connect Rewind & play/pause Button for one action. Not using interface builder at all for app.
Right now rewind button has this method when it is pressed
-(void)rewind:(id)sender{
[timer invalidate];
audioPlayer.currentTime = 0;
MainViewController *viewController = [[MainViewController alloc] init];
viewController.view.frame = CGRectMake(0, 0, 320, 480);
[self.view addSubview:viewController.view];
[self.view addSubview:toolbar];
[viewController release];
[audioPlayer play];
self.timer = [NSTimer scheduledTimerWithTimeInterval:11.0
target:self
selector:#selector(displayviewsAction:)
userInfo:nil
repeats:NO];
}
and play/pause button has this method when it is pressed
-(void)playpauseAction:(id)sender {
if([audioPlayer isPlaying])
{
[sender setImage:[UIImage imageNamed:#"Play Icon.png"] forState:UIControlStateSelected];
[audioPlayer pause];
[self pauseTimer];
[self pauseLayer:self.view.layer];
}else{
[sender setImage:[UIImage imageNamed:#"pause.png"] forState:UIControlStateNormal];
[audioPlayer play];
[self resumeTimer];
[self resumeLayer:self.view.layer];
if(isFirstTime == YES)
{
self.timer = [NSTimer scheduledTimerWithTimeInterval:11.0
target:self
selector:#selector(displayviewsAction:)
userInfo:nil
repeats:NO];
isFirstTime = NO;
}
}
}
When the rewind button is pressed, it should do the play/pause action method, means, when rewind button is pressed then play/pause button should toggle to pause button and when pause button is resumed, then it should toggle to play button.

An action method/selector can be connected to a UIButton using code:
[button1 addTarget:self action:#selector(method:) forControlEvents:UIControlEventTouchUpInside];
You can add same actions to UIButton using above line of code.

If I understand your question right, you want to call the same method when Play/Pause or Rewind button is clicked.
Just add this in addition to your existing code after connecting this method as the target for both your buttons.:
set a unique tag for your Play and Rewind buttons
-(void)buttonAction:(id)sender {
UIButton *clickedButton = (UIButton *)[sender];
if (clickedButton.tag = playButtonTag){
[self playPauseAction:sender];
}
else{
[self rewindAction:sender];
}
}
For sake of simplicity I have used if else. you could use if/if, or switch-case in place if this. Hope this helps!

Related

One method for two UIButtons

This rewind method is for rewind button as well as for play button.
-(void)rewind:(id)sender
{
[timer invalidate];
audioPlayer.currentTime = 0;
MainViewController *viewController = [[MainViewController alloc] init];
viewController.view.frame = CGRectMake(0, 0, 320, 480);
[self.view addSubview:viewController.view];
[self.view addSubview:toolbar];
[viewController release];
if([audioPlayer isPlaying])
{
[sender setImage:[UIImage imageNamed:#"Play Icon.png"] forState:UIControlStateSelected];
[audioPlayer pause];
[self pauseTimer];
[self pauseLayer:self.view.layer];
}else{
[sender setImage:[UIImage imageNamed:#"pause.png"] forState:UIControlStateNormal];
[audioPlayer play];
[self resumeTimer];
[self resumeLayer:self.view.layer];
if(isFirstTime == YES)
{
self.timer = [NSTimer scheduledTimerWithTimeInterval:11.0
target:self
selector:#selector(displayviewsAction:)
userInfo:nil
repeats:NO];
isFirstTime = NO;
}
}
}
Now in this method sender is rewind button and toggling of play/pause is happening on rewind button whereas i want this toggling on play button rather then sender which is rewind button. So i tried giving the name of the actual button on which i want toggling to happen and i defined that button as play button in my code and whose action method i have added in this rewind method.
That's how defined the play button
//Add Play Button
UIButton *playButton = [UIButton buttonWithType:UIButtonTypeCustom];
[playButton addTarget:self action:#selector(playpauseAction:) forControlEvents:UIControlEventTouchUpInside];
playButton.frame = CGRectMake(0, 0, 30, 30);
[playButton setImage:[UIImage imageNamed:#"Play Icon.png"] forState:UIControlStateNormal];
[playButton setImage:[UIImage imageNamed:#"pause.png"] forState:UIControlStateSelected];
UIBarButtonItem *play = [[UIBarButtonItem alloc] initWithCustomView:playButton];
and this is the method of play button which i added in the rewind button
-(void)playpauseAction:(id)sender
{
if([audioPlayer isPlaying])
{
[sender setImage:[UIImage imageNamed:#"Play Icon.png"] forState:UIControlStateSelected];
[audioPlayer pause];
[self pauseTimer];
[self pauseLayer:self.view.layer];
}
else
{
[sender setImage:[UIImage imageNamed:#"pause.png"] forState:UIControlStateNormal];
[audioPlayer play];
[self resumeTimer];
[self resumeLayer:self.view.layer];
if(isFirstTime == YES)
{
self.timer = [NSTimer scheduledTimerWithTimeInterval:11.0
target:self
selector:#selector(displayviewsAction:)
userInfo:nil
repeats:NO];
isFirstTime = NO;
}
}
}
now problem i m facing at this time is that when i m clicking the rewind button toggling should happen on play button than rewind button.
But to fix this problem i simply replaced sender with playButton in the rewind method like this
[playButton setImage:[UIImage imageNamed:#"Play Icon.png"] forState:UIControlStateSelected];
but then i get warning message in red that use of undeclared identifier playButton.
How can i tell rewind method to do toggling on playButton rather then on rewind button.
Please help.
Thanks.
Your "undeclared identifier playButton" is telling you that you don't have an instance variable playButton.
It is probably only visible in the method where you created it, but you need to save it into an iVar to be able to access it from the other method.

pause button when pressed again to resume reloading view controllers

I am using AVAudioplayer to play audio files, play/pause button to toggle between play and pause and NSTimer with audio player to synchronize view controllers one after another. I have a total of 10 or 11 view controllers to load one after the other.
When play button is pressed the very first time it starts NSTimer, starts playing an audio file and based on NSTimer, view controllers will load one after the other. When pause button is pressed again to resume it resumes everything from that point audio file, NSTimer and view controllers from the same point where it was paused which is good. However, at the same time it starts loading the view controllers again one after the other from the beginning based on NSTimer which is not good.
It is reloading view controllers with this statement
self.timer = [NSTimer scheduledTimerWithTimeInterval:11.0
target:self
selector:#selector(displayviewsAction:)
userInfo:nil
repeats:NO];
So my issue is that I need to stop the loading of view controllers again from the beginning when pause button is pressed again to resume playback.
-(void)playpauseAction:(id)sender
{
if ([audioPlayer isPlaying]) {
[sender setImage:[UIImage imageNamed:#"Play Icon.png"] forState:UIControlStateSelected];
[audioPlayer pause];
[self pauseTimer];
} else {
[sender setImage:[UIImage imageNamed:#"pause.png"] forState:UIControlStateNormal];
[audioPlayer play];
[self resumeTimer];
self.timer = [NSTimer scheduledTimerWithTimeInterval:11.0
target:self
selector:#selector(displayviewsAction:)
userInfo:nil
repeats:NO];
}
}
-(void)pauseTimer{
pauseStart = [[NSDate dateWithTimeIntervalSinceNow:0] retain];
previousFireDate = [[timer fireDate] retain];
[timer setFireDate:[NSDate distantFuture]];
}
-(void)resumeTimer{
float pauseTime = -1*[pauseStart timeIntervalSinceNow];
[timer setFireDate:[previousFireDate initWithTimeInterval:pauseTime sinceDate:previousFireDate]];
[pauseStart release];
[previousFireDate release];
}
- (void)displayviewsAction:(id)sender
{
First *firstController = [[First alloc] init];
firstController.view.frame = CGRectMake(0, 0, 320, 480);
CATransition *transitionAnimation = [CATransition animation];
[transitionAnimation setDuration:1];
[transitionAnimation setType:kCATransitionFade];
[transitionAnimation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]];
[self.view.layer addAnimation:transitionAnimation forKey:kCATransitionFade];
[self.view addSubview:firstController.view];
[self.view addSubview:toolbar];
[firstController release];
self.timer = [NSTimer scheduledTimerWithTimeInterval:23 target:self selector:#selector(Second) userInfo:nil repeats:NO];
}
Can anyone give an idea on how to stop the loading of view controllers again from the beginning when pause button is pressed again to resume playback.
I gather you're trying to display FirstViewController after 11 seconds have elapsed in the audio track.
You can set you timer up to poll (every .5 - 1.0 seconds) and if the audioPlayer's elapsed time is greater than 11.0, perform your action.
-(void)playpauseAction:(id)sender
{
if ([audioPlayer isPlaying]){
[sender setImage:[UIImage imageNamed:#"Play Icon.png"] forState:UIControlStateSelected];
[audioPlayer pause];
[self.timer invalidate]; // stop the polling timer
} else {
[sender setImage:[UIImage imageNamed:#"pause.png"] forState:UIControlStateNormal];
[audioPlayer play];
// start/resume the timer
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 /* polling interval */
target:self
selector:#selector(tryToDisplayViews:)
userInfo:nil
repeats:YES]; /* REPEAT = YES */
}
}
// the new polled method
-(void)tryToDisplayViews:(id)sender {
// need last current time as a new variable to ensure that we only add the view once
// and not every time the method fires with currentTime > 11.0
if( audioPlayer.currentTime > 11.0 && lastCurrentTime < 11.0) {
[self displayviewsAction:nil];
}
// you can add the second view here in a similar fashion
// if(audioPlayer.currentTime > (23.0+11.0) && lastCurrentTime < (23.0+11.0) ) {}
lastCurrentTime = audioPlayer.currentTime;
}
This also get's rid of your resumeTimer/pauseTimer actions, you don't need to count the time paused.

How to use NSNotificationCenter to send a notification from one UIButton to another UIButton

How this UIButton rewind can send notification to UIButton play to perform playpauseaction method when rewind button is clicked.
-(void)rewind:(id)sender{
[timer invalidate];
audioPlayer.currentTime = 0;
MainViewController *viewController = [[MainViewController alloc] init];
viewController.view.frame = CGRectMake(0, 0, 320, 480);
[self.view addSubview:viewController.view];
[self.view addSubview:toolbar];
[viewController release];
}
-(void)playpauseAction:(id)sender {
if([audioPlayer isPlaying])
{
[sender setImage:[UIImage imageNamed:#"Play Icon.png"] forState:UIControlStateSelected];
[audioPlayer pause];
[self pauseTimer];
[self pauseLayer:self.view.layer];
}
else
{
[sender setImage:[UIImage imageNamed:#"pause.png"] forState:UIControlStateNormal];
[audioPlayer play];
[self resumeTimer];
[self resumeLayer:self.view.layer];
if(isFirstTime == YES)
{
self.timer = [NSTimer scheduledTimerWithTimeInterval:11.0
target:self
selector:#selector(displayviewsAction:)
userInfo:nil
repeats:NO];
isFirstTime = NO;
}
}
}
rewind button when clicks perform rewind method and as well send notification to play button to perform playpauseAction method.
Thanks for help.
EDIT
Have declared
#property (nonatomic, retain) UIButton *playButton;
#synthesize playButton = _playButton;
[self playpauseAction:_playButton];
what happening is when clicking on rewind button it performing play pause action method but not toggling play button to pause as per playpauseaction method. why is that
In your view did load write this;
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(playpauseAction) name:#"ButtonPressed" object:nil];
When the button is pressed add this code;
[[NSNotificationCenter defaultCenter] postNotificationName:#"ButtonPressed" object:nil];
And it should call your playpauseAction.
Don't forget in your dealloc to write;
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"ButtonPressed" object:nil];
Otherwise you code will crash, as the method will still try to be called even when the instance of you class no longer exists.
Hope this helps,
Jonathan
If you have a reference to your play pause button (which you will want to have to make this kind of thing a ton easier), you can just write this line in your rewind method
[self playpauseAction:playpauseButton];
You don't need to use the notification center at all

Multiple methods: Target and Selector of button not working

Trying to solve my Other question. This time trying this way
Added multiple methods to one button but when clicking on button it does nothing looks like those methods are not working.
//Add Play Button
UIButton *playpauseButton = [UIButton buttonWithType:UIButtonTypeCustom];
[playpauseButton addTarget:self action:#selector(playAction:) forControlEvents:UIControlEventTouchUpInside];
[playpauseButton addTarget:self action:#selector(playpauseAction:) forControlEvents:UIControlEventTouchUpInside];
playpauseButton.frame = CGRectMake(0, 0, 30, 30);
[playpauseButton setImage:[UIImage imageNamed:#"Play Icon.png"] forState:UIControlStateNormal];
[playpauseButton setImage:[UIImage imageNamed:#"pause.png"] forState:UIControlStateSelected];
UIBarButtonItem *play = [[UIBarButtonItem alloc] initWithCustomView:playpauseButton];
- (void)playAction:(id)sender{
[audioPlayer play];
self.timer = [NSTimer scheduledTimerWithTimeInterval:11.0
target:self
selector:#selector(displayviewsAction:)
userInfo:nil
repeats:NO];
}
-(void)playpauseAction:(id)sender {
if ([audioPlayer isPlaying]){
[sender setImage:[UIImage imageNamed:#"Play Icon.png"] forState:UIControlStateSelected];
[audioPlayer pause];
[self pauseTimer];
} else {
[sender setImage:[UIImage imageNamed:#"pause.png"] forState:UIControlStateNormal];
[audioPlayer play];
[self resumeTimer];
self.timer = [NSTimer scheduledTimerWithTimeInterval:11.0
target:self
selector:#selector(displayviewsAction:)
userInfo:nil
repeats:NO];
}
}
-(void)pauseTimer{
pauseStart = [[NSDate dateWithTimeIntervalSinceNow:0] retain];
previousFireDate = [[timer fireDate] retain];
[timer setFireDate:[NSDate distantFuture]];
}
-(void)resumeTimer{
float pauseTime = -1*[pauseStart timeIntervalSinceNow];
[timer setFireDate:[previousFireDate initWithTimeInterval:pauseTime sinceDate:previousFireDate]];
[pauseStart release];
[previousFireDate release];
}
It shows play button when clicking on it nothing happens. It should play the audio file, start the NSTimer, start loading views and toggle between play and pause button. Any idea what is wrong.
Thanks.
When the user taps the button, the playAction: calls [audioPlayer play].
Immediately afterwards, the playpauseAction: evaluates [audioPlayer isPlaying] to YES and does [audioPlayer pause].

How to check if audioplayer is paused while loading multiple viewcontrollers

In playpauseAction Method execution it will play audio file as well as load multiple viewcontrollers
-(void)playpauseAction:(id)sender
{
if
([audioPlayer isPlaying]){
[sender setImage:[UIImage imageNamed:#"play.png"] forState:UIControlStateSelected];
[audioPlayer pause];
} else {
[sender setImage:[UIImage imageNamed:#"pause.png"] forState:UIControlStateNormal];
[audioPlayer play];
self.timer = [NSTimer scheduledTimerWithTimeInterval:11 target:self selector:#selector(displayviewsAction:) userInfo:nil repeats:NO];
}
}
While loading these view controllers just want to check in every viewcontroller that if audioplayer is paused then invalidate timer if not then continue loading of viewcontroller with NSTimer
- (void)displayviewsAction:(id)sender
{
FirstViewController *viewController = [[FirstViewController alloc] init];
viewController.view.frame = CGRectMake(0, 0, 320, 480);
[self.view addSubview:viewController.view];
[self.view addSubview:toolbar];
if
([audioPlayer pause]){
[timer invalidate];
} else {
self.timer = [NSTimer scheduledTimerWithTimeInterval:23 target:self selector:#selector(secondViewController) userInfo:nil repeats:NO];
}
[viewController release];
}
My problem is when i add if statement in displayviewAction method it gives me red warning message that statement requires expression of scalar type (void invalid).
But if statement in the playpauseAction works fine.
Why the if statement of displayviewAction is giving red warning message.
AVAudioPlayer's pause is defined as:
-(void)pause
so writing:
if([audioPlayer pause]) {...}
corresponds to write:
if(void) {...}
and void is not a scalar type, exactly what the error message tells you.
Probably your intention was to check if the audio player was paused, that is it is not playing :
if([audioPlayer isPlaying]==NO) {...}