I'm having problem to control the iPhone controls with my avplayer.
if I put the function
- (void)remoteControlReceivedWithEvent:(UIEvent *)event
in the view controller that responsible for playing the function called but only if I i'm going to background in the current view controller.
if i'm going to background from other view controller the function never called.
that's why i want to put it in the app delegate.
I tried Becomefirstresponse and to put the function in every view controller but it did help.
also I call
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
in the
-(void)applicationWillResignActive:(UIApplication *)application
thanks
I have used below code to iPhone Control -
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
Used to get register for listening the remote control.
Once done remove it -
[[UIApplication sharedApplication] endReceivingRemoteControlEvents];
[self resignFirstResponder];
make the App canBecomeFirstResponder-
- (BOOL)canBecomeFirstResponder {
return YES;
}
Used delegate method to handle iPhone control, like play and pause while doble tap on the home button
- (void)remoteControlReceivedWithEvent:(UIEvent *)event {
//if it is a remote control event handle it correctly
if (event.type == UIEventTypeRemoteControl) {
if (event.subtype == UIEventSubtypeRemoteControlPlay) {
[audioPlayer play];
NSLog(#"play");
} else if (event.subtype == UIEventSubtypeRemoteControlPause) {
[audioPlayer stop];
NSLog(#"pause");
} else if (event.subtype == UIEventSubtypeRemoteControlTogglePlayPause) {
NSLog(#"toggle");
}
}
}
In my case i am able to handle play and pause.Please let know if any thing wrong.
You can move the function up the responder chain, to UIApplication subclass. This way, it will always be there to catch the event.
This kind of event is ignored in common UI and controller classes, so it travels up to the bottom of responder chain, where your app delegate and the the application itself reside.
As noted here, UIApplication's delegate is not part of responder chain (I was wrong here). UIApplication is there, so is root UIWidow, all the views in chain and corresponding UIViewControllers.
Hint: becomeFirstResponder must be called from within viewDidAppear, not viewWillAppear...
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self becomeFirstResponder];
}
Related
I have a App works well on iOS 4.3.3. But I found there are some problems on iOS 5. This App plays mp3 files by avaudioplayer and the remote control does not work well on iOS 5.
There are four view controllers in this App. I add following codes on each view controller in order to realize the function of remote control. The problem is, when the view controller is first time to open. The remote control button works well, even the app run in background or lock the screen. But when I click anther view controller and go back the previous on, the remote controller does not work anymore. But canBecomeFirstResponder function was called every time.
I even try to put
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
in delegate function
(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
It not work.
I don't understand why this is happening. It tortured me for few days.
Is there better way to realize remote control function in multiple view controllers?
BTW, I added the UIBackgroundModes audio key to the info.plist. And this App works well well in background.
Any help will be appreciated.
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
}
- (void)viewWillAppear:(BOOL)animated {
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[[UIApplication sharedApplication] endReceivingRemoteControlEvents];
[self resignFirstResponder];
}
- (BOOL) canBecomeFirstResponder {
NSLog(#"Can be first responder!");
return YES;
}
- (void)remoteControlReceivedWithEvent:(UIEvent *)event
{
if (event.subtype == UIEventSubtypeRemoteControlTogglePlayPause) {
NSLog(#"UIEventSubtypeRemoteControlTogglePlayPause");
[self playAndpause:nil];
}
}
I'm trying to make a shake events.
I tried:
1) How do I detect when someone shakes an iPhone? (posts of Kendall, and Eran)
2) motionBegan: Not Working
but nothig helps.
My View becomes first responder, but motionBegan/motionEnded never called.
Is there some additiol settings must be done, or i'm missing somethig? My iOS SDK is 4.3.
I have a class of UIView:
#import "ShakeView.h"
#implementation ShakeView
- (BOOL)canBecomeFirstResponder {
return YES;
}
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
NSLog (#"123");
if ( event.subtype == UIEventSubtypeMotionShake ) {
NSLog(#"Shake!");
}
if ([super respondsToSelector:#selector(motionEnded:withEvent:)]) {
[super motionEnded:motion withEvent:event];
}
}
#end
In my ViewController's xib class of View is ShakeView.
my ViewController pushed:
Wheel *secondViewController = [[Wheel alloc] initWithNibName:#"Wheel" bundle:nil];
[self.navigationController pushViewController:secondViewController animated:YES];
[secondViewController release];
In my ViewController:
- (void) viewDidAppear:(BOOL)animated
{
[self.view becomeFirstResponder];
[super viewWillAppear:animated];
NSLog(#"%d", [self.view isFirstResponder]);
}
- (void) viewWillDisappear:(BOOL)animated
{
[self.view resignFirstResponder];
[super viewWillDisappear:animated];
}
It logs "1", so it IS first responder. But it logs nothing else.
I spend a half day on this few lines of code, and I have no more ideas. Do anyone knows how to solve it?
Thanks.
This is much too late to help SentineL, but I was having the same problem and I like his question because it is clear that he has all the relevant code in place -- except one crucial line, in the application delegate's didFinishLaunching:
[self.window makeKeyAndVisible];
This is very hard to debug, because even without this line, everything else will be fine. Your gestures will work, your controls will respond, you will be able to make your view first responder (as SentineL checked) -- but your subclassed window or view or view controller will never receive the motion events.
Which doesn't make sense to me. Why would makeKeyAndVisible affect the accelerometer but not gestures? Hopefully some more experienced user can answer that.
P.S. If you use this code as an example, I would recommend that you omit the super respondsToSelector conditional. Of course it responds to the selector; you're overriding it.
How do I use shake-events in iOS 4.0+? I tested this solution but isn't working in 4.1. Is it possible that something changed or am I doing someting wrong? motionBegan: Not Working
From this SO question How do I detect when someone shakes an iPhone?
The main trick is that you need to have some UIView (not view controller) that you want as firstResponder to receive the shake event messages. Here's the code that you can use in any UIView to get shake events:
#implementation ShakingView
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
if ( event.subtype == UIEventSubtypeMotionShake )
{
// Put in code here to handle shake
}
if ( [super respondsToSelector:#selector(motionEnded:withEvent:)] )
[super motionEnded:motion withEvent:event];
}
- (BOOL)canBecomeFirstResponder
{ return YES; }
#end
You can easily transform any UIView (even system views) into a view that can get the shake event simply by subclassing the view with only these methods (and then selecting this new type instead of the base type in IB, or using it when allocating a view).
In the view controller, you want to set this view to become first responder:
- (void) viewWillAppear:(BOOL)animated
{
[shakeView becomeFirstResponder];
[super viewWillAppear:animated];
}
- (void) viewWillDisappear:(BOOL)animated
{
[shakeView resignFirstResponder];
[super viewWillDisappear:animated];
}
Don't forget that if you have other views that become first responder from user actions (like a search bar or text entry field) you'll also need to restore the shaking view first responder status when the other view resigns!
This method works even if you set applicationSupportsShakeToEdit to NO.
i have questions regarding the shake detection that posted here before,
here is a reminder:
"Now ... I wanted to do something similar (in iPhone OS 3.0+), only in my case I wanted it app-wide so I could alert various parts of the app when a shake occurred. Here's what I ended up doing.
First, I subclassed UIWindow. This is easy peasy. Create a new class file with an interface such as MotionWindow : UIWindow (feel free to pick your own, natch). Add a method like so:
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
if (event.type == UIEventTypeMotion && event.subtype == UIEventSubtypeMotionShake) {
[[NSNotificationCenter defaultCenter] postNotificationName:#"DeviceShaken" object:self];
}
}
Now, if you use a MainWindow.xib (stock Xcode template stuff), go in there and change the class of your Window object from UIWindow to MotionWindow or whatever you called it. Save the xib. If you set up UIWindow programmatically, use your new Window class there instead.
Now your app is using the specialized UIWindow class. Wherever you want to be told about a shake, sign up for them notifications! Like this:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(deviceShaken) name:#"DeviceShaken" object:nil];
To remove yourself as an observer:
[[NSNotificationCenter defaultCenter] removeObserver:self];
questions:
where to put the notifications (i have a view based app) ?
do i have to remove myself as an observe, what does it mean ?
what is the if statement that i use to check if the shake accrued?
how can i know if the shake event know it is "already in progress" ?
thanks.
In iPhone OS 3.x it is simple to receive motion events form any view that is set as the first responder.
In you view class override the method motionEnded:, like this:
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
if(motion == UIEventSubtypeMotionShake && [self isViewLoaded])
{
//handle shake here...
}
}
In addition, you will need to become the First Responder when the view is loaded and appears:
- (void)viewDidAppear:(BOOL)animated
{
[self becomeFirstResponder];
[super viewDidAppear:animated];
//any extra set up code...
}
You may also have to respond to the canBecomeFirstResponder method.
- (BOOL)canBecomeFirstResponder
{
return YES;
}
These can be used in any object that inherits form UIView.
I have this inside my viewController:
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
if (event.type == UIEventSubtypeMotionShake) {
NSLog(#"I have shaked");
}
}
Why is this not working?
Edit:
I do infact have this:
- (void) viewWillAppear:(BOOL)animated
{
[shakeView becomeFirstResponder];
[super viewWillAppear:animated];
}
- (void) viewWillDisappear:(BOOL)animated
{
[shakeView resignFirstResponder];
[super viewWillDisappear:animated];
}
If the UIViewController is loaded at the very start of the application, I've seen an odd glitch in OS 3.0 where it would not become the first responder unless you delayed the appropriate message a bit. Try placing
[self performSelector:#selector(becomeFirstResponder) withObject:nil afterDelay:0.3];
within -loadView or something else that is called when the controller is first set up.
There may be a more elegant way to work around this, but this approach has worked for me.
The viewController must be the first responder during the shake to receive this event.
This could be one reason it's not working.