简体   繁体   中英

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 UIImageView s 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 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM