Gold Challenge


#1

The gold challenge was kinda difficult, Apple documentation is very limited/hard to understand in this one. My solution comes from an example i found online at http://www.scianski.com/customizing-uipopover-with-uipopoverbackgroundview/. I did my best to simplify it, since it uses things like ivars, defines and interface implementations in the .m file.

MyCustomPopOverBackground.h

#import <UIKit/UIKit.h>

@interface MyCustomPopOverBackground : UIPopoverBackgroundView
{
}

@property (nonatomic, readwrite)            CGFloat                  arrowOffset;
@property (nonatomic, readwrite)            UIPopoverArrowDirection  arrowDirection;
@property (nonatomic, readwrite, strong)    UIImageView             *arrowImageView;
@property (nonatomic, readwrite, strong)    UIImageView             *popoverBackgroundImageView;

@end

MyCustomPopOverBackground.m

#import "MyCustomPopOverBackground.h"

@implementation MyCustomPopOverBackground

@synthesize arrowOffset, arrowDirection, popoverBackgroundImageView, arrowImageView;

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        
        UIImage *popoverBackgroundImage = [[UIImage imageNamed:@"background-image.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(5, 5, 5, 5)];
        self.popoverBackgroundImageView = [[UIImageView alloc] initWithImage:popoverBackgroundImage];
        [self addSubview:self.popoverBackgroundImageView];
        
        self.arrowImageView = [[UIImageView alloc] init];
        [self addSubview:self.arrowImageView];
    }
    return self;
}

+ (CGFloat)arrowBase
{
    return 13.0; // width of the arrow image 
}

+ (CGFloat)arrowHeight
{
    return 25.0; // height of the arrow image 
}

+ (UIEdgeInsets)contentViewInsets{
    return UIEdgeInsetsMake(5, 5,
                            5, 5); // background image has roudned edges of 5 pixels
}

// Custom setters

// Whenever arrow changes direction or position layout subviews
// will be called in order to update arrow and backgorund images frames

-(void) setArrowOffset:(CGFloat)ao
{
    arrowOffset = ao;
    [self setNeedsLayout];
}

-(void) setArrowDirection:(UIPopoverArrowDirection)ad
{
    arrowDirection = ad;
    [self setNeedsLayout];
}

-(void)layoutSubviews
{
    [super layoutSubviews];
    
    NSLog(@"layoutSubviews");
    
    CGFloat popoverImageOriginX = 0;
    CGFloat popoverImageOriginY = 0;
    
    CGFloat popoverImageWidth = self.bounds.size.width;
    CGFloat popoverImageHeight = self.bounds.size.height;
    
    CGFloat arrowImageOriginX = 0;
    CGFloat arrowImageOriginY = 0;
    
    CGFloat arrowImageWidth = 13.0;
    CGFloat arrowImageHeight = 25.0;
    
    // Radius value you used to make rounded corners in your popover background image
    CGFloat cornerRadius = 5;
    
    switch (self.arrowDirection) {
                   
        case UIPopoverArrowDirectionDown:
            
            NSLog(@"UIPopoverArrowDirectionDown");
            
            NSLog(@"self.arrowOffset %f",self.arrowOffset);
            NSLog(@"self.bounds.size.width %f",self.bounds.size.width);
            
            popoverImageHeight = self.bounds.size.height - arrowImageHeight + 2;
            
            arrowImageOriginX = roundf((self.bounds.size.width - arrowImageWidth) / 2 + self.arrowOffset);
            
            if (arrowImageOriginX + arrowImageWidth > self.bounds.size.width - cornerRadius)
            {
                arrowImageOriginX -= cornerRadius;
            }
            
            if (arrowImageOriginX < cornerRadius)
            {
                arrowImageOriginX += cornerRadius;
            }
            
            arrowImageOriginY = popoverImageHeight - 2;
            
            self.arrowImageView.image = [UIImage imageNamed:@"arrow-down.png"];
            
            break;
            
        default:
            
            // For popovers without arrows (Thanks Martin!)
            popoverImageHeight = self.bounds.size.height - arrowImageHeight + 2;
            
            break;
    }
    
    self.popoverBackgroundImageView.frame = CGRectMake(popoverImageOriginX, popoverImageOriginY, popoverImageWidth, popoverImageHeight);
    self.arrowImageView.frame = CGRectMake(arrowImageOriginX, arrowImageOriginY, arrowImageWidth, arrowImageHeight);
}


@end

In the layoutSubviews method i only used the UIPopoverArrowDirectionDown since it’s the only one that seems to get called in out particular implementation.