Question

So in my app I have a popover control with an embedded navigation control. In different parts of the navigation stack, I want the popover to be different colors depending on where the user is. The weird thing is sometimes setting the popover background color makes this terrible looking box around it, sometimes it doesn't. It looks like this:

enter image description here

This is the look I am trying to get:

enter image description here

It seems if I change the background color before displaying the popover it seems to work and transition correctly, but if I don't set the popover color before showing it, then change it after it has been shown it has the box effect. I've also noticed other cases where it seems to happen randomly, but I can't really explain what is causing it (my real app is much more complex than this demo). Here is the relevant code:

- (IBAction)buttonPressed:(id)sender {
    UIViewController *vc = [[UIViewController alloc] init];
    UIButton *b = [[UIButton alloc] init];
    [b addTarget:self action:@selector(innerButtonPressed) forControlEvents:UIControlEventTouchUpInside];
    [b setTitle:@"Button" forState:UIControlStateNormal];
    [b setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
    [b setFrame:CGRectMake(0,0,100,100)];
    [vc.view addSubview:b];
    _innerNav = [[UINavigationController alloc] initWithRootViewController:vc];
    _popOver = [[UIPopoverController alloc] initWithContentViewController:_innerNav];

    //If this line is here, everything works fine
    _popOver.backgroundColor = [UIColor yellowColor];

    [_popOver presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];

    //If this line is here (and the above line is commented out), the transition will look wrong
    //_popOver.backgroundColor = [UIColor yellowColor];
}

-(void)innerButtonPressed {
    _controller = [[UIViewController alloc] init];
    UIButton *b = [[UIButton alloc] init];
    [b addTarget:self action:@selector(test) forControlEvents:UIControlEventTouchUpInside];
    [b setTitle:@"Make Purple" forState:UIControlStateNormal];
    [b setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
    [b setFrame:CGRectMake(0,0,200,200)];
    [_controller.view addSubview:b];
    [_popOver setBackgroundColor:[UIColor orangeColor]];
    [_innerNav pushViewController:_controller animated:YES];
}

-(void)test{
    _popOver.backgroundColor = [UIColor purpleColor];
}

Any idea what is causing this issue? And what steps to safely update the background color of a popover without ever getting into this state? I have a full project demonstrating the problem, I thought you could attach projects to questions but apparently you cannot. If someone wants it I can probably host it somewhere.

Was it helpful?

Solution

After looking at your sample project, Apple's "Popover Controllers in iOS" sample project, perusing Apple's Documentation, and trying a few different things I have come to the following observations:

  • The UIPopoverController only exhibits this odd behavior when it is presented without a valid value for the backgroundColor property. From this I am guessing that since UIPopoverController's backgroundColor property is nil by default it must use different drawing code than when the backgroundColor property is valid.
  • Triggering some sort of redraw (e.x. Setting popoverContentSize) will get the colored box overlay to go away (it looks like it clips a color layer).

Conclusion: For the time being I would set a backgroundColor prior to the UIPopoverController being presented and then update it as needed. If this is not an option try updating the UIPopoverController such that it redraws (As a note: I was not able to get this to look good and it seems hacky). Lastly, I would report it as a bug to apple.

I hope this helps.

OTHER TIPS

UIPopoverController is now deprecated. I found a similar issue when updating it to use the new popoverPresentationController. In the past I was able to set the backgroundColor of UIPopoverController before presenting. The popover presentation controller also has a backgroundColor property but didn't work like it did before where I could assign it before presentation. To get it to work I had to assign it after it starts presenting for some reason:

contentViewController.modalPresentationStyle = UIModalPresentationPopover;
[[self presentViewController:contentViewController animated:YES completion:^{
    // completion code
}];
contentViewController.popoverPresentationController.backgroundColor = [UIColor orangeColor];

For your particular scenario where you are changing the background color after presentation is finished I don't think you'd be able to do that by just changing the popoverPresentationController's backgroundColor. The only solution I can think of is to dismiss and re-present the popover without animating:

[self dismissViewControllerAnimated:NO completion:^{

    contentViewController.modalPresentationStyle = UIModalPresentationPopover;

    [[self presentViewController:contentViewController animated:NO completion:^{
        // completion code
    }];
    contentViewController.popoverPresentationController.backgroundColor = [UIColor purpleColor];

}];
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top