Возможно, я немного опоздал, но думаю, мне есть что добавить. Если вы просто ищете ответ, перейдите к Как я это исправил?
Что такое 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
}