Проблема
При отображении пользовательского контроллера плеера на экране (iOS 4) я использую AVPlayerLayer
для отображения. Я хочу создать несколько оверлеев поверх плеера (рекламные баннеры, элементы управления плеером и т. Д.). На данный момент это работает абсолютно нормально со следующей иерархией:
UIView(self.view)\
| UIView(controlsView)\
* | UIView [some movie player controls]
| UIView [some more movie player controls]
*
AVPlayerLayer
- это подслой self.view
. При загрузке плеера я сначала добавляю слой к self.view
и вызываю bringSubviewToFront:
на controlsView
, а затем обнаруживаю касания по нему и программно показываю / исчезаю по таймеру / как угодно. Здесь нет проблем.
Теперь, когда у меня есть поддержка динамического извлечения и отображения рекламного контента, я хотел бы установить следующую иерархию:
UIView(self.view)\
| UIImageView (ad banner)
| UIImageView (another ad banner)
| ...
| UIView(controlsView)\
* | UIView [some movie player controls]
| UIView [some more movie player controls]
*
При загрузке плеера я затем присоединяю к своему экземпляру AVPlayer
некоторые addBoundaryTimeObserverForTimes:queue:usingBlock:
звонки для постепенного исчезновения рекламных баннеров в соответствующее время. При этом я добавляю UIImageView
s к self.view
как подпредставления без явного упорядочения (следовательно, они должны быть нарисованы поверх всего остального) и setHidden:YES
на них.
Я NSLog
'd, и эти блоки затухания выполняются правильно, установив view.alpha = 1.0f
и view.alpha = 0.0f
для показа и скрытия соответственно на рекламных баннерах, но вообще ничего не появляется, даже если явно установить UIImage
отображается при просмотре известного рабочего локального изображения и в кадре на (0, 0, 320, 480)
, плюс установка autoresizingMask
из
UIViewAutoresizingFlexibleTopMargin |
UIViewAutoresizingFlexibleLeftMargin |
UIViewAutoresizingFlexibleRightMargin;
По умолчанию UIViewContentMode
(должно быть UIViewContentModeScaleToFill
).
Решение, которое я нашел для решения проблемы
На самом деле это вообще не решает проблему, но теперь я использую непрозрачность 0,1% в качестве замены непрозрачности 0%. Эффективно скрывает элемент, не вызывая проблем, и затухания / затухания работают хорошо.
Поиск и устранение неисправностей
Чтобы убедиться, что я не рисовал фильм поверх всех неуправляемых видов, я переместил AVPlayerLayer
в дополнительный вид, videoView
:
UIView(self.view)\
| UIView(videoView)
| UIImageView (ad banner)
| UIImageView (another ad banner)
| ...
| UIView(controlsView)\
* | UIView [some movie player controls]
| UIView [some more movie player controls]
*
Я явно звоню sendSubviewToBack:videoView
и bringSubviewToFront:controlsView
, но все равно не люблю. Я могу видеть оверлейные объявления на экране, если не позвоню setHidden:YES
, когда впервые добавлю их в иерархию просмотра. Кикер таков: объявление также исчезает в правильное время (в ответ на overlayImage.alpha = 0.0f
в моих блоках анимации), поэтому я знаю, что мои блоки анимации в порядке.
Вот фрагмент кода для добавления рекламных баннеров в вид моего проигрывателя фильмов:
for(MyCustomAdBannerClass *overlay in overlays)
{
UIImageView *overlayImage =
[[UIImageView alloc] initWithImage:
[UIImage initWithData:
[NSData dataWithContentsOfURL:[overlay contentURL]]]];
UIViewAutoresizing autoresizingFlags =
UIViewAutoresizingNone;
CGFloat x, y, width, height;
width = [overlay width];
height = [overlay height];
// <snip> set x, y, autoresizing values of the above vars
[overlayImage setFrame:CGRectMake(x, y, width, height)];
[overlayImage setAutoresizingMask:autoresizingFlags];
[self.view addSubview:overlayImage];
}
for(UIView *subview in self.view.subviews)
{
if(subview == controlsView)
[self.view bringSubviewToFront:subview];
else if(subview == videoView)
[self.view sendSubviewToBack:subview];
else
[subview setHidden:YES];
}
Вот код, который я использую для добавления наложенных / исчезающих обратных вызовов (overlay
- это объект с информацией о том, когда показывать наложение и как долго, overlayImage
- это UIImageView
, содержащий фактический рекламный баннер ):
[self.player
addBoundaryTimeObserverForTimes:[NSArray arrayWithObject:
[overlay startTime]]
queue:dispatch_get_main_queue()
usingBlock:^{
[UIView
animateWithDuration:0.7
animations:^{
overlayImage.alpha = 1.0f;
dispatch_time_t popTime =
dispatch_time(DISPATCH_TIME_NOW,
[overlay duration] * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(),
^(void){
[UIView
animateWithDuration:0.7
animations:^{
overlayImage.alpha = 0.0f;
[overlayImage removeFromSuperview];
}];
}];
}];
}];
Как я уже сказал, этот overlayImage.alpha = 0.0f;
вызов выполняется правильно .
ПРИМЕЧАНИЕ: Только что попробовал установить overlay.alpha = 0.5f;
вместо 0.0f
при первом добавлении видов. Наложение FADES IN теперь правильно. Таким образом, происходит нечто странное с тем, чтобы сделать представление на 100% невидимым, что не позволяет его снова показывать позже. Никаких сбоев, так что это не просто ссылка на освобожденную память.
Попытка обхода
Я попытался отправить все наложения рекламы за videoView
, а затем, когда нужно было показать каждый из них, я позвонил
[overlayImage removeFromSuperview];
[self.view insertSubview:overlayImage aboveView:videoView];
// dispatch hide animation
Все еще не показывает их, но все равно исчезает, когда я опускаю setHidden:YES
.