ios - UIView 显示顺序问题?

标签 ios objective-c cocoa-touch uiimageview uiviewanimation

问题

在屏幕上绘制自定义电影播放器​​ Controller (iOS 4) 时,我使用 AVPlayerLayer显示。我希望在播放器顶部合成一些叠加层(广告横幅、播放器控件等)。目前,这对以下层次结构非常有效:

UIView(self.view)\
                 | UIView(controlsView)\
                 *                     | UIView [some movie player controls]
                                       | UIView [some more movie player controls]
                                       *

The AVPlayerLayer is a sublayer of self.view. On player load, I add the layer to self.view first and call bringSubviewToFront: on the controlsView, and then detect taps on it and programmatically show/fadeout on a timer/whatever. No issue here.

Now that I have support for dynamically fetching and displaying advertising content, I would like to set up the following hierarchy:

UIView(self.view)\
                 | UIImageView (ad banner)
                 | UIImageView (another ad banner)
                 | ...
                 | UIView(controlsView)\
                 *                     | UIView [some movie player controls]
                                       | UIView [some more movie player controls]
                                       *

At player load, what I then do is attach to my AVPlayer instance some addBoundaryTimeObserverForTimes:queue:usingBlock: calls to fade the ad banners in and out at appropriate times. As I do this, I add the UIImageViews to self.view as subviews with no explicit ordering (hence they should be drawn on top of everything else), and setHidden:YES on them.

I've NSLog'd and these fade blocks are correctly being executed, setting view.alpha = 1.0f and view.alpha = 0.0f for show and hide respectively on the ad banners, but nothing is appearing at all, even when explicitly setting the UIImage displayed by the view to a known working local image and the frame to (0, 0, 320, 480), plus setting an autoresizingMask of

UIViewAutoresizingFlexibleTopMargin  |
UIViewAutoresizingFlexibleLeftMargin |
UIViewAutoresizingFlexibleRightMargin;
UIViewContentMode是默认值(应该是 UIViewContentModeScaleToFill )。

我解决问题的“解决方案”

这实际上根本没有解决这个问题,但我现在使用 0.1% 的不透明度来代替 0% 的不透明度。有效地隐藏元素而不会引起问题,并且淡入/淡出运行良好。

疑难解答

为了确保我没有在所有非控件 View 的顶部绘制电影,我移动了 AVPlayerLayer到另一个 View ,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]
                                       *

I explicitly call sendSubviewToBack:videoView and bringSubviewToFront:controlsView, but still no love. I can see the overlay ads on-screen if I don't call setHidden:YES when I first add them to the view hierarchy. The kicker is this: the ad also disappears at the correct time (in response to overlayImage.alpha = 0.0f in my animation blocks), so I know my animation blocks are fine.

Here is a code snippet to do with adding the ad banners to my movie player's view:

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; call 正在正确执行。

注意:刚试过设置overlay.alpha = 0.5f;而不是 0.0f首次添加 View 时。叠加层现在正确淡入。因此,让 View 100% 不可见会发生一些奇怪的事情,这会阻止它在以后再次显示。没有崩溃,所以它不仅仅是引用释放的内存。

尝试的解决方法

我尝试在 videoView 后面发送所有广告叠加层然后当每一个要展示时,我调用
[overlayImage removeFromSuperview];
[self.view insertSubview:overlayImage aboveView:videoView];
// dispatch hide animation

仍然没有显示它们,但是当我省略 setHidden:YES 时仍然会正确消失.

最佳答案

请注意,我现在使用 0.001f而不是 0.0f并且没有显示问题。不过,我仍然很想弄清楚它为什么会这样做。

关于ios - UIView 显示顺序问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6197741/

相关文章:

ios - ReactiveCocoa - 忽略所有值

ios - 无法将 UINavigationBar 中的图像设置到中心

ios - 平滑我的滚动 TouchesMoved

ios - 如何在iPad中运行Interactive PDF文件?

cocoa-touch - 如何防止 NSPropertyListSerialization 崩溃?

ios - 在sqlite数据库中插入多个表数据

ios - UISegmentedControl tintColor

ios - 在 iOS 中,使用 Storyboard,如何在容器 View 中设置 View Controller ?

ios - 如何找出触摸事件在哪个 View 结束?

iphone - 控制台消息 : "snarfed from ivar layout..."? 的含义是什么