Blame client/iOS/Additions/Toast+UIView.m

Packit Service fa4841
/***************************************************************************
Packit Service bb5c11
 
Packit Service fa4841
 Toast+UIView.h
Packit Service fa4841
 Toast
Packit Service fa4841
 Version 0.1
Packit Service bb5c11
 
Packit Service fa4841
 Copyright (c) 2011 Charles Scalesse.
Packit Service bb5c11
 
Packit Service fa4841
 Permission is hereby granted, free of charge, to any person obtaining a
Packit Service fa4841
 copy of this software and associated documentation files (the
Packit Service fa4841
 "Software"), to deal in the Software without restriction, including
Packit Service fa4841
 without limitation the rights to use, copy, modify, merge, publish,
Packit Service fa4841
 distribute, sublicense, and/or sell copies of the Software, and to
Packit Service fa4841
 permit persons to whom the Software is furnished to do so, subject to
Packit Service fa4841
 the following conditions:
Packit Service bb5c11
 
Packit Service fa4841
 The above copyright notice and this permission notice shall be included
Packit Service fa4841
 in all copies or substantial portions of the Software.
Packit Service bb5c11
 
Packit Service fa4841
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
Packit Service fa4841
 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Packit Service fa4841
 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
Packit Service fa4841
 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
Packit Service fa4841
 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
Packit Service fa4841
 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
Packit Service fa4841
 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Packit Service bb5c11
 
Packit Service fa4841
 ***************************************************************************/
Packit Service fa4841
Packit Service fa4841
#import "Toast+UIView.h"
Packit Service fa4841
#import <QuartzCore/QuartzCore.h>
Packit Service fa4841
#import <objc/runtime.h>
Packit Service fa4841
Packit Service bb5c11
#define kMaxWidth           0.8
Packit Service bb5c11
#define kMaxHeight          0.8
Packit Service fa4841
Packit Service bb5c11
#define kHorizontalPadding  10.0
Packit Service bb5c11
#define kVerticalPadding    10.0
Packit Service bb5c11
#define kCornerRadius       10.0
Packit Service bb5c11
#define kOpacity            0.8
Packit Service bb5c11
#define kFontSize           16.0
Packit Service bb5c11
#define kMaxTitleLines      999
Packit Service bb5c11
#define kMaxMessageLines    999
Packit Service fa4841
Packit Service bb5c11
#define kFadeDuration       0.2
Packit Service fa4841
Packit Service bb5c11
#define kDefaultLength      3
Packit Service bb5c11
#define kDefaultPosition    @"bottom"
Packit Service fa4841
Packit Service bb5c11
#define kImageWidth         80.0
Packit Service bb5c11
#define kImageHeight        80.0
Packit Service fa4841
Packit Service fa4841
static NSString *kDurationKey = @"duration";
Packit Service fa4841
Packit Service bb5c11
Packit Service fa4841
@interface UIView (ToastPrivate)
Packit Service fa4841
Packit Service bb5c11
-(CGPoint)getPositionFor:(id)position toast:(UIView *)toast;
Packit Service bb5c11
-(UIView *)makeViewForMessage:(NSString *)message title:(NSString *)title image:(UIImage *)image;
Packit Service fa4841
Packit Service fa4841
@end
Packit Service fa4841
Packit Service bb5c11
Packit Service fa4841
@implementation UIView (Toast)
Packit Service fa4841
Packit Service fa4841
#pragma mark -
Packit Service fa4841
#pragma mark Toast Methods
Packit Service fa4841
Packit Service bb5c11
-(void)makeToast:(NSString *)message {
Packit Service bb5c11
    [self makeToast:message duration:kDefaultLength position:kDefaultPosition];
Packit Service fa4841
}
Packit Service fa4841
Packit Service bb5c11
-(void)makeToast:(NSString *)message duration:(float)interval position:(id)point {
Packit Service bb5c11
    UIView *toast = [self makeViewForMessage:message title:nil image:nil];
Packit Service bb5c11
    [self showToast:toast duration:interval position:point];  
Packit Service fa4841
}
Packit Service fa4841
Packit Service bb5c11
-(void)makeToast:(NSString *)message duration:(float)interval position:(id)point title:(NSString *)title {
Packit Service bb5c11
    UIView *toast = [self makeViewForMessage:message title:title image:nil];
Packit Service bb5c11
    [self showToast:toast duration:interval position:point];  
Packit Service fa4841
}
Packit Service fa4841
Packit Service bb5c11
-(void)makeToast:(NSString *)message duration:(float)interval position:(id)point image:(UIImage *)image {
Packit Service bb5c11
    UIView *toast = [self makeViewForMessage:message title:nil image:image];
Packit Service bb5c11
    [self showToast:toast duration:interval position:point];  
Packit Service fa4841
}
Packit Service fa4841
Packit Service bb5c11
-(void)makeToast:(NSString *)message duration:(float)interval  position:(id)point title:(NSString *)title image:(UIImage *)image {
Packit Service bb5c11
    UIView *toast = [self makeViewForMessage:message title:title image:image];
Packit Service bb5c11
    [self showToast:toast duration:interval position:point];  
Packit Service fa4841
}
Packit Service fa4841
Packit Service bb5c11
-(void)showToast:(UIView *)toast {
Packit Service bb5c11
    [self showToast:toast duration:kDefaultLength position:kDefaultPosition];
Packit Service fa4841
}
Packit Service fa4841
Packit Service bb5c11
-(void)showToast:(UIView *)toast duration:(float)interval position:(id)point {
Packit Service bb5c11
    
Packit Service bb5c11
    /****************************************************
Packit Service bb5c11
     *                                                  *
Packit Service bb5c11
     * Displays a view for a given duration & position. *
Packit Service bb5c11
     *                                                  *
Packit Service bb5c11
     ****************************************************/
Packit Service bb5c11
    
Packit Service bb5c11
    CGPoint toastPoint = [self getPositionFor:point toast:toast];
Packit Service bb5c11
    
Packit Service bb5c11
    //use an associative reference to associate the toast view with the display interval
Packit Service bb5c11
    objc_setAssociatedObject (toast, &kDurationKey, [NSNumber numberWithFloat:interval], OBJC_ASSOCIATION_RETAIN);
Packit Service bb5c11
    
Packit Service bb5c11
    [toast setCenter:toastPoint];
Packit Service bb5c11
    [toast setAlpha:0.0];
Packit Service bb5c11
    [self addSubview:toast];
Packit Service bb5c11
    
Packit Service bb5c11
    [UIView beginAnimations:@"fade_in" context:toast];
Packit Service bb5c11
    [UIView setAnimationDuration:kFadeDuration];
Packit Service bb5c11
    [UIView setAnimationDelegate:self];
Packit Service bb5c11
    [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];
Packit Service bb5c11
    [UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
Packit Service bb5c11
    [toast setAlpha:1.0];
Packit Service bb5c11
    [UIView commitAnimations];
Packit Service bb5c11
    
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
#pragma mark -
Packit Service fa4841
#pragma mark Animation Delegate Method
Packit Service fa4841
Packit Service bb5c11
- (void)animationDidStop:(NSString*)animationID finished:(BOOL)finished context:(void *)context {
Packit Service bb5c11
    
Packit Service bb5c11
    UIView *toast = (UIView *)context;
Packit Service bb5c11
    
Packit Service bb5c11
    // retrieve the display interval associated with the view
Packit Service bb5c11
    float interval = [(NSNumber *)objc_getAssociatedObject(toast, &kDurationKey) floatValue];
Packit Service bb5c11
    
Packit Service bb5c11
    if([animationID isEqualToString:@"fade_in"]) {
Packit Service bb5c11
        
Packit Service bb5c11
        [UIView beginAnimations:@"fade_out" context:toast];
Packit Service bb5c11
        [UIView setAnimationDelay:interval];
Packit Service bb5c11
        [UIView setAnimationDuration:kFadeDuration];
Packit Service bb5c11
        [UIView setAnimationDelegate:self];
Packit Service bb5c11
        [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];
Packit Service bb5c11
        [UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
Packit Service bb5c11
        [toast setAlpha:0.0];
Packit Service bb5c11
        [UIView commitAnimations];
Packit Service bb5c11
        
Packit Service bb5c11
    } else if ([animationID isEqualToString:@"fade_out"]) {
Packit Service bb5c11
        
Packit Service bb5c11
        [toast removeFromSuperview];
Packit Service bb5c11
        
Packit Service bb5c11
    }
Packit Service bb5c11
    
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
#pragma mark -
Packit Service fa4841
#pragma mark Private Methods
Packit Service fa4841
Packit Service bb5c11
-(CGPoint)getPositionFor:(id)point toast:(UIView *)toast {
Packit Service bb5c11
    
Packit Service bb5c11
    /*************************************************************************************
Packit Service bb5c11
     *                                                                                   *
Packit Service bb5c11
     * Converts string literals @"top", @"bottom", @"center", or any point wrapped in an *
Packit Service bb5c11
     * NSValue object into a CGPoint                                                     *
Packit Service bb5c11
     *                                                                                   *
Packit Service bb5c11
     *************************************************************************************/
Packit Service bb5c11
    
Packit Service bb5c11
    if([point isKindOfClass:[NSString class]]) {
Packit Service bb5c11
        
Packit Service bb5c11
        if( [point caseInsensitiveCompare:@"top"] == NSOrderedSame ) {
Packit Service bb5c11
            return CGPointMake(self.bounds.size.width/2, (toast.frame.size.height / 2) + kVerticalPadding);
Packit Service bb5c11
        } else if( [point caseInsensitiveCompare:@"bottom"] == NSOrderedSame ) {
Packit Service bb5c11
            return CGPointMake(self.bounds.size.width/2, (self.bounds.size.height - (toast.frame.size.height / 2)) - kVerticalPadding);
Packit Service bb5c11
        } else if( [point caseInsensitiveCompare:@"center"] == NSOrderedSame ) {
Packit Service bb5c11
            return CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2);
Packit Service bb5c11
        }
Packit Service bb5c11
        
Packit Service bb5c11
    } else if ([point isKindOfClass:[NSValue class]]) {
Packit Service bb5c11
        return [point CGPointValue];
Packit Service bb5c11
    }
Packit Service bb5c11
    
Packit Service bb5c11
    NSLog(@"Error: Invalid position for toast.");
Packit Service bb5c11
    return [self getPositionFor:kDefaultPosition toast:toast];
Packit Service fa4841
}
Packit Service fa4841
Packit Service bb5c11
-(UIView *)makeViewForMessage:(NSString *)message title:(NSString *)title image:(UIImage *)image {
Packit Service bb5c11
    
Packit Service bb5c11
    /***********************************************************************************
Packit Service bb5c11
     *                                                                                 *
Packit Service bb5c11
     * Dynamically build a toast view with any combination of message, title, & image. *
Packit Service bb5c11
     *                                                                                 *
Packit Service bb5c11
     ***********************************************************************************/
Packit Service bb5c11
    
Packit Service bb5c11
    if((message == nil) && (title == nil) && (image == nil)) return nil;
Packit Service bb5c11
Packit Service bb5c11
    UILabel *messageLabel = nil;
Packit Service bb5c11
    UILabel *titleLabel = nil;
Packit Service bb5c11
    UIImageView *imageView = nil;
Packit Service bb5c11
    
Packit Service bb5c11
    // create the parent view
Packit Service bb5c11
    UIView *wrapperView = [[[UIView alloc] init] autorelease];
Packit Service bb5c11
    [wrapperView.layer setCornerRadius:kCornerRadius];
Packit Service bb5c11
    [wrapperView setBackgroundColor:[[UIColor blackColor] colorWithAlphaComponent:kOpacity]];
Packit Service bb5c11
    wrapperView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
Packit Service bb5c11
Packit Service bb5c11
    if(image != nil) {
Packit Service bb5c11
        imageView = [[[UIImageView alloc] initWithImage:image] autorelease];
Packit Service bb5c11
        [imageView setContentMode:UIViewContentModeScaleAspectFit];
Packit Service bb5c11
        [imageView setFrame:CGRectMake(kHorizontalPadding, kVerticalPadding, kImageWidth, kImageHeight)];
Packit Service bb5c11
    }
Packit Service bb5c11
    
Packit Service bb5c11
    float imageWidth, imageHeight, imageLeft;
Packit Service bb5c11
    
Packit Service bb5c11
    // the imageView frame values will be used to size & position the other views
Packit Service bb5c11
    if(imageView != nil) {
Packit Service bb5c11
        imageWidth = imageView.bounds.size.width;
Packit Service bb5c11
        imageHeight = imageView.bounds.size.height;
Packit Service bb5c11
        imageLeft = kHorizontalPadding;
Packit Service bb5c11
    } else {
Packit Service bb5c11
        imageWidth = imageHeight = imageLeft = 0;
Packit Service bb5c11
    }
Packit Service bb5c11
    
Packit Service bb5c11
    if (title != nil) {
Packit Service bb5c11
        titleLabel = [[[UILabel alloc] init] autorelease];
Packit Service bb5c11
        [titleLabel setNumberOfLines:kMaxTitleLines];
Packit Service bb5c11
        [titleLabel setFont:[UIFont boldSystemFontOfSize:kFontSize]];
Packit Service bb5c11
        [titleLabel setTextAlignment:UITextAlignmentLeft];
Packit Service bb5c11
        [titleLabel setLineBreakMode:UILineBreakModeWordWrap];
Packit Service bb5c11
        [titleLabel setTextColor:[UIColor whiteColor]];
Packit Service bb5c11
        [titleLabel setBackgroundColor:[UIColor clearColor]];
Packit Service bb5c11
        [titleLabel setAlpha:1.0];
Packit Service bb5c11
        [titleLabel setText:title];
Packit Service bb5c11
        
Packit Service bb5c11
        // size the title label according to the length of the text
Packit Service bb5c11
        CGSize maxSizeTitle = CGSizeMake((self.bounds.size.width * kMaxWidth) - imageWidth, self.bounds.size.height * kMaxHeight);
Packit Service bb5c11
        CGSize expectedSizeTitle = [title sizeWithFont:titleLabel.font constrainedToSize:maxSizeTitle lineBreakMode:titleLabel.lineBreakMode]; 
Packit Service bb5c11
        [titleLabel setFrame:CGRectMake(0, 0, expectedSizeTitle.width, expectedSizeTitle.height)];
Packit Service bb5c11
    }
Packit Service bb5c11
    
Packit Service bb5c11
    if (message != nil) {
Packit Service bb5c11
        messageLabel = [[[UILabel alloc] init] autorelease];
Packit Service bb5c11
        [messageLabel setNumberOfLines:kMaxMessageLines];
Packit Service bb5c11
        [messageLabel setFont:[UIFont systemFontOfSize:kFontSize]];
Packit Service bb5c11
        [messageLabel setLineBreakMode:UILineBreakModeWordWrap];
Packit Service bb5c11
        [messageLabel setTextColor:[UIColor whiteColor]];
Packit Service bb5c11
        [messageLabel setTextAlignment:UITextAlignmentCenter];
Packit Service bb5c11
        [messageLabel setBackgroundColor:[UIColor clearColor]];
Packit Service bb5c11
        [messageLabel setAlpha:1.0];
Packit Service bb5c11
        [messageLabel setText:message];
Packit Service bb5c11
        
Packit Service bb5c11
        // size the message label according to the length of the text
Packit Service bb5c11
        CGSize maxSizeMessage = CGSizeMake((self.bounds.size.width * kMaxWidth) - imageWidth, self.bounds.size.height * kMaxHeight);
Packit Service bb5c11
        CGSize expectedSizeMessage = [message sizeWithFont:messageLabel.font constrainedToSize:maxSizeMessage lineBreakMode:messageLabel.lineBreakMode]; 
Packit Service bb5c11
        [messageLabel setFrame:CGRectMake(0, 0, expectedSizeMessage.width, expectedSizeMessage.height)];
Packit Service bb5c11
    }
Packit Service bb5c11
    
Packit Service bb5c11
    // titleLabel frame values
Packit Service bb5c11
    float titleWidth, titleHeight, titleTop, titleLeft;
Packit Service bb5c11
    
Packit Service bb5c11
    if(titleLabel != nil) {
Packit Service bb5c11
        titleWidth = titleLabel.bounds.size.width;
Packit Service bb5c11
        titleHeight = titleLabel.bounds.size.height;
Packit Service bb5c11
        titleTop = kVerticalPadding;
Packit Service bb5c11
        titleLeft = imageLeft + imageWidth + kHorizontalPadding;
Packit Service bb5c11
    } else {
Packit Service bb5c11
        titleWidth = titleHeight = titleTop = titleLeft = 0;
Packit Service bb5c11
    }
Packit Service bb5c11
    
Packit Service bb5c11
    // messageLabel frame values
Packit Service bb5c11
    float messageWidth, messageHeight, messageLeft, messageTop;
Packit Service bb5c11
Packit Service bb5c11
    if(messageLabel != nil) {
Packit Service bb5c11
        messageWidth = messageLabel.bounds.size.width;
Packit Service bb5c11
        messageHeight = messageLabel.bounds.size.height;
Packit Service bb5c11
        messageLeft = imageLeft + imageWidth + kHorizontalPadding;
Packit Service bb5c11
        messageTop = titleTop + titleHeight + kVerticalPadding;
Packit Service bb5c11
    } else {
Packit Service bb5c11
        messageWidth = messageHeight = messageLeft = messageTop = 0;
Packit Service bb5c11
    }
Packit Service bb5c11
    
Packit Service bb5c11
    // compare the title & message widths and use the longer value to calculate the size of the wrapper width
Packit Service bb5c11
    // the same logic applies to the x value (left)
Packit Service bb5c11
    float longerWidth = (messageWidth < titleWidth) ? titleWidth : messageWidth;
Packit Service bb5c11
    float longerLeft = (messageLeft < titleLeft) ? titleLeft : messageLeft;
Packit Service bb5c11
    
Packit Service bb5c11
    // if the image width is larger than longerWidth, use the image width to calculate the wrapper width.
Packit Service bb5c11
    // the same logic applies to the wrapper height
Packit Service bb5c11
    float wrapperWidth = ((longerLeft + longerWidth + kHorizontalPadding) < imageWidth + (kHorizontalPadding * 2)) ? imageWidth + (kHorizontalPadding * 2) : (longerLeft + longerWidth + kHorizontalPadding);
Packit Service bb5c11
    float wrapperHeight = ((messageTop + messageHeight + kVerticalPadding) < imageHeight + (kVerticalPadding * 2)) ? imageHeight + (kVerticalPadding * 2) : (messageTop + messageHeight + kVerticalPadding);
Packit Service bb5c11
                         
Packit Service bb5c11
    [wrapperView setFrame:CGRectMake(0, 0, wrapperWidth, wrapperHeight)];
Packit Service bb5c11
    
Packit Service bb5c11
    if(titleLabel != nil) {
Packit Service bb5c11
        [titleLabel setFrame:CGRectMake(titleLeft, titleTop, titleWidth, titleHeight)];
Packit Service bb5c11
        [wrapperView addSubview:titleLabel];
Packit Service bb5c11
    }
Packit Service bb5c11
    
Packit Service bb5c11
    if(messageLabel != nil) {
Packit Service bb5c11
        [messageLabel setFrame:CGRectMake(messageLeft, messageTop, messageWidth, messageHeight)];
Packit Service bb5c11
        [wrapperView addSubview:messageLabel];
Packit Service bb5c11
    }
Packit Service bb5c11
    
Packit Service bb5c11
    if(imageView != nil) {
Packit Service bb5c11
        [wrapperView addSubview:imageView];
Packit Service bb5c11
    }
Packit Service bb5c11
    
Packit Service bb5c11
    return wrapperView;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
@end