Ответ 1
Возможно, я немного опоздал, но я думаю, что у меня есть что-то полезное для добавления. Если вы просто ищете ответ, перейдите к Как я его исправим?
Что такое MPVolumeView
?
Класс MPVolumeView
используется для установки слайдера на экране, который контролирует объем системы. Он должен предотвратить появление наложения системного объема, пока он находится на экране, но иногда это не так. Я столкнулся с этой проблемой, когда я добавил свой собственный MPVolumeView в иерархию представлений, но все же увидел, что наложение появилось при перетаскивании ползунка.
Как сообщает MPVolumeView
, когда он виден?
Это вопрос, который я задал себе. Каким-то образом класс определяет, видно ли это или нет, и сообщает системе, чтобы она скрывала или отображала наложение громкости системы соответственно. Это связано с тем, что Apple действительно не хочет, чтобы вы использовали этот класс, чтобы предотвратить появление наложения, без фактического отображения пользовательского интерфейса слайдера (как в ответе myell0w).
Вот как я считаю, MPVolumeView
пытается проверить, действительно ли это видно:
- Когда представление добавляется в супервизор, как определено
viewWillMoveToSuperview:
иviewDidMoveToSuperview
, он запускает короткий таймер. - Когда срабатывает таймер, представление пересекает его дерево предков, рекурсивное исследование свойства
superview
. -
MPVolumewView
проверяет, что каждый из его предков имеетhidden = NO
иalpha
больше некоторого небольшого значения (вероятно, 0,05).
Могут быть другие проверки, о которых я не знаю, поскольку этот код, конечно, закрыт. Таймер на шаге 1 существует таким образом, чтобы следующий код не "обманул" представление:
MPVolumeView *volView = [[MPVolumeView alloc] init];
[self.view addSubview:volView];
volView.hidden = YES;
потому что он проверяет свойство hidden
не сразу, а немного, после того, как он уже установлен на YES
.
Как я все это понял? Ключевая находка заключалась в том, что экземпляр MPVolumeView
вызывал isHidden
в своем супервизоре, как показано в следующей трассировке стека:
В чем была моя проблема?
Короче говоря, я сделал что-то вроде этого:
- (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;
}
Но когда я перетащил слайдер вновь обнаруженного MPVolumeView
, наложение все еще появилось. Я понял, что это произошло потому, что во время создания MPVolumeView
его супервизор был скрыт.
Как я это исправил?
Как только я понял, как класс MPVolumeView
оценил, было ли это видно, у меня был простой способ "обмануть" его. Я добавил следующий класс классу, отвечающему за MPVolumeView
:
- (void)refreshVolumeView {
[self.volView willMoveToSuperview:self];
[self.volView didMoveToSuperview];
}
и называть его каждый раз, когда мне нужно заставить представление переоценить, было ли оно видимым. Этот метод просто претендует на повторное добавление представления в иерархию. Как только я удовлетворю условиям, которые оценивает представление (каждый предок не скрыт или имеет очень низкую альфу), я называю это, и наложение перестает отображаться. В моем примере, приведенном выше, я бы добавил одну строку:
- (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
}