// // BlockAlertView.m // // #import "BlockAlertView.h" #import "BlockBackground.h" @implementation BlockAlertView @synthesize view = _view; static UIImage *background = nil; static UIFont *titleFont = nil; static UIFont *messageFont = nil; static UIFont *buttonFont = nil; #define kBounce 20 #define kBorder 10 #define kButtonHeight 44 #define kAlertFontColor [UIColor colorWithWhite:244.0/255.0 alpha:1.0] #define kAlertViewBackground @"alert-window.png" #define kAlertViewBackgroundCapHeight 38 #pragma mark - init + (void)initialize { if (self == [BlockAlertView class]) { background = [UIImage imageNamed:kAlertViewBackground]; background = [[background stretchableImageWithLeftCapWidth:0 topCapHeight:kAlertViewBackgroundCapHeight] retain]; titleFont = [[UIFont boldSystemFontOfSize:20] retain]; messageFont = [[UIFont systemFontOfSize:18] retain]; buttonFont = [[UIFont boldSystemFontOfSize:18] retain]; } } + (BlockAlertView *)alertWithTitle:(NSString *)title message:(NSString *)message { return [[[BlockAlertView alloc] initWithTitle:title message:message] autorelease]; } /////////////////////////////////////////////////////////////////////////////////////////////////// #pragma mark - NSObject - (id)initWithTitle:(NSString *)title message:(NSString *)message { if ((self = [super init])) { BlockBackground* blockBackground = [BlockBackground sharedInstance]; [blockBackground sizeToFill]; [self setViewTransform:blockBackground forOrientation:blockBackground.orientation]; CGRect frame = blockBackground.bounds; frame.origin.x = (frame.size.width - background.size.width) * 0.5; frame.size.width = background.size.width; _view = [[UIView alloc] initWithFrame:frame]; _blocks = [[NSMutableArray alloc] init]; _height = kBorder + 15; if (title) { CGSize size = [title sizeWithFont:titleFont constrainedToSize:CGSizeMake(frame.size.width-kBorder*2, 1000) lineBreakMode:NSLineBreakByWordWrapping]; UILabel *labelView = [[UILabel alloc] initWithFrame:CGRectMake(kBorder, _height, frame.size.width-kBorder*2, size.height)]; labelView.font = titleFont; labelView.numberOfLines = 0; labelView.lineBreakMode = NSLineBreakByWordWrapping; labelView.textColor = kAlertFontColor; labelView.backgroundColor = [UIColor clearColor]; labelView.textAlignment = NSTextAlignmentCenter; labelView.shadowColor = [UIColor blackColor]; labelView.shadowOffset = CGSizeMake(0, -1); labelView.text = title; [_view addSubview:labelView]; [labelView release]; _height += size.height + kBorder; } if (message) { CGSize size = [message sizeWithFont:messageFont constrainedToSize:CGSizeMake(frame.size.width-kBorder*2, 1000) lineBreakMode:NSLineBreakByWordWrapping]; UILabel *labelView = [[UILabel alloc] initWithFrame:CGRectMake(kBorder, _height, frame.size.width-kBorder*2, size.height)]; labelView.font = messageFont; labelView.numberOfLines = 0; labelView.lineBreakMode = NSLineBreakByWordWrapping; labelView.textColor = kAlertFontColor; labelView.backgroundColor = [UIColor clearColor]; labelView.textAlignment = NSTextAlignmentCenter; labelView.shadowColor = [UIColor blackColor]; labelView.shadowOffset = CGSizeMake(0, -1); labelView.text = message; [_view addSubview:labelView]; [labelView release]; _height += size.height + kBorder; } } return self; } - (void)dealloc { [_view release]; [_blocks release]; [super dealloc]; } - (void)setViewTransform:(UIView*)view forOrientation:(UIInterfaceOrientation)orientation { switch(orientation) { case UIInterfaceOrientationPortrait: view.transform = CGAffineTransformMakeRotation(0); break; case UIInterfaceOrientationPortraitUpsideDown: view.transform = CGAffineTransformMakeRotation((-2) *M_PI/2); break; case UIInterfaceOrientationLandscapeRight: view.transform = CGAffineTransformMakeRotation(M_PI/2); break; case UIInterfaceOrientationLandscapeLeft: view.transform = CGAffineTransformMakeRotation((-1) * M_PI/2); break; } } /////////////////////////////////////////////////////////////////////////////////////////////////// #pragma mark - Public - (void)addButtonWithTitle:(NSString *)title color:(NSString*)color block:(void (^)())block { [_blocks addObject:[NSArray arrayWithObjects: block ? [[block copy] autorelease] : [NSNull null], title, color, nil]]; } - (void)addButtonWithTitle:(NSString *)title block:(void (^)())block { [self addButtonWithTitle:title color:@"gray" block:block]; } - (void)setCancelButtonWithTitle:(NSString *)title block:(void (^)())block { [self addButtonWithTitle:title color:@"black" block:block]; } - (void)setDestructiveButtonWithTitle:(NSString *)title block:(void (^)())block { [self addButtonWithTitle:title color:@"red" block:block]; } - (void)show { BOOL isSecondButton = NO; NSUInteger index = 0; for (NSUInteger i = 0; i < _blocks.count; i++) { NSArray *block = [_blocks objectAtIndex:i]; NSString *title = [block objectAtIndex:1]; NSString *color = [block objectAtIndex:2]; UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:@"alert-%@-button.png", color]]; image = [image stretchableImageWithLeftCapWidth:(int)(image.size.width+1)>>1 topCapHeight:0]; CGFloat maxHalfWidth = floorf((_view.bounds.size.width-kBorder*3)*0.5); CGFloat width = _view.bounds.size.width-kBorder*2; CGFloat xOffset = kBorder; if (isSecondButton) { width = maxHalfWidth; xOffset = width + kBorder * 2; isSecondButton = NO; } else if (i + 1 < _blocks.count) { // In this case there's another button. // Let's check if they fit on the same line. CGSize size = [title sizeWithFont:buttonFont minFontSize:10 actualFontSize:nil forWidth:_view.bounds.size.width-kBorder*2 lineBreakMode:NSLineBreakByClipping]; if (size.width < maxHalfWidth - kBorder) { // It might fit. Check the next Button NSArray *block2 = [_blocks objectAtIndex:i+1]; NSString *title2 = [block2 objectAtIndex:1]; size = [title2 sizeWithFont:buttonFont minFontSize:10 actualFontSize:nil forWidth:_view.bounds.size.width-kBorder*2 lineBreakMode:NSLineBreakByClipping]; if (size.width < maxHalfWidth - kBorder) { // They'll fit! isSecondButton = YES; // For the next iteration width = maxHalfWidth; } } } UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; button.frame = CGRectMake(xOffset, _height, width, kButtonHeight); button.titleLabel.font = buttonFont; if ([button.titleLabel respondsToSelector:@selector(setMinimumScaleFactor:)]) button.titleLabel.minimumScaleFactor = 10; button.titleLabel.textAlignment = NSTextAlignmentCenter; button.titleLabel.shadowOffset = CGSizeMake(0, -1); button.backgroundColor = [UIColor clearColor]; button.tag = i+1; [button setBackgroundImage:image forState:UIControlStateNormal]; [button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; [button setTitleShadowColor:[UIColor blackColor] forState:UIControlStateNormal]; [button setTitle:title forState:UIControlStateNormal]; button.accessibilityLabel = title; [button addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside]; [_view addSubview:button]; if (!isSecondButton) _height += kButtonHeight + kBorder; index++; } CGRect frame = _view.frame; frame.origin.y = - _height; frame.size.height = _height; _view.frame = frame; UIImageView *modalBackground = [[UIImageView alloc] initWithFrame:_view.bounds]; modalBackground.image = background; modalBackground.contentMode = UIViewContentModeScaleToFill; [_view insertSubview:modalBackground atIndex:0]; [modalBackground release]; [[BlockBackground sharedInstance] addToMainWindow:_view]; __block CGPoint center = _view.center; center.y = floorf([BlockBackground sharedInstance].bounds.size.height * 0.5) + kBounce; [UIView animateWithDuration:0.4 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{ [BlockBackground sharedInstance].alpha = 1.0f; _view.center = center; } completion:^(BOOL finished) { [UIView animateWithDuration:0.1 delay:0.0 options:0 animations:^{ center.y -= kBounce; _view.center = center; } completion:nil]; }]; [self retain]; } - (void)dismissWithClickedButtonIndex:(NSInteger)buttonIndex animated:(BOOL)animated { if (buttonIndex >= 0 && buttonIndex < [_blocks count]) { id obj = [[_blocks objectAtIndex: buttonIndex] objectAtIndex:0]; if (![obj isEqual:[NSNull null]]) { ((void (^)())obj)(); } } if (animated) { [UIView animateWithDuration:0.1 delay:0.0 options:0 animations:^{ CGPoint center = _view.center; center.y += 20; _view.center = center; } completion:^(BOOL finished) { [UIView animateWithDuration:0.4 delay:0.0 options:UIViewAnimationOptionCurveEaseIn animations:^{ CGRect frame = _view.frame; frame.origin.y = -frame.size.height; _view.frame = frame; [[BlockBackground sharedInstance] reduceAlphaIfEmpty]; } completion:^(BOOL finished) { [[BlockBackground sharedInstance] removeView:_view]; [_view release]; _view = nil; [self autorelease]; }]; }]; } else { [[BlockBackground sharedInstance] removeView:_view]; [_view release]; _view = nil; [self autorelease]; } } /////////////////////////////////////////////////////////////////////////////////////////////////// #pragma mark - Action - (void)buttonClicked:(id)sender { /* Run the button's block */ int buttonIndex = [sender tag] - 1; [self dismissWithClickedButtonIndex:buttonIndex animated:YES]; } @end