开发者

UIView display order issue?

The problem

When drawing a custom movie player controller on-screen (iOS 4), I use an AVPlayerLayer to display. I wish to composite some overlays on top of the player (ad banners, player controls, etc). At the moment, this works absolutely fine with the following hierarchy:

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;

The UIViewContentMode is default (should be UIViewContentModeScaleToFill).


The 'solution' I've gone with 开发者_JAVA技巧for the problem

This doesn't actually address the issue at all, but I'm now using 0.1% opacity as a replacement for 0% opacity. Effectively hides the element without causing issues, and fadeins/fadeouts are working well.


Troubleshooting

To make sure I wasn't drawing the movie over the top of all non-controls views, I moved the AVPlayerLayer to an additional 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];
}

Here is the code I use for adding the overlay appear/disappear callbacks (overlay is an object with information about when to show the overlay and how long for, overlayImage is the UIImageView containing the actual ad banner):

[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];
                              }];
                          }];
                }];
}];

As I said, that overlayImage.alpha = 0.0f; call is being executed correctly.

NOTE: Just tried setting overlay.alpha = 0.5f; instead of 0.0f when the views are first added. The overlay FADES IN properly now. So there is something funky going on with making the view 100% invisible which prevents it from being shown again at a later date. No crashes, so it's not just referencing dealloced memory.


Attempted workaround

I tried sending all the ad overlays behind videoView and then when each one was to be shown I called

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

Still doesn't show them, but still fades properly when I omit setHidden:YES.


Note that I am now using 0.001f instead of 0.0f and there are no display issues. I'm still keen to figure out why it does this though.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜