Проблема с порядком отображения UIView?

Проблема

При рисовании пользовательского контроллера видеоплеера на экране (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: вызовов, чтобы рекламные баннеры появлялись и исчезали в соответствующее время. Когда я это делаю, я добавляю UIImageViews к self.view как подпредставления без явного порядка (поэтому они должны быть нарисованы поверх всего остального) и setHidden:YES на них.

Я сделал NSLog, и эти блоки затухания выполняются правильно, устанавливая 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 при первом добавлении представлений. Теперь оверлей ИСЧЕЗАЕТ. Таким образом, происходит что-то странное, когда вид становится на 100% невидимым, что предотвращает его повторное отображение позже. Никаких сбоев, так что это не просто ссылка на освобожденную память.


Попытка обходного пути

Я попытался отправить все рекламные оверлеи за videoView, а затем, когда нужно было показать каждый из них, я позвонил

[overlayImage removeFromSuperview];
[self.view insertSubview:overlayImage aboveView:videoView];
// dispatch hide animation

По-прежнему не показывает их, но все равно правильно исчезает, когда я опускаю setHidden:YES.


person Community    schedule 01.06.2011    source источник
comment
Скрытые и альфа-свойства полностью разделены. Если вы скроете представление, изменение альфы не отобразит его, пока вы не отобразите его.   -  person ughoavgfhw    schedule 02.06.2011
comment
@ughoavgfhw: На самом деле это неправильно. Даже когда я меняю метод на setAlpha:0.0f вместо setHidden:YES, поведение идентично (ничего не отображается), а затем, когда я пропускаю вызов setAlpha:0.0f, он отображается с самого начала, а затем исчезает в нужное время.   -  person    schedule 02.06.2011


Ответы (1)


Обратите внимание, что теперь я использую 0.001f вместо 0.0f, и проблем с отображением нет. Я все еще стремлюсь выяснить, почему он делает это, хотя.

person Community    schedule 02.06.2011