I've put a MPVolumeView over a movie I'm playing. The trouble is, whenever I adjust the vol using the MPVolumeView, then the standard grey volume overlay appears (the one that appears when you use the rocker switch on the iPhone). Is there a way to disable the standard grey overlay?
I might be a bit late, but I think I have something useful to add. If you're just looking for an answer, skip to How did I fix it?
What is MPVolumeView
?
The MPVolumeView
class is used to put a slider onscreen that controls the system volume. It's supposed to prevent the system volume overlay from appearing while it is onscreen, but sometimes does not. I ran into this issue when I added my own MPVolumeView to the view hierarchy, but still saw the overlay appear when I dragged the slider.
How does MPVolumeView
tell when it is visible?
This is the question I asked myself. Somehow, the class detects whether or not it is visible, and tells the system to hide or display the system volume overlay accordingly. This is because Apple does not really want you using the class just to prevent the overlay from appearing, without actually displaying the slider UI to the user (as in myell0w's answer).
Here's how I believe MPVolumeView
tries to check if it is really visible:
viewWillMoveToSuperview:
and viewDidMoveToSuperview
, it starts a short timer.superview
property.MPVolumewView
checks that each of its ancestors has hidden = NO
and alpha
greater than some small value (likely 0.05). There could be other checks that I'm not aware of, since this code is of course closed-source. The timer in step 1 is there so that code like the following will not "fool" the view:
MPVolumeView *volView = [[MPVolumeView alloc] init];
[self.view addSubview:volView];
volView.hidden = YES;
because it will check the hidden
property not immediately, but in a bit, after it is already set to YES
.
How did I figure all of this out? A key find was that the instance of MPVolumeView
was calling isHidden
on its superview, as shown in the following stack trace:
What was my problem?
In short, I did something like this:
- (void)viewDidLoad {
// Add an MPVolumeView to my view
self.volView = [[MPVolumeView alloc] init];
[self.view addSubview:self.volView];
self.volView.hidden = YES;
}
- (void)someButtonTouched {
// Show the MPVolumeView (and hopefully hide the system overlay)
self.volView.hidden = NO;
}
But when I dragged the slider of the newly revealed MPVolumeView
, the overlay still appeared. I realized that this was because during the MPVolumeView
's instantiation, its superview was hidden.
How did I fix it?
Once I had realized how the MPVolumeView
class judged whether it was visible, I had an easy way to "fool" it. I added the following method to the class responsible for the MPVolumeView
:
- (void)refreshVolumeView {
[self.volView willMoveToSuperview:self];
[self.volView didMoveToSuperview];
}
and called it each time I need to force the view to reevaluate whether it was visible. This method simply pretends to re-add the view to the hierarchy. Once I've satisfied the conditions that the view evaluates (each ancestor is not hidden or of very low alpha), I call it, and the overlay stops showing up. In my example code above, I would add one line:
- (void)viewDidLoad {
// Add an MPVolumeView to my view
self.volView = [[MPVolumeView alloc] init];
[self.view addSubview:self.volView];
self.volView.hidden = YES;
}
- (void)someButtonTouched {
// Show the MPVolumeView (and hopefully hide the system overlay)
self.volView.hidden = NO;
[self refreshVolumeView]; // <<< This line was added
}