diff --git a/PopoverView/PopoverView.m b/PopoverView/PopoverView.m index bf7fe88..644230d 100644 --- a/PopoverView/PopoverView.m +++ b/PopoverView/PopoverView.m @@ -10,6 +10,24 @@ #import "PopoverView_Configuration.h" #import +#pragma mark - Private Interface + +@interface PopoverView() + +// Returns an array of UIButtons generated from an array of NSStrings +- (NSMutableArray *)_makeButtonsWithStrings:(NSArray *)strings; + +// Returns an array of UIButtons with images above the label generated from an array of NSStrings and UIImages +- (NSMutableArray *)_makeVerticalButtonsWithStrings:(NSArray *)strings andImages:(NSArray *)images; + +// Returns an array of UIButtons with inline images generated from an array of NSStrings and UIImages +- (NSMutableArray *)_makeHorizontalButtonsWithStrings:(NSArray *)strings andImages:(NSArray *)images; + +// generates a UIButton from a string +- (UIButton *)_makeButtonWithString:(NSString *)string; + +@end + #pragma mark - Implementation @implementation PopoverView @@ -212,7 +230,7 @@ - (void)showAtPoint:(CGPoint)point inView:(UIView *)view withViewArray:(NSArray float padding = (i == viewArray.count-1) ? 0 : kBoxPadding; totalHeight += view.frame.size.height + padding; - + if (view.frame.size.width > totalWidth) { totalWidth = view.frame.size.width; } @@ -233,17 +251,10 @@ - (void)showAtPoint:(CGPoint)point inView:(UIView *)view withViewArray:(NSArray totalHeight = 0; - //Now we actually change the frame element for each subview, and center the views horizontally. + //Now we actually change the frame element for each subview to make sure all views are the full width. for (UIView *view in viewArray) { - if ([view autoresizingMask] == UIViewAutoresizingFlexibleWidth) { - //Now make sure all flexible views are the full width - view.frame = CGRectMake(view.frame.origin.x, view.frame.origin.y, totalWidth, view.frame.size.height); - } else { - //If the view is not flexible width, then we position it centered in the view - //without stretching it. - view.frame = CGRectMake(floorf(CGRectGetMinX(boxFrame) + totalWidth*0.5f - view.frame.size.width*0.5f), view.frame.origin.y, view.frame.size.width, view.frame.size.height); - } - + view.frame = CGRectMake(view.frame.origin.x, view.frame.origin.y, totalWidth, view.frame.size.height); + //and if dividers are enabled, we record their position for the drawing methods if (kShowDividersBetweenViews && i != viewArray.count-1) { CGRect dividerRect = CGRectMake(view.frame.origin.x, floorf(view.frame.origin.y + view.frame.size.height + kBoxPadding*0.5f), view.frame.size.width, 0.5f); @@ -296,13 +307,10 @@ - (void)showAtPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)t float padding = (i == viewArray.count-1) ? 0.f : kBoxPadding; totalHeight += view.frame.size.height + padding; - - if (view.frame.size.width > totalWidth) { - totalWidth = view.frame.size.width; - } - - [container addSubview:view]; - + totalWidth = MAX(totalWidth, view.frame.size.width); + + [container addSubview:view]; + i++; } @@ -312,17 +320,11 @@ - (void)showAtPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)t } i = 0; - - for (UIView *view in viewArray) { - if ([view autoresizingMask] == UIViewAutoresizingFlexibleWidth) { - //Now make sure all flexible views are the full width - view.frame = CGRectMake(view.frame.origin.x, view.frame.origin.y, totalWidth, view.frame.size.height); - } else { - //If the view is not flexible width, then we position it centered in the view - //without stretching it. - view.frame = CGRectMake(floorf(CGRectGetMinX(boxFrame) + totalWidth*0.5f - view.frame.size.width*0.5f), view.frame.origin.y, view.frame.size.width, view.frame.size.height); - } - + + //Now we actually change the frame element for each subview to make sure all views are the full width. + for (UIView *view in viewArray) { + view.frame = CGRectMake(view.frame.origin.x, view.frame.origin.y, totalWidth, view.frame.size.height); + //and if dividers are enabled, we record their position for the drawing methods if (kShowDividersBetweenViews && i != viewArray.count-1) { CGRect dividerRect = CGRectMake(view.frame.origin.x, floorf(view.frame.origin.y + view.frame.size.height + kBoxPadding*0.5f), view.frame.size.width, 0.5f); @@ -351,119 +353,141 @@ - (void)showAtPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)t - (void)showAtPoint:(CGPoint)point inView:(UIView *)view withStringArray:(NSArray *)stringArray { - NSMutableArray *labelArray = [[NSMutableArray alloc] initWithCapacity:stringArray.count]; - - UIFont *font = kTextFont; - - for (NSString *string in stringArray) { - CGSize textSize = [string sizeWithFont:font]; - UIButton *textButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, textSize.width, textSize.height)]; - textButton.backgroundColor = [UIColor clearColor]; - textButton.titleLabel.font = font; - textButton.titleLabel.textAlignment = kTextAlignment; - textButton.titleLabel.textColor = kTextColor; - [textButton setTitle:string forState:UIControlStateNormal]; - textButton.layer.cornerRadius = 4.f; - [textButton setTitleColor:kTextColor forState:UIControlStateNormal]; - [textButton setTitleColor:kTextHighlightColor forState:UIControlStateHighlighted]; - [textButton addTarget:self action:@selector(didTapButton:) forControlEvents:UIControlEventTouchUpInside]; - - [labelArray addObject:[textButton autorelease]]; - } - - [self showAtPoint:point inView:view withViewArray:[labelArray autorelease]]; + [self showAtPoint:point inView:view withViewArray:[self _makeButtonsWithStrings:stringArray]]; } - (void)showAtPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)title withStringArray:(NSArray *)stringArray - { - NSMutableArray *labelArray = [[NSMutableArray alloc] initWithCapacity:stringArray.count]; - - UIFont *font = kTextFont; - - for (NSString *string in stringArray) { - CGSize textSize = [string sizeWithFont:font]; - UIButton *textButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, textSize.width, textSize.height)]; - textButton.backgroundColor = [UIColor clearColor]; - textButton.titleLabel.font = font; - textButton.titleLabel.textAlignment = kTextAlignment; - textButton.titleLabel.textColor = kTextColor; - [textButton setTitle:string forState:UIControlStateNormal]; - textButton.layer.cornerRadius = 4.f; - [textButton setTitleColor:kTextColor forState:UIControlStateNormal]; - [textButton setTitleColor:kTextHighlightColor forState:UIControlStateHighlighted]; - [textButton addTarget:self action:@selector(didTapButton:) forControlEvents:UIControlEventTouchUpInside]; - - [labelArray addObject:[textButton autorelease]]; - } - - [self showAtPoint:point inView:view withTitle:title withViewArray:[labelArray autorelease]]; +{ + [self showAtPoint:point inView:view withTitle:title withViewArray:[self _makeButtonsWithStrings:stringArray]]; } - (void)showAtPoint:(CGPoint)point inView:(UIView *)view withStringArray:(NSArray *)stringArray withImageArray:(NSArray *)imageArray { - //Here we do something pretty similar to the stringArray method above. - //We create an array of subviews that contains the strings and images centered above a label. - - NSAssert((stringArray.count == imageArray.count), @"stringArray.count should equal imageArray.count"); - NSMutableArray* tempViewArray = [self makeTempViewsWithStrings:stringArray andImages:imageArray]; + NSMutableArray* tempViews = [self _makeButtonsWithStrings:stringArray andImages:imageArray]; - [self showAtPoint:point inView:view withViewArray:[tempViewArray autorelease]]; + [self showAtPoint:point inView:view withViewArray:tempViews]; } - (void)showAtPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)title withStringArray:(NSArray *)stringArray withImageArray:(NSArray *)imageArray { - NSAssert((stringArray.count == imageArray.count), @"stringArray.count should equal imageArray.count"); - NSMutableArray* tempViewArray = [self makeTempViewsWithStrings:stringArray andImages:imageArray]; - - [self showAtPoint:point inView:view withTitle:title withViewArray:[tempViewArray autorelease]]; + NSMutableArray* tempViews = [self _makeButtonsWithStrings:stringArray andImages:imageArray]; + + [self showAtPoint:point inView:view withTitle:title withViewArray:tempViews]; } -- (NSMutableArray*) makeTempViewsWithStrings:(NSArray *)stringArray andImages:(NSArray *)imageArray +- (NSMutableArray *)_makeButtonsWithStrings:(NSArray *)strings { - NSMutableArray *tempViewArray = [[NSMutableArray alloc] initWithCapacity:stringArray.count]; - - UIFont *font = kTextFont; - - for (int i = 0; i < stringArray.count; i++) { - NSString *string = [stringArray objectAtIndex:i]; - - //First we build a label for the text to set in. - CGSize textSize = [string sizeWithFont:font]; - UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, textSize.width, textSize.height)]; - label.backgroundColor = [UIColor clearColor]; - label.font = font; - label.textAlignment = kTextAlignment; - label.textColor = kTextColor; - label.text = string; - label.layer.cornerRadius = 4.f; - - //Now we grab the image at the same index in the imageArray, and create - //a UIImageView for it. - UIImage *image = [imageArray objectAtIndex:i]; - UIImageView *imageView = [[UIImageView alloc] initWithImage:image]; - - //Take the larger of the two widths as the width for the container - float containerWidth = MAX(imageView.frame.size.width, label.frame.size.width); - float containerHeight = label.frame.size.height + kImageTopPadding + kImageBottomPadding + imageView.frame.size.height; - - //This container will hold both the image and the label - UIView *containerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, containerWidth, containerHeight)]; - - //Now we do the frame manipulations to put the imageView on top of the label, both centered - imageView.frame = CGRectMake(floorf(containerWidth*0.5f - imageView.frame.size.width*0.5f), kImageTopPadding, imageView.frame.size.width, imageView.frame.size.height); - label.frame = CGRectMake(floorf(containerWidth*0.5f - label.frame.size.width*0.5f), imageView.frame.size.height + kImageBottomPadding + kImageTopPadding, label.frame.size.width, label.frame.size.height); - - [containerView addSubview:imageView]; - [containerView addSubview:label]; - - [label release]; - [imageView release]; - - [tempViewArray addObject:containerView]; - [containerView release]; - } + NSMutableArray *buttons = [[NSMutableArray alloc] initWithCapacity:strings.count]; + + for (NSString *string in strings) { + [buttons addObject:[self _makeButtonWithString:string]]; + } + + return [buttons autorelease]; +} + +- (NSMutableArray *)_makeButtonsWithStrings:(NSArray *)strings andImages:(NSArray *)images +{ + NSAssert((strings.count == images.count), @"strings.count should equal images.count"); + if (kImageAboveLabel) { + return [self _makeVerticalButtonsWithStrings:strings andImages:images]; + } else { + return [self _makeHorizontalButtonsWithStrings:strings andImages:images]; + } +} - return tempViewArray; +- (NSMutableArray *)_makeVerticalButtonsWithStrings:(NSArray *)strings andImages:(NSArray *)images +{ + NSMutableArray *buttons = [[NSMutableArray alloc] initWithCapacity:strings.count]; + + // create buttons and add images to them + for (int i = 0; i < strings.count; i++) { + UIButton *button = [self _makeButtonWithString:strings[i]]; + UIImage *image = images[i]; + [button setImage:image forState:UIControlStateNormal]; + button.imageView.contentMode = UIViewContentModeScaleAspectFit; + + //Take the larger of the two widths as the width for the button + float containerWidth = MAX(image.size.width, button.frame.size.width); + float containerHeight = button.frame.size.height + kImageTopPadding + kImageBottomPadding + kImageTitlePadding + image.size.height; + button.frame = CGRectMake(0, 0, containerWidth, containerHeight); + + [button setImage:image forState:UIControlStateNormal]; + button.imageView.contentMode = UIViewContentModeScaleAspectFit; + + CGSize imageSize = button.imageView.frame.size; + CGSize titleSize = button.titleLabel.frame.size; + + // lower the text and push it left to center it + button.titleEdgeInsets = UIEdgeInsetsMake(0.0, -imageSize.width, -(imageSize.height + kImageTitlePadding), 0.0); + + // the text width might have changed (in case it was shortened before due to + // lack of space and isn't anymore now), so we get the frame size again + titleSize = button.titleLabel.frame.size; + + // raise the image and push it right to center it + button.imageEdgeInsets = UIEdgeInsetsMake(-(titleSize.height + kImageTitlePadding), 0.0, 0.0, -titleSize.width); + + [buttons addObject:button]; + } + + return [buttons autorelease]; +} + +- (NSMutableArray *)_makeHorizontalButtonsWithStrings:(NSArray *)strings andImages:(NSArray *)images +{ + NSAssert((strings.count == images.count), @"strings.count should equal images.count"); + NSMutableArray *buttons = [[NSMutableArray alloc] initWithCapacity:strings.count]; + CGFloat maxImageWidth = 0.0; + + // create buttons and add images to them + for (int i = 0; i < strings.count; i++) { + UIButton *button = [self _makeButtonWithString:strings[i]]; + + // resize the button based on the image width + UIImage *image = images[i]; + button.frame = CGRectInset(button.frame, image.size.width * -0.5 - kImageTitlePadding, (kImageTopPadding + kImageBottomPadding) * -1.f); + + [button setImage:image forState:UIControlStateNormal]; + button.imageView.contentMode = UIViewContentModeScaleAspectFit; + [buttons addObject:button]; + + maxImageWidth = MAX(image.size.width, maxImageWidth); + } + + // resize buttons based on maxImageWidth + for (UIButton * button in buttons) { + CGFloat insetWidth = (maxImageWidth - button.imageView.frame.size.width); + button.frame = CGRectInset(button.frame, insetWidth * -0.25, 0); + button.imageEdgeInsets = UIEdgeInsetsMake(0, insetWidth * 0.5, 0, 0); + button.titleEdgeInsets = UIEdgeInsetsMake(0, insetWidth + kImageTitlePadding, 0, 0); + } + + return [buttons autorelease]; +} + +- (UIButton *)_makeButtonWithString:(NSString *)string +{ + UIFont *font = kTextFont; + + CGSize textSize = [string sizeWithFont:font]; + UIButton *textButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, textSize.width, textSize.height)]; + textButton.backgroundColor = [UIColor clearColor]; + textButton.titleLabel.font = font; + textButton.titleLabel.textColor = kTextColor; + [textButton setTitle:string forState:UIControlStateNormal]; + textButton.layer.cornerRadius = 4.f; + [textButton setTitleColor:kTextColor forState:UIControlStateNormal]; + [textButton setTitleColor:kTextHighlightColor forState:UIControlStateHighlighted]; + [textButton addTarget:self action:@selector(didTapButton:) forControlEvents:UIControlEventTouchUpInside]; + + if (kTextAlignment == UITextAlignmentLeft || kTextAlignment == NSTextAlignmentLeft) { + textButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft; + } else if (kTextAlignment == UITextAlignmentRight || kTextAlignment == NSTextAlignmentRight) { + textButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight; + } + + return [textButton autorelease]; } - (void)showAtPoint:(CGPoint)point inView:(UIView *)view withTitle:(NSString *)title withContentView:(UIView *)cView diff --git a/PopoverView/PopoverView_Configuration.h b/PopoverView/PopoverView_Configuration.h index 0c00fd8..c7c7e2a 100644 --- a/PopoverView/PopoverView_Configuration.h +++ b/PopoverView/PopoverView_Configuration.h @@ -49,6 +49,13 @@ //padding along bottom of icons/images #define kImageBottomPadding 3.f +//padding between icons/images and titles +#define kImageTitlePadding 6.f + +// POSITION OF IMAGES + +//Bool that positions icons/images above or to the left of labels +#define kImageAboveLabel YES // DIVIDERS BETWEEN VIEWS