| // |
| // WEPopoverController.m |
| // WEPopover |
| // |
| // Created by Werner Altewischer on 02/09/10. |
| // Copyright 2010 Werner IT Consultancy. All rights reserved. |
| // |
| |
| #import "WEPopoverController.h" |
| #import "WEPopoverParentView.h" |
| #import "UIBarButtonItem+WEPopover.h" |
| |
| #define FADE_DURATION 0.3 |
| |
| @interface WEPopoverController(Private) |
| |
| - (UIView *)keyView; |
| - (void)updateBackgroundPassthroughViews; |
| - (void)setView:(UIView *)v; |
| - (CGRect)displayAreaForView:(UIView *)theView; |
| - (WEPopoverContainerViewProperties *)defaultContainerViewProperties; |
| - (void)dismissPopoverAnimated:(BOOL)animated userInitiated:(BOOL)userInitiated; |
| |
| @end |
| |
| |
| @implementation WEPopoverController |
| |
| @synthesize contentViewController; |
| @synthesize popoverContentSize; |
| @synthesize popoverVisible; |
| @synthesize popoverArrowDirection; |
| @synthesize delegate; |
| @synthesize view; |
| @synthesize containerViewProperties; |
| @synthesize context; |
| @synthesize passthroughViews; |
| |
| - (id)init { |
| if ((self = [super init])) { |
| } |
| return self; |
| } |
| |
| - (id)initWithContentViewController:(UIViewController *)viewController { |
| if ((self = [self init])) { |
| self.contentViewController = viewController; |
| } |
| return self; |
| } |
| |
| - (void)dealloc { |
| [self dismissPopoverAnimated:NO]; |
| } |
| |
| - (void)setContentViewController:(UIViewController *)vc { |
| if (vc != contentViewController) { |
| contentViewController = vc; |
| popoverContentSize = CGSizeZero; |
| } |
| } |
| |
| //Overridden setter to copy the passthroughViews to the background view if it exists already |
| - (void)setPassthroughViews:(NSArray *)array { |
| passthroughViews = nil; |
| if (array) { |
| passthroughViews = [[NSArray alloc] initWithArray:array]; |
| } |
| [self updateBackgroundPassthroughViews]; |
| } |
| |
| - (void)dismissPopoverAnimated:(BOOL)animated { |
| |
| [self dismissPopoverAnimated:animated userInitiated:NO]; |
| } |
| |
| - (void)presentPopoverFromBarButtonItem:(UIBarButtonItem *)item |
| permittedArrowDirections:(UIPopoverArrowDirection)arrowDirections |
| animated:(BOOL)animated { |
| |
| UIView *v = [self keyView]; |
| CGRect rect = [item frameInView:v]; |
| |
| [self presentPopoverFromRect:rect inView:v permittedArrowDirections:arrowDirections animated:animated]; |
| } |
| |
| - (void)presentPopoverFromRect:(CGRect)rect |
| inView:(UIView *)theView |
| permittedArrowDirections:(UIPopoverArrowDirection)arrowDirections |
| animated:(BOOL)animated { |
| |
| |
| [self dismissPopoverAnimated:NO]; |
| |
| //First force a load view for the contentViewController so the popoverContentSize is properly initialized |
| // NEST: edit to avoid warning |
| if (contentViewController.view == nil) return; |
| |
| if (CGSizeEqualToSize(popoverContentSize, CGSizeZero)) { |
| popoverContentSize = contentViewController.preferredContentSize; |
| } |
| |
| CGRect displayArea = [self displayAreaForView:theView]; |
| |
| WEPopoverContainerViewProperties *props = self.containerViewProperties ? self.containerViewProperties : [self defaultContainerViewProperties]; |
| WEPopoverContainerView *containerView = [[WEPopoverContainerView alloc] initWithSize:self.popoverContentSize anchorRect:rect displayArea:displayArea permittedArrowDirections:arrowDirections properties:props]; |
| popoverArrowDirection = containerView.arrowDirection; |
| |
| UIView *topView = theView; |
| while (topView.superview.superview != nil) topView = topView.superview; |
| |
| UIView *keyView = topView; |
| |
| backgroundView = [[WETouchableView alloc] initWithFrame:keyView.bounds]; |
| backgroundView.contentMode = UIViewContentModeScaleToFill; |
| backgroundView.autoresizingMask = ( UIViewAutoresizingFlexibleLeftMargin | |
| UIViewAutoresizingFlexibleWidth | |
| UIViewAutoresizingFlexibleRightMargin | |
| UIViewAutoresizingFlexibleTopMargin | |
| UIViewAutoresizingFlexibleHeight | |
| UIViewAutoresizingFlexibleBottomMargin); |
| backgroundView.backgroundColor = [UIColor clearColor]; |
| backgroundView.delegate = self; |
| |
| [keyView addSubview:backgroundView]; |
| |
| containerView.frame = [theView convertRect:containerView.frame toView:backgroundView]; |
| |
| [backgroundView addSubview:containerView]; |
| |
| containerView.contentView = contentViewController.view; |
| containerView.autoresizingMask = ( UIViewAutoresizingFlexibleLeftMargin | |
| UIViewAutoresizingFlexibleRightMargin); |
| |
| self.view = containerView; |
| [self updateBackgroundPassthroughViews]; |
| |
| [contentViewController viewWillAppear:animated]; |
| |
| [self.view becomeFirstResponder]; |
| |
| if (animated) { |
| self.view.alpha = 0.0; |
| |
| [UIView animateWithDuration:FADE_DURATION animations:^{ |
| self.view.alpha = 1.0; |
| } completion:^(BOOL finished) { |
| self.view.userInteractionEnabled = YES; |
| popoverVisible = YES; |
| [contentViewController viewDidAppear:YES]; |
| }]; |
| } else { |
| popoverVisible = YES; |
| [contentViewController viewDidAppear:animated]; |
| } |
| } |
| |
| - (void)repositionPopoverFromRect:(CGRect)rect |
| inView:(UIView *)theView |
| permittedArrowDirections:(UIPopoverArrowDirection)arrowDirections { |
| |
| CGRect displayArea = [self displayAreaForView:theView]; |
| WEPopoverContainerView *containerView = (WEPopoverContainerView *)self.view; |
| [containerView updatePositionWithAnchorRect:rect |
| displayArea:displayArea |
| permittedArrowDirections:arrowDirections]; |
| |
| popoverArrowDirection = containerView.arrowDirection; |
| containerView.frame = [theView convertRect:containerView.frame toView:backgroundView]; |
| } |
| |
| #pragma mark - |
| #pragma mark WETouchableViewDelegate implementation |
| |
| - (void)viewWasTouched:(WETouchableView *)view { |
| if (popoverVisible) { |
| if (!delegate || [delegate popoverControllerShouldDismissPopover:self]) { |
| [self dismissPopoverAnimated:YES userInitiated:YES]; |
| } |
| } |
| } |
| |
| @end |
| |
| |
| @implementation WEPopoverController(Private) |
| |
| - (UIView *)keyView { |
| UIWindow *w = [[UIApplication sharedApplication] keyWindow]; |
| if (w.subviews.count > 0) { |
| return [w.subviews objectAtIndex:0]; |
| } else { |
| return w; |
| } |
| } |
| |
| - (void)setView:(UIView *)v { |
| if (view != v) { |
| view = v; |
| } |
| } |
| |
| - (void)updateBackgroundPassthroughViews { |
| backgroundView.passthroughViews = passthroughViews; |
| } |
| |
| |
| - (void)dismissPopoverAnimated:(BOOL)animated userInitiated:(BOOL)userInitiated { |
| if (self.view) { |
| [contentViewController viewWillDisappear:animated]; |
| popoverVisible = NO; |
| [self.view resignFirstResponder]; |
| if (animated) { |
| |
| self.view.userInteractionEnabled = NO; |
| [UIView animateWithDuration:FADE_DURATION animations:^{ |
| self.view.alpha = 0.0; |
| } completion:^(BOOL finished) { |
| popoverVisible = NO; |
| [contentViewController viewDidDisappear:YES]; |
| [self.view removeFromSuperview]; |
| self.view = nil; |
| [backgroundView removeFromSuperview]; |
| backgroundView = nil; |
| |
| if (userInitiated) { |
| //Only send message to delegate in case the user initiated this event, which is if he touched outside the view |
| [delegate popoverControllerDidDismissPopover:self]; |
| } |
| }]; |
| } else { |
| [contentViewController viewDidDisappear:animated]; |
| [self.view removeFromSuperview]; |
| self.view = nil; |
| [backgroundView removeFromSuperview]; |
| backgroundView = nil; |
| } |
| } |
| } |
| |
| - (CGRect)displayAreaForView:(UIView *)theView { |
| CGRect displayArea = CGRectZero; |
| if ([theView conformsToProtocol:@protocol(WEPopoverParentView)] && [theView respondsToSelector:@selector(displayAreaForPopover)]) { |
| displayArea = [(id <WEPopoverParentView>)theView displayAreaForPopover]; |
| } else { |
| displayArea = [[[UIApplication sharedApplication] keyWindow] convertRect:[[UIScreen mainScreen] applicationFrame] toView:theView]; |
| displayArea = CGRectInset(displayArea, 6, 6); // give some margin from the edges of the screen |
| } |
| return displayArea; |
| } |
| |
| //Enable to use the simple popover style |
| - (WEPopoverContainerViewProperties *)defaultContainerViewProperties { |
| WEPopoverContainerViewProperties *ret = [WEPopoverContainerViewProperties new]; |
| |
| CGSize imageSize = CGSizeMake(30.0f, 30.0f); |
| NSString *bgImageName = nl_img_popover_bg_simple; |
| CGFloat bgMargin = 0.0f; |
| CGFloat contentMargin = 12.0f; |
| |
| ret.leftBgMargin = bgMargin; |
| ret.rightBgMargin = bgMargin; |
| ret.topBgMargin = bgMargin; |
| ret.bottomBgMargin = bgMargin; |
| ret.leftBgCapSize = (NSInteger)(imageSize.width/2); |
| ret.topBgCapSize = (NSInteger)(imageSize.height/2); |
| ret.bgImageName = bgImageName; |
| ret.leftContentMargin = contentMargin; |
| ret.rightContentMargin = contentMargin; |
| ret.topContentMargin = contentMargin; |
| ret.bottomContentMargin = contentMargin; |
| ret.arrowMargin = 1.0f; |
| |
| ret.upArrowImageName = nl_img_popover_arrow_up_simple; |
| ret.downArrowImageName = nl_img_popover_arrow_down_simple; |
| ret.leftArrowImageName = nl_img_popover_arrow_left_simple; |
| ret.rightArrowImageName = nl_img_popover_arrow_right_simple; |
| return ret; |
| } |
| |
| @end |