Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Perfect framework #10

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 6 additions & 7 deletions TOActionSheet/TOActionSheet.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ typedef NS_ENUM(NSInteger, TOActionSheetContentStyle) {
TOActionSheetContentStyleRight
};

extern CGFloat kTOActionSheetBorderRadius;
extern CGFloat kTOActionSheetCompactMargin;

@interface TOActionSheet : UIView

/**
Expand Down Expand Up @@ -206,15 +209,11 @@ Optionally, the text for the 'Cancel' button.
@param title The title to display in the button
@param tappedBlock A block that will be executed when the button is tapped
*/
- (void)addButtonWithTitle:(NSString *)title icon:(UIImage *)icon tappedBlock:(void (^)(void))tappedBlock;
- (void)addButtonWithTitle:(NSString *)title tappedBlock:(void (^)(void))tappedBlock;
- (void)addButtonWithTitle:(NSString *)title atIndex:(NSInteger)index tappedBlock:(void (^)(void))tappedBlock;
- (void)addButtonWithAttibuteStr:(NSAttributedString *)title icon:(UIImage *)icon tappedBlock:(void (^)(void))tappedBlock;
- (void)addButtonWithAttibuteStr:(NSAttributedString *)title tappedBlock:(void (^)(void))tappedBlock;
- (void)addButtonWithAttibuteStr:(NSAttributedString *)title atIndex:(NSInteger)index tappedBlock:(void (^)(void))tappedBlock;
- (void)removeButtonAtIndex:(NSInteger)index;

- (void)addDestructiveButtonWithTitle:(NSString *)title tappedBlock:(void (^)(void))tappedBlock;
- (void)addDestructiveButtonWithTitle:(NSString *)title icon:(UIImage *)icon tappedBlock:(void (^)(void))tappedBlock;
- (void)removeDestructiveButton;

- (void)showFromRect:(CGRect)rect inView:(UIView *)view;
- (void)showFromView:(UIView *)fromView inView:(UIView *)view;
- (void)showFromBarButtonItem:(UIBarButtonItem *)barButtonItem inView:(UIView *)view;
Expand Down
184 changes: 32 additions & 152 deletions TOActionSheet/TOActionSheet.m
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ typedef NS_ENUM(NSInteger, TOActionSheetArrowDirection) {

const CGFloat kTOActionSheetButtonHeight = 56.0f;
const CGFloat kTOActionSheetDefaultWidth = 300.0f;
const CGFloat kTOActionSheetBorderRadius = 15.0f;
CGFloat kTOActionSheetBorderRadius = 15.0f;
const CGFloat kTOActionSheetTitlePadding = 15.0f;
const CGFloat kTOActionSheetCompactMargin = 20.0f;
CGFloat kTOActionSheetCompactMargin = 20.0f;
const CGFloat kTOActionSheetArrowBase = 36.0f;
const CGFloat kTOActionSheetArrowHeight = 13.0f;
const CGFloat kTOActionSheetScreenPadding = 20.0f;
Expand All @@ -55,17 +55,13 @@ @interface TOActionSheet ()
@property (nonatomic, strong) NSMutableArray *buttonIcons;
@property (nonatomic, strong) NSMutableArray *buttonBlocks;

@property (nonatomic, copy) NSString *destructiveTitle;
@property (nonatomic, copy) UIImage *destructiveIcon;
@property (nonatomic, copy) void (^destructiveBlock)(void);

/* The views of each button */
@property (nonatomic, strong) NSMutableArray *buttonViews;
@property (nonatomic, strong) UIButton *cancelButton;
@property (nonatomic, strong) UIButton *destructiveButton;
@property (nonatomic, strong) NSMutableArray *separatorViews;

/* The views used to construct the view hierarchy */
@property (nonatomic, strong) UIView *shadowView;
@property (nonatomic, strong) UIView *containerView;
@property (nonatomic, strong) UIView *headerBackgroundView;
@property (nonatomic, strong) UIImageView *arrowImageView;
Expand Down Expand Up @@ -211,12 +207,14 @@ - (void)layoutSubviews
frame.origin.x = (self.frame.size.width - frame.size.width) * 0.5f;
frame.origin.y = (self.cancelButton.frame.origin.y - kTOActionSheetCompactMargin) - frame.size.height;
self.containerView.frame = frame;
self.shadowView.frame = self.containerView.frame;
}
else {
//make sure the frame is reset to standard
frame = self.containerView.frame;
frame.size.width = self.width;
self.containerView.frame = frame;
self.shadowView.frame = self.containerView.frame;

CGRect presentationRect = self.presentationRect;
TOActionSheetArrowDirection direction = [self bestArrowDirectionForPresentationRect:presentationRect];
Expand All @@ -233,14 +231,15 @@ - (void)layoutSubviews

self.arrowImageView.hidden = NO;
self.containerView.frame = [self frameOfContainerViewWithArrowDirection:self.arrowDirection presentationRect:presentationRect];
self.shadowView.frame = self.containerView.frame;
self.arrowImageView.frame = [self frameOfArrowViewWithDirection:self.arrowDirection presentationRect:presentationRect];
}

self.cancelButton.hidden = !self.compactLayout;

//set up shadows for these elements
if (self.shadowOpacity > 0.0f) {
[self configureShadowForView:self.containerView];
[self configureShadowForView:self.shadowView];
[self configureShadowForView:self.cancelButton];
}
}
Expand Down Expand Up @@ -412,31 +411,15 @@ - (UIImage *)arrowImageForDirection:(TOActionSheetArrowDirection)direction color
#pragma mark - Action Sheet Views Set-up -
- (void)setUpRegularButtons
{
CGRect buttonFrame = (CGRect){0,0,self.width,kTOActionSheetButtonHeight};

// See if we need to generate graphics for buttons in-between the top and bottom rounded ones
NSInteger numberOfElements = 0;
if (self.headerView || self.title.length) {
numberOfElements++;
}
CGRect buttonFrame = (CGRect){0, 0, self.width, kTOActionSheetButtonHeight};

numberOfElements += self.buttonTitles.count;

if (self.destructiveTitle) {
numberOfElements++;
}

UIImage *regularBG = nil;
UIImage *regularTappedBG = nil;
if (numberOfElements >= 3) {
regularBG = [self buttonBackgroundImageWithColor:self.buttonBackgroundColor];
regularTappedBG = [self buttonBackgroundImageWithColor:self.buttonTappedBackgroundColor];
}
UIImage *regularBG = [self buttonBackgroundImageWithColor:self.buttonBackgroundColor];
UIImage *regularTappedBG = [self buttonBackgroundImageWithColor:self.buttonTappedBackgroundColor];

//Set up each of the regular buttons
NSInteger i = 0;
self.buttonViews = [NSMutableArray array];
for (NSString *title in self.buttonTitles) {
for (NSAttributedString *title in self.buttonTitles) {
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.autoresizingMask = UIViewAutoresizingFlexibleWidth;

Expand All @@ -448,9 +431,8 @@ - (void)setUpRegularButtons
button.frame = buttonFrame;
button.titleLabel.font = self.buttonFont;

[button setTitleColor:self.buttonTextColor forState:UIControlStateNormal];
[button setAttributedTitle:title forState:UIControlStateNormal];
[button setTitleColor:self.buttonTappedTextColor forState:UIControlStateHighlighted];
[button setTitle:title forState:UIControlStateNormal];

if (self.contentstyle == TOActionSheetContentStyleLeft) {
button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
Expand Down Expand Up @@ -480,22 +462,8 @@ - (void)setUpRegularButtons
}
}

if (i == 0 && self.buttonTitles.count > 1 && (self.title.length == 0 && self.headerView == nil)) {
UIImage *background = [self buttonBackgroundImageWithColor:self.buttonBackgroundColor roundedTop:YES roundedBottom:NO];
UIImage *backgroundPressed = [self buttonBackgroundImageWithColor:self.buttonTappedBackgroundColor roundedTop:YES roundedBottom:NO];
[button setBackgroundImage:background forState:UIControlStateNormal];
[button setBackgroundImage:backgroundPressed forState:UIControlStateHighlighted];
}
else if (i >= self.buttonTitles.count-1 && self.destructiveTitle.length == 0) {
UIImage *background = [self buttonBackgroundImageWithColor:self.buttonBackgroundColor roundedTop:NO roundedBottom:YES];
UIImage *backgroundPressed = [self buttonBackgroundImageWithColor:self.buttonTappedBackgroundColor roundedTop:NO roundedBottom:YES];
[button setBackgroundImage:background forState:UIControlStateNormal];
[button setBackgroundImage:backgroundPressed forState:UIControlStateHighlighted];
}
else {
[button setBackgroundImage:regularBG forState:UIControlStateNormal];
[button setBackgroundImage:regularTappedBG forState:UIControlStateHighlighted];
}
[button setBackgroundImage:regularBG forState:UIControlStateNormal];
[button setBackgroundImage:regularTappedBG forState:UIControlStateHighlighted];

i++;
}
Expand All @@ -522,57 +490,6 @@ - (void)setUpCancelButton
[self addSubview:self.cancelButton];
}

- (void)setUpDestructiveButton
{
if (self.destructiveTitle.length == 0) {
return;
}

self.destructiveButton = [UIButton buttonWithType:UIButtonTypeCustom];
self.destructiveButton.autoresizingMask = UIViewAutoresizingFlexibleWidth;
self.destructiveButton.frame = (CGRect){0,0,self.width,kTOActionSheetButtonHeight};
[self.destructiveButton setTitle:self.destructiveTitle forState:UIControlStateNormal];
[self.destructiveButton setTitleColor:self.destructiveButtonTextColor forState:UIControlStateNormal];
[self.destructiveButton setTitleColor:self.destructiveButtonTappedTextColor forState:UIControlStateHighlighted];
self.destructiveButton.titleLabel.font = self.buttonFont;

if (self.contentstyle == TOActionSheetContentStyleLeft) {
self.destructiveButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
} else if (self.contentstyle == TOActionSheetContentStyleRight) {
self.destructiveButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
} else {
self.destructiveButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
}

if (self.destructiveIcon != nil) {
UIImage *icon = [self.destructiveIcon imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
UIImageView *image = [[UIImageView alloc] initWithImage:icon];
image.tintColor = self.destructiveButtonTextColor;
CGFloat size = (self.destructiveButton.frame.size.height-image.frame.size.height)/2;
if (self.contentstyle == TOActionSheetContentStyleRight) {
image.frame = (CGRect){self.destructiveButton.frame.size.width-(10+image.frame.size.width), size, image.frame.size.width, image.frame.size.height};
} else {
image.frame = (CGRect){size, size, image.frame.size.width, image.frame.size.height};
}
[self.destructiveButton addSubview:image];

if (self.contentstyle == TOActionSheetContentStyleLeft) {
[self.destructiveButton setTitleEdgeInsets:UIEdgeInsetsMake(0, 50, 0, 0)];
} else if (self.contentstyle == TOActionSheetContentStyleRight) {
[self.destructiveButton setTitleEdgeInsets:UIEdgeInsetsMake(0, 10, 0, 0)];
}
}

BOOL roundedTop = (self.buttonTitles.count == 0 && self.headerView == nil && self.title.length == 0);
UIImage *backgroundImage = [self buttonBackgroundImageWithColor:self.destructiveButtonBackgroundColor roundedTop:roundedTop roundedBottom:YES];
[self.destructiveButton setBackgroundImage:backgroundImage forState:UIControlStateNormal];

UIImage *backgroundTappedImage = [self buttonBackgroundImageWithColor:self.destructiveButtonTappedBackgroundColor roundedTop:roundedTop roundedBottom:YES];
[self.destructiveButton setBackgroundImage:backgroundTappedImage forState:UIControlStateHighlighted];

[self.destructiveButton addTarget:self action:@selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside];
}

- (void)setUpSeparators
{
NSInteger numberOfSeparators = 0;
Expand All @@ -599,8 +516,7 @@ - (void)setUpHeaderView
return;
}

UIImage *backgroundImage = [self buttonBackgroundImageWithColor:self.headerBackgroundColor roundedTop:YES roundedBottom:NO];
self.headerBackgroundView = [[UIImageView alloc] initWithImage:backgroundImage];
self.headerBackgroundView = [[UIImageView alloc] init];
self.headerBackgroundView.autoresizingMask = UIViewAutoresizingFlexibleWidth;

//Set up if a header view was supplied
Expand Down Expand Up @@ -661,11 +577,13 @@ - (void)setUpContainer
{
//Create the container
self.containerView = [[UIView alloc] init];
self.containerView.layer.backgroundColor = [UIColor whiteColor].CGColor;
self.containerView.layer.cornerRadius = kTOActionSheetBorderRadius;
self.containerView.layer.masksToBounds = YES;
CGRect frame = CGRectZero;
frame.size.width = self.width;
frame.size.height += self.headerBackgroundView.frame.size.height;
frame.size.height += (self.buttonTitles.count * kTOActionSheetButtonHeight);
frame.size.height += (self.destructiveButton.frame.size.height);
self.containerView.frame = frame;

//Lay out the elements in the container
Expand All @@ -686,14 +604,6 @@ - (void)setUpContainer
height += frame.size.height;
}

//Add the destructive button
if (self.destructiveButton) {
frame = self.destructiveButton.frame;
frame.origin.y = height;
self.destructiveButton.frame = frame;
[self.containerView addSubview:self.destructiveButton];
}

//Add the separators
if (self.headerBackgroundView) {
height = self.headerBackgroundView.frame.size.height;
Expand All @@ -710,6 +620,10 @@ - (void)setUpContainer
[self.containerView addSubview:separatorView];
}

self.shadowView = [[UIView alloc] init];
self.shadowView.frame = self.containerView.frame;
self.shadowView.backgroundColor = [UIColor clearColor];
[self addSubview:self.shadowView];
[self addSubview:self.containerView];
}

Expand Down Expand Up @@ -758,12 +672,11 @@ - (void)show

//Set up various views in the container
[self setUpRegularButtons];
[self setUpCancelButton];
[self setUpDestructiveButton];
[self setUpHeaderView];
[self setUpSeparators];
[self setUpContainer];

[self setUpCancelButton];

//Force a layout now to update the state
[self setNeedsLayout];
[self layoutIfNeeded];
Expand All @@ -781,13 +694,15 @@ - (void)presentViewWithCompactAnimation

CGRect containerFrame = self.containerView.frame;
self.containerView.frame = CGRectOffset(self.containerView.frame, 0.0f, offset);
self.shadowView.frame = self.containerView.frame;

CGRect cancelButtonFrame = self.cancelButton.frame;
self.cancelButton.frame = CGRectOffset(self.cancelButton.frame, 0.0f, offset);

//Animate the container view
[UIView animateWithDuration:0.4f delay:0.0f usingSpringWithDamping:0.7f initialSpringVelocity:0.5f options:UIViewAnimationOptionAllowUserInteraction animations:^{
self.containerView.frame = containerFrame;
self.shadowView.frame = self.containerView.frame;
} completion:nil];

//animate the cancel button
Expand All @@ -808,6 +723,7 @@ - (void)dismissViewWithCompactAnimation

[UIView animateWithDuration:0.4f delay:0.0f usingSpringWithDamping:1.0f initialSpringVelocity:0.5f options:0 animations:^{
self.containerView.frame = CGRectOffset(self.containerView.frame, 0.0f, offset);
self.shadowView.frame = self.containerView.frame;
self.cancelButton.frame = CGRectOffset(self.cancelButton.frame, 0.0f, offset);
self.backgroundColor = [UIColor clearColor];
} completion:^(BOOL complete) {
Expand Down Expand Up @@ -877,11 +793,6 @@ - (void)buttonTapped:(id)sender
self.cancelButtonTappedBlock();
}
}
else if (sender == self.destructiveButton) {
if (self.destructiveBlock) {
self.destructiveBlock();
}
}
else {
NSInteger index = [self.buttonViews indexOfObject:sender];
[sender viewWithTag:123].tintColor = self.buttonTappedTextColor;
Expand Down Expand Up @@ -944,7 +855,7 @@ - (void)dimmingViewTapped:(UIGestureRecognizer *)recognizer
}

#pragma mark - Button Configuration -
- (void)addButtonWithTitle:(NSString *)title icon:(UIImage *)icon tappedBlock:(void (^)(void))tappedBlock
- (void)addButtonWithAttibuteStr:(NSAttributedString *)title icon:(UIImage *)icon tappedBlock:(void (^)(void))tappedBlock
{
if (self.buttonIcons == nil) {
self.buttonIcons = [NSMutableArray array];
Expand All @@ -954,15 +865,15 @@ - (void)addButtonWithTitle:(NSString *)title icon:(UIImage *)icon tappedBlock:(v
[self.buttonIcons insertObject:icon atIndex:self.buttonTitles.count];
}

[self addButtonWithTitle:title atIndex:self.buttonTitles.count tappedBlock:tappedBlock];
[self addButtonWithAttibuteStr:title atIndex:self.buttonTitles.count tappedBlock:tappedBlock];
}

- (void)addButtonWithTitle:(NSString *)title tappedBlock:(void (^)(void))tappedBlock
- (void)addButtonWithAttibuteStr:(NSAttributedString *)title tappedBlock:(void (^)(void))tappedBlock
{
[self addButtonWithTitle:title atIndex:self.buttonTitles.count tappedBlock:tappedBlock];
[self addButtonWithAttibuteStr:title atIndex:self.buttonTitles.count tappedBlock:tappedBlock];
}

- (void)addButtonWithTitle:(NSString *)title atIndex:(NSInteger)index tappedBlock:(void (^)(void))tappedBlock
- (void)addButtonWithAttibuteStr:(NSAttributedString *)title atIndex:(NSInteger)index tappedBlock:(void (^)(void))tappedBlock
{
if (title.length == 0 || tappedBlock == nil) {
[NSException raise:NSInternalInconsistencyException format:@"TOActionSheet: Buttons must have both a block and a title."];
Expand All @@ -984,34 +895,6 @@ - (void)removeButtonAtIndex:(NSInteger)index
[self.buttonBlocks removeObjectAtIndex:index];
}

- (void)addDestructiveButtonWithTitle:(NSString *)title icon:(UIImage *)image tappedBlock:(void (^)(void))tappedBlock
{
if (title.length == 0 || tappedBlock == nil) {
[NSException raise:NSInternalInconsistencyException format:@"TOActionSheet: Buttons must have both a block and a title."];
}


self.destructiveIcon = image;
self.destructiveTitle = title;
self.destructiveBlock = tappedBlock;
}

- (void)addDestructiveButtonWithTitle:(NSString *)title tappedBlock:(void (^)(void))tappedBlock
{
if (title.length == 0 || tappedBlock == nil) {
[NSException raise:NSInternalInconsistencyException format:@"TOActionSheet: Buttons must have both a block and a title."];
}

self.destructiveTitle = title;
self.destructiveBlock = tappedBlock;
}

- (void)removeDestructiveButton
{
self.destructiveTitle = nil;
self.destructiveBlock = nil;
}

#pragma mark - Layout Calculation -
- (BOOL)compactLayout
{
Expand Down Expand Up @@ -1179,9 +1062,6 @@ - (UIColor *)bestColorForArrowWithDirection:(TOActionSheetArrowDirection)directi
{
switch (direction) {
case TOActionSheetArrowDirectionDown:
if (self.destructiveTitle) {
return self.destructiveButtonBackgroundColor;
}

if (self.buttonTitles.count) {
return self.buttonBackgroundColor;
Expand Down
Loading