可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I want to implement the same behavior with the native camera of iOS5
:
- press the volume + button to take a photo
What's the ideal way to archive it?
Are there any ways to capture the volume key pressed event?
After googling & searching around for hours, I found 1 solution: using NSNotificationCenter
:
...
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(volumeChanged:)
name:@"AVSystemController_SystemVolumeDidChangeNotification"
object:nil];
...
- (void)volumeChanged:(NSNotification *)notification{
[self takePhoto];
}
However, it has 2 issues:
- There is an semi-transparent overlay of "current system volume" show up every time when pressing the volume key, this is not what I wanted.
- For the native camera, when you press the volume key as shutter, the system volume won't change, however, by using the above method, the system volume will change.
回答1:
I've found another way to hide the "system volume overlay" and "bypass the system volume change when the volume key pressed" by myself.
The bad part: this is an super UGLY hack.
However, the good part is: this ugly hack uses NO private APIs.
Another note is: it only works for ios5+ (anyway, for my issue, since the AVSystemController_SystemVolumeDidChangeNotification only works for ios5, so this UGLY hack just fits my issue.)
The way it work: "act as a music/movie player app and let the volume key to adjust the application-volume".
Code:
// these 4 lines of code tell the system that "this app needs to play sound/music"
AVAudioPlayer* p = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"photo-shutter.wav"]] error:NULL];
[p prepareToPlay];
[p stop];
[p release];
// these 5 lines of code tell the system that "this window has an volume view inside it, so there is no need to show a system overlay"
[[self.view viewWithTag:54870149] removeFromSuperview];
MPVolumeView* vv = [[MPVolumeView alloc] initWithFrame:CGRectMake(-100, -100, 100, 100)];
[self.view addSubview:vv];
vv.tag = 54870149;
[vv release];
(5 hours spending on discovering this super ugly method... shit... 草尼马啊!)
Another thing:
if you take the above hack, you need to run the code EVERY-TIME when your app become active.
So, you might need to put some code into your app delegate.
- (void)applicationDidBecomeActive:(UIApplication *)application
回答2:
Building on huxia's code, this works on ios5+, no need to run the code every time it becomes active, just run it once in the beginning.
// these 4 lines of code tell the system that "this app needs to play sound/music"
AVAudioPlayer* p = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"photoshutter.wav"]] error:NULL];
[p prepareToPlay];
[p stop];
//make MPVolumeView Offscreen
CGRect frame = CGRectMake(-1000, -1000, 100, 100);
MPVolumeView *volumeView = [[MPVolumeView alloc] initWithFrame:frame];
[volumeView sizeToFit];
[self.view addSubview:volumeView];
回答3:
…
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(volumeChanged:)
name:@"AVSystemController_SystemVolumeDidChangeNotification"
object:nil];
…
- (void)volumeChanged:(NSNotification *)notification{
CGRect frame = CGRectMake(-1000, -1000, 100, 100);
MPVolumeView *volumeView = [[MPVolumeView alloc] initWithFrame:frame];
[volumeView sizeToFit];
[self.view addSubview:volumeView];
[volumeView release];
[self takePhoto];
}
回答4:
There's currently no official way to capture the volume key pressed event. Apple's stated line is that the volume button works with the UIImagePickerController
if you've allowed it to show camera controls.
Other approaches, such as listening for the notification, seem to be unsupported hacks that Apple's team are — anecdotally — sometimes turning a blind eye to. To prevent the volume HUD from appearing you can use the undocumented UIApplication
methods:
- (void)setSystemVolumeHUDEnabled:(BOOL)enabled;
- (void)setSystemVolumeHUDEnabled:(BOOL)enabled forAudioCategory:(NSString *)category;
The only statement of their use I've seen is:
UIApplication *app = [UIApplication sharedApplication];
[app setSystemVolumeHUDEnabled:NO forAudioCategory:@"Ringtone"];
[app setSystemVolumeHUDEnabled:NO];
I'm unsure if or why you seemingly need to disable the HUD for a specific category and then in general, but without proper documentation that's difficult to figure out.
So: use UIImagePickerController
and its camera buttons if you want to be within the rules. If you've found an app that seems to work outside of the rules then it's probably using the methods above.
回答5:
I call this method from viewDidAppear
-(void) startTrackingVolume
{
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient withOptions:AVAudioSessionCategoryOptionMixWithOthers error:nil];
[[AVAudioSession sharedInstance] setActive:YES error:nil];
if (!self.volumeView) {
// put it somewhere outside the bounds of parent view
self.volumeView = [[MPVolumeView alloc] initWithFrame:CGRectMake(-100, -100, 10, 0)];
[self.volumeView sizeToFit];
}
if (!self.volumeView.superview) {
[self.view addSubview:self.volumeView];
}
}
In viewWillDisappear
in call
[[AVAudioSession sharedInstance] setActive:NO error:nil];