1
votes

I am customizing the appearance of my popovers by subclassing UIPopoverBackgroundView. Everything is working fine, except there are some instances where there is a gap between the arrow and the content view. If I keep rotating the device to dismiss the popover then bring it back up, sometimes they line up and others they do not. I'm logging the frame sizes and they are consistently the same, so I have no idea what's going on. I'm attaching screenshots and my layoutSubviews code below.

Where you see me subtracting 4 in the case of arrow direction right this was based on trial & error of getting it to work at least some of the time. I hate coding like this because I'm not sure what this space of 4 points is and why I don't need it in all cases of arrow direction, for example.

In the images the 1st shot shows the problem. This happened on a random triggering of the popover. The next image shows it randomly working when triggered later within the same execution of the app.

Also worth mentioning, I found some sample code at http://blog.teamtreehouse.com/customizing-the-design-of-uipopovercontroller and tried this version of layoutSubviews, even though it's already very similar to what I have. Even with this code I was still seeing the same issue.

EDIT: Worth mentioning it might be obvious from my screenshots but I am not including a border for my popover:

+ (UIEdgeInsets)contentViewInsets
{
    return UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 0.0f);
}

Possibly also worth mentioning I am not using an image file for my arrow image but rather am drawing it custom. Again, even when I comment out the drawing I'm still having the issue, so I don't think it's related, but wanted to mention it for full disclosure.

Any help greatly appreciated. Thanks.

CGSize arrowSize = CGSizeMake(kCMAPopoverBackgroundViewArrowBase, kCMAPopoverBackgroundViewArrowHeight);
// Leaving code out for drawArrowImage - even when I leave the arrowImageView as 
// an empty image view and set a non-clear background color this gap is still 
// sporadically showing up
self.arrowImageView.image = [self drawArrowImage:arrowSize];

float arrowXCoordinate = 0.0f;
float arrowYCoordinate = 0.0f;
CGAffineTransform arrowRotation = CGAffineTransformIdentity;

float borderMargin = 2.0f;

switch (self.arrowDirection) {
    case UIPopoverArrowDirectionUp:
        arrowXCoordinate = ((self.bounds.size.width / 2.0f) - (arrowSize.width / 2.0f));
        arrowYCoordinate = 0.0f;
        break;

    case UIPopoverArrowDirectionDown:
        arrowXCoordinate = ((self.bounds.size.width / 2.0f) - (arrowSize.width / 2.0f));
        arrowYCoordinate = self.bounds.size.height - arrowSize.height;
        arrowRotation = CGAffineTransformMakeRotation(M_PI);
        break;

    case UIPopoverArrowDirectionLeft:
        arrowXCoordinate = 0.0f - (arrowSize.height / 2.0f) + borderMargin;
        arrowYCoordinate = ((self.bounds.size.height / 2.0f) - (arrowSize.height / 2.0f));
        arrowRotation = CGAffineTransformMakeRotation(-M_PI_2);
        break;

    case UIPopoverArrowDirectionRight:
        arrowXCoordinate = self.bounds.size.width - arrowSize.height - 4.0f;
        arrowYCoordinate = ((self.bounds.size.height / 2.0f) - (arrowSize.height / 2.0f));
        arrowRotation = CGAffineTransformMakeRotation(M_PI_2);
        break;

    default:
        break;

}

self.arrowImageView.frame = CGRectMake(arrowXCoordinate, arrowYCoordinate, arrowSize.width, arrowSize.height);
[self.arrowImageView setTransform:arrowRotation];

Here is an example of the issue happening on a random occurrence

This is an example of it not happening on another random occurrence on the

2

2 Answers

1
votes

Is your arrow image square? If not, I'm guessing that the transform is affecting its frame slightly and this is generating the unexpected gap.

0
votes

Possibly you are getting subpixel values in your calculations (most likely 0.5)

Try using floorf or ceilf to make sure your values are landing exactly on pixel integral values.

For example...

arrowXCoordinate = floorf(((self.bounds.size.width / 2.0f) - (arrowSize.width / 2.0f)));

See floor reference.