A bit old question, but I also needed a solution for Gui13's question/comment:
We're not using any sort of control in our app, all volume interaction is based on volume buttons.. So I could maybe implement this but I'd need a way to tie it to the volume buttons. Is this possible?
Apple recommends using MPVolumeView
, so I came up with this:
MPVolumeView *volumeView = [MPVolumeView new];
[self.view addSubview:volumeView];
and then:
__block UISlider *volumeSlider = nil;
[[volumeView subviews] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([obj isKindOfClass:[UISlider class]]) {
volumeSlider = obj;
*stop = YES;
}
}];
[volumeSlider addTarget:self action:@selector(handleVolumeChanged:) forControlEvents:UIControlEventValueChanged];
with:
- (void)handleVolumeChanged:(id)sender
{
NSLog(@"%s - %f", __PRETTY_FUNCTION__, ((UISlider *)sender).value);
}
The [MPVolumeView new]
code above inits MPVolumeView
with no frame so, it's not visible in our self.view
where it has been added as a subview, but it is important that it has to be added!
You can also init the MPVolumeView
with the code:
MPVolumeView *volumeView = [[MPVolumeView alloc] initWithFrame:self.view.frame];
volumeView.showsRouteButton = NO;
volumeView.showsVolumeSlider = NO;
[self.view addSubview:volumeView];
which will also init the empty MPVolumeView
(i.e. without RouteButton and VolumeSlider).
What's interesting is that UISlider
subview (actually MPVolumeSlider
, the subclass of UISlider
) will still be found in the enumerateObjectsUsingBlock
above.
This approach is also interesting because you can save the reference to volumeSlider
and use it later to set volume from code, or your custom control:
Init and add to your view:
MPVolumeView *volumeView = [MPVolumeView new];
volumeView.showsRouteButton = NO;
volumeView.showsVolumeSlider = NO;
[self.view addSubview:volumeView];
Find and save reference to UISlider
:
__weak __typeof(self)weakSelf = self;
[[volumeView subviews] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([obj isKindOfClass:[UISlider class]]) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
strongSelf.volumeSlider = obj;
*stop = YES;
}
}];
Add target action for UIControlEventValueChanged
:
[self.volumeSlider addTarget:self action:@selector(handleVolumeChanged:) forControlEvents:UIControlEventValueChanged];
And then update your custom control when the volume has been changed (i.e. by the hardware volume controls):
- (void)handleVolumeChanged:(id)sender
{
NSLog(@"%s - %f", __PRETTY_FUNCTION__, self.volumeSlider.value);
self.myCustomVolumeSliderView.value = self.volumeSlider.value;
}
and also:
- (IBAction)myCustomVolumeSliderViewValueChanged:(id)sender {
NSLog(@"set volume to: %f", self.myCustomVolumeSliderView.value);
self.volumeSlider.value = self.myCustomVolumeSliderView.value;
}
Hope this helps someone (and that Apple doesn't remove MPVolumeSlider from MPVolumeView).