diff --git a/MTZoomWindow.h b/MTZoomWindow.h index db8b7f7..ce96555 100644 --- a/MTZoomWindow.h +++ b/MTZoomWindow.h @@ -22,19 +22,21 @@ typedef enum { MTZoomGesturePinch = 4 } MTZoomGesture; +typedef NSInteger MTZoomGestureMask; + @interface MTZoomWindow : UIWindow @property (nonatomic, retain) UIView *backgroundView; -@property (nonatomic, assign) NSInteger zoomGestures; +@property (nonatomic, assign) MTZoomGestureMask zoomGestures; @property (nonatomic, assign) UIViewAnimationOptions animationOptions; @property (nonatomic, assign) NSTimeInterval animationDuration; @property (nonatomic, assign) NSTimeInterval animationDelay; - +@property (nonatomic, assign) float maximumZoomScale; @property (nonatomic, readonly, getter = isZoomedIn) BOOL zoomedIn; + (MTZoomWindow *)sharedWindow; -- (void)zoomView:(UIView *)view toSize:(CGSize)size completion:(mt_zoom_block)completionBlock; -- (void)zoomOutWithCompletion:(mt_zoom_block)completionBlock; +- (void)zoomView:(UIView *)view toSize:(CGSize)size; +- (void)zoomOut; @end \ No newline at end of file diff --git a/MTZoomWindow.m b/MTZoomWindow.m index 887ab85..6a4bfd7 100644 --- a/MTZoomWindow.m +++ b/MTZoomWindow.m @@ -11,7 +11,8 @@ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - +// +// Rotation code based on Alan Quatermains AQSelfRotatingViewController #import "MTZoomWindow.h" @@ -26,6 +27,7 @@ - (void)handleGesture:(UIGestureRecognizer *)gestureRecognizer; - (void)orientationWillChange:(NSNotification *)note; - (void)orientationDidChange:(NSNotification *)note; +- (void)setupForOrientation:(UIInterfaceOrientation)orientation forceLayout:(BOOL)forceLayout; @end @@ -40,8 +42,7 @@ @implementation MTZoomWindow @synthesize scrollView = scrollView_; @synthesize zoomedView = zoomedView_; @synthesize gestureRecognizers = gestureRecognizers_; - -#import +@synthesize maximumZoomScale = maximumZoomScale_; //////////////////////////////////////////////////////////////////////// #pragma mark - @@ -51,8 +52,8 @@ @implementation MTZoomWindow - (id)initWithFrame:(CGRect)frame { if ((self = [super initWithFrame:frame])) { // setup window - self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; self.windowLevel = UIWindowLevelStatusBar + 2.0f; + self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; self.backgroundColor = [UIColor clearColor]; // setup black backgroundView @@ -63,12 +64,15 @@ - (id)initWithFrame:(CGRect)frame { [self addSubview:backgroundView_]; // setup scrollview + maximumZoomScale_ = 2.f; scrollView_ = [[UIScrollView alloc] initWithFrame:self.frame]; scrollView_.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - scrollView_.maximumZoomScale = 2.0f; + scrollView_.maximumZoomScale = maximumZoomScale_; scrollView_.showsVerticalScrollIndicator = NO; scrollView_.showsHorizontalScrollIndicator = NO; scrollView_.delegate = self; + scrollView_.hidden = YES; + [self addSubview:scrollView_]; // setup animation properties animationOptions_ = UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionAllowUserInteraction; @@ -87,9 +91,6 @@ - (id)initWithFrame:(CGRect)frame { selector: @selector(orientationDidChange:) name: UIApplicationDidChangeStatusBarOrientationNotification object: nil]; - - scrollView_.layer.borderWidth = 2.f; - scrollView_.layer.borderColor = [UIColor blueColor].CGColor; } return self; @@ -116,12 +117,11 @@ - (void)dealloc { #pragma mark MTZoomWindow //////////////////////////////////////////////////////////////////////// -- (void)zoomView:(UIView *)view toSize:(CGSize)size completion:(mt_zoom_block)completionBlock { +- (void)zoomView:(UIView *)view toSize:(CGSize)size { self.zoomedView = view; // save frames before zoom operation - CGRect originalFrameInWindow = [view convertRect:view.bounds toView:nil]; - CGSize zoomedSize = view.zoomedSize; + CGRect originalFrameInWindow = [view convertRect:view.bounds toView:self]; // pre-setup self.backgroundView.alpha = 0.f; @@ -131,69 +131,75 @@ - (void)zoomView:(UIView *)view toSize:(CGSize)size completion:(mt_zoom_block)co // to still visually appear on the same place like before to the user [self.zoomSuperview addSubview:self.zoomedView]; self.zoomedView.frame = originalFrameInWindow; - self.zoomedView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin; + self.zoomedView.autoresizingMask = self.zoomedView.zoomedAutoresizingMask; [UIView animateWithDuration:self.animationDuration delay:self.animationDelay options:self.animationOptions animations:^{ self.backgroundView.alpha = 1.f; - self.zoomedView.frame = CGRectMake((self.frame.size.width-zoomedSize.width)/2.f, (self.frame.size.height-zoomedSize.height)/2.f, - zoomedSize.width, zoomedSize.height); + self.zoomedView.frame = CGRectMake((self.bounds.size.width-size.width)/2.f, (self.bounds.size.height-size.height)/2.f, + size.width, size.height); } completion:^(BOOL finished) { - if (completionBlock != nil) { - completionBlock(); + id delegate = view.zoomDelegate; + + if ([delegate respondsToSelector:@selector(zoomWindow:didZoomInView:)]) { + [delegate zoomWindow:self didZoomInView:view]; } }]; } -- (void)zoomOutWithCompletion:(mt_zoom_block)completionBlock { - CGRect destinationFrameInWindow = [self.zoomedView.zoomPlaceholderView convertRect:self.zoomedView.zoomPlaceholderView.bounds toView:nil]; - UIView *zoomSuperview = self.zoomSuperview; - - // if superview is a scrollView, reset zoom-scale - if ([zoomSuperview respondsToSelector:@selector(setZoomScale:animated:)]) { - [zoomSuperview performSelector:@selector(setZoomScale:animated:) - withObject:[NSNumber numberWithFloat:1.f] - withObject:[NSNumber numberWithBool:YES]]; +- (void)zoomOut { + if (self.zoomedIn) { + CGRect destinationFrameInWindow = [self.zoomedView.zoomPlaceholderView convertRect:self.zoomedView.zoomPlaceholderView.bounds toView:self]; + UIView *zoomSuperview = self.zoomSuperview; + + // if superview is a scrollView, reset zoom-scale + if ([zoomSuperview respondsToSelector:@selector(setZoomScale:animated:)]) { + [zoomSuperview performSelector:@selector(setZoomScale:animated:) + withObject:[NSNumber numberWithFloat:1.f] + withObject:[NSNumber numberWithBool:YES]]; + } + + [UIView animateWithDuration:self.animationDuration + delay:self.animationDelay + options:self.animationOptions | UIViewAnimationOptionBeginFromCurrentState + animations:^{ + self.backgroundView.alpha = 0.0f; + self.zoomedView.frame = destinationFrameInWindow; + } completion:^(BOOL finished) { + // reset zoomed view to original position + self.zoomedView.frame = self.zoomedView.zoomPlaceholderView.frame; + self.zoomedView.autoresizingMask = self.zoomedView.zoomPlaceholderView.autoresizingMask; + [self.zoomedView.zoomPlaceholderView.superview addSubview:self.zoomedView]; + [self.zoomedView.zoomPlaceholderView removeFromSuperview]; + self.zoomedView.zoomPlaceholderView = nil; + // hide window + self.hidden = YES; + + id delegate = self.zoomDelegate; + + if ([delegate respondsToSelector:@selector(zoomWindow:didZoomOutView:)]) { + [delegate zoomWindow:self didZoomOutView:self.zoomedView]; + } + + self.zoomedView = nil; + }]; } - - [UIView animateWithDuration:self.animationDuration - delay:self.animationDelay - options:self.animationOptions | UIViewAnimationOptionBeginFromCurrentState - animations:^{ - self.backgroundView.alpha = 0.0f; - self.zoomedView.frame = destinationFrameInWindow; - } completion:^(BOOL finished) { - // reset zoomed view to original position - self.zoomedView.frame = self.zoomedView.zoomPlaceholderView.frame; - self.zoomedView.autoresizingMask = self.zoomedView.zoomPlaceholderView.autoresizingMask; - [self.zoomedView.zoomPlaceholderView.superview addSubview:self.zoomedView]; - [self.zoomedView.zoomPlaceholderView removeFromSuperview]; - self.zoomedView.zoomPlaceholderView = nil; - // hide window - self.hidden = YES; - - if (completionBlock != nil) { - completionBlock(); - } - }]; } - (UIView *)zoomSuperview { if (self.zoomedView.wrapInScrollviewWhenZoomed) { - if (self.scrollView.superview == nil) { - [self insertSubview:self.scrollView atIndex:1]; - } + self.scrollView.hidden = NO; return self.scrollView; } else { - [self.scrollView removeFromSuperview]; + self.scrollView.hidden = YES; return self; } } - (BOOL)isZoomedIn { - return !self.hidden && self.backgroundView.alpha > 0.f; + return !self.hidden && self.zoomedView != nil; } - (void)setZoomGestures:(NSInteger)zoomGestures { @@ -217,32 +223,17 @@ - (void)setZoomGestures:(NSInteger)zoomGestures { tapGestureRecognizer.numberOfTapsRequired = 2; [self.gestureRecognizers addObject:tapGestureRecognizer]; } - if (zoomGestures & MTZoomGesturePinch) { - UIPinchGestureRecognizer *pinchGestureRecognizer = [[[UIPinchGestureRecognizer alloc] initWithTarget:self - action:@selector(handleGesture:)] autorelease]; - [self.gestureRecognizers addObject:pinchGestureRecognizer]; - } // add new gesture recognizers to views for (UIGestureRecognizer *gestureRecognizer in self.gestureRecognizers) { [self.backgroundView addGestureRecognizer:gestureRecognizer]; - // TODO: add to zoomedView } } } - (void)handleGesture:(UIGestureRecognizer *)gestureRecognizer { if (gestureRecognizer.state == UIGestureRecognizerStateRecognized) { - if ([gestureRecognizer isKindOfClass:[UIPinchGestureRecognizer class]]) { - UIPinchGestureRecognizer *pinchGestureRecognizer = (UIPinchGestureRecognizer *)gestureRecognizer; - - if (pinchGestureRecognizer.scale < 1.0) { - // TODO: how to set completion block? - [self zoomOutWithCompletion:nil]; - } - } else { - [self zoomOutWithCompletion:nil]; - } + [self zoomOut]; } } @@ -255,20 +246,30 @@ - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView { return self.zoomedView; } +- (void)scrollViewDidZoom:(UIScrollView *)scrollView { + if (self.zoomGestures & MTZoomGesturePinch) { + if (!scrollView.zooming && scrollView.zoomBouncing && scrollView.zoomScale <= 1.f) { + [self zoomOut]; + } + } +} + //////////////////////////////////////////////////////////////////////// #pragma mark - #pragma mark Rotation //////////////////////////////////////////////////////////////////////// -- (void)orientationWillChange:(NSNotification *)note { - UIInterfaceOrientation current = [[UIApplication sharedApplication] statusBarOrientation]; - UIInterfaceOrientation orientation = [[[note userInfo] objectForKey: UIApplicationStatusBarOrientationUserInfoKey] integerValue]; - - // if ( [self shouldAutorotateToInterfaceOrientation: orientation] == NO ) - // return; +- (void)setupForOrientation:(UIInterfaceOrientation)orientation forceLayout:(BOOL)forceLayout { + UIInterfaceOrientation current = [[UIApplication sharedApplication] statusBarOrientation]; - if ( current == orientation ) - return; + if (!forceLayout) { + // if ( [self shouldAutorotateToInterfaceOrientation: orientation] == NO ) + // return; + + if (current == orientation) { + return; + } + } // direction and angle CGFloat angle = 0.0; @@ -354,20 +355,25 @@ - (void)orientationWillChange:(NSNotification *)note { } } - CGAffineTransform rotation = CGAffineTransformMakeRotation( angle ); + CGAffineTransform rotation = CGAffineTransformMakeRotation(angle); [UIView animateWithDuration:0.4 animations:^{ self.transform = CGAffineTransformConcat(rotation, self.transform); }]; } +- (void)orientationWillChange:(NSNotification *)note { + UIInterfaceOrientation orientation = [[[note userInfo] objectForKey: UIApplicationStatusBarOrientationUserInfoKey] integerValue]; + [self setupForOrientation:orientation forceLayout:NO]; +} + - (void)orientationDidChange:(NSNotification *)note { // UIInterfaceOrientation orientation = [[[note userInfo] objectForKey: UIApplicationStatusBarOrientationUserInfoKey] integerValue]; //if ([self shouldAutorotateToInterfaceOrientation:[[UIApplication sharedApplication] statusBarOrientation]] == NO) // return; - self.frame = [[UIScreen mainScreen] applicationFrame]; + self.frame = [[UIScreen mainScreen] bounds]; } //////////////////////////////////////////////////////////////////////// diff --git a/MTZoomWindow.xcodeproj/project.pbxproj b/MTZoomWindow.xcodeproj/project.pbxproj index 5d04c0a..b471523 100644 --- a/MTZoomWindow.xcodeproj/project.pbxproj +++ b/MTZoomWindow.xcodeproj/project.pbxproj @@ -9,6 +9,9 @@ /* Begin PBXBuildFile section */ 392B15A81326592500BF254A /* MTZoomWindow.h in Headers */ = {isa = PBXBuildFile; fileRef = 392B15A61326592500BF254A /* MTZoomWindow.h */; }; 392B15A91326592500BF254A /* MTZoomWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 392B15A71326592500BF254A /* MTZoomWindow.m */; }; + 9B0D3741145F3B0E00DB01C5 /* UIView+MTZoom.h in Headers */ = {isa = PBXBuildFile; fileRef = 9B0D373F145F3B0E00DB01C5 /* UIView+MTZoom.h */; }; + 9B0D3742145F3B0E00DB01C5 /* UIView+MTZoom.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B0D3740145F3B0E00DB01C5 /* UIView+MTZoom.m */; }; + 9B0D3746145F3BC400DB01C5 /* MTZoomWindowDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 9B0D3745145F3BC400DB01C5 /* MTZoomWindowDelegate.h */; }; AA747D9F0F9514B9006C5449 /* MTZoomWindow_Prefix.pch in Headers */ = {isa = PBXBuildFile; fileRef = AA747D9E0F9514B9006C5449 /* MTZoomWindow_Prefix.pch */; }; AACBBE4A0F95108600F1A2B1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AACBBE490F95108600F1A2B1 /* Foundation.framework */; }; /* End PBXBuildFile section */ @@ -16,6 +19,10 @@ /* Begin PBXFileReference section */ 392B15A61326592500BF254A /* MTZoomWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTZoomWindow.h; sourceTree = ""; }; 392B15A71326592500BF254A /* MTZoomWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTZoomWindow.m; sourceTree = ""; }; + 9B0D373F145F3B0E00DB01C5 /* UIView+MTZoom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+MTZoom.h"; sourceTree = ""; }; + 9B0D3740145F3B0E00DB01C5 /* UIView+MTZoom.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+MTZoom.m"; sourceTree = ""; }; + 9B0D3744145F3B1400DB01C5 /* Readme.mdown */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Readme.mdown; sourceTree = ""; }; + 9B0D3745145F3BC400DB01C5 /* MTZoomWindowDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTZoomWindowDelegate.h; sourceTree = ""; }; AA747D9E0F9514B9006C5449 /* MTZoomWindow_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTZoomWindow_Prefix.pch; sourceTree = SOURCE_ROOT; }; AACBBE490F95108600F1A2B1 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; D2AAC07E0554694100DB518D /* libMTZoomWindow.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libMTZoomWindow.a; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -65,6 +72,9 @@ children = ( 392B15A61326592500BF254A /* MTZoomWindow.h */, 392B15A71326592500BF254A /* MTZoomWindow.m */, + 9B0D3745145F3BC400DB01C5 /* MTZoomWindowDelegate.h */, + 9B0D373F145F3B0E00DB01C5 /* UIView+MTZoom.h */, + 9B0D3740145F3B0E00DB01C5 /* UIView+MTZoom.m */, ); name = Classes; sourceTree = ""; @@ -72,6 +82,7 @@ 32C88DFF0371C24200C91783 /* Other Sources */ = { isa = PBXGroup; children = ( + 9B0D3744145F3B1400DB01C5 /* Readme.mdown */, AA747D9E0F9514B9006C5449 /* MTZoomWindow_Prefix.pch */, ); name = "Other Sources"; @@ -86,6 +97,8 @@ files = ( AA747D9F0F9514B9006C5449 /* MTZoomWindow_Prefix.pch in Headers */, 392B15A81326592500BF254A /* MTZoomWindow.h in Headers */, + 9B0D3741145F3B0E00DB01C5 /* UIView+MTZoom.h in Headers */, + 9B0D3746145F3BC400DB01C5 /* MTZoomWindowDelegate.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -143,6 +156,7 @@ buildActionMask = 2147483647; files = ( 392B15A91326592500BF254A /* MTZoomWindow.m in Sources */, + 9B0D3742145F3B0E00DB01C5 /* UIView+MTZoom.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/MTZoomWindowDelegate.h b/MTZoomWindowDelegate.h new file mode 100644 index 0000000..7b9f9bd --- /dev/null +++ b/MTZoomWindowDelegate.h @@ -0,0 +1,27 @@ +// +// MTZoomWindowDelegate.h +// +// Created by Matthias Tretter on 31.10.2011. +// Copyright (c) 2009-2011 Matthias Tretter, @myell0w. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +@class MTZoomWindow; + +@protocol MTZoomWindowDelegate + +@optional + +- (void)zoomWindow:(MTZoomWindow *)zoomWindow willZoomInView:(UIView *)view; +- (void)zoomWindow:(MTZoomWindow *)zoomWindow didZoomInView:(UIView *)view; + +- (void)zoomWindow:(MTZoomWindow *)zoomWindow willZoomOutView:(UIView *)view; +- (void)zoomWindow:(MTZoomWindow *)zoomWindow didZoomOutView:(UIView *)view; + +@end \ No newline at end of file diff --git a/Readme.mdown b/Readme.mdown index e71806a..9fdb7f1 100644 --- a/Readme.mdown +++ b/Readme.mdown @@ -10,21 +10,21 @@ Usage You can use MTZoomWindow like this: - // configure zoom window - MTZoomWindow *zoomWindow = [[[MTZoomWindow alloc] initWithTargetView:targetView - gestureRecognizerClass:[UITapGestureRecognizer class]] autorelease]; // specify size of the UIView when it is zoomed in - zoomWindow.overlaySize = CGSizeMake(300,460); - // customize gesture recognizer - zoomWindow.windowGestureRecognizer.numberOfTapsRequired = 2; - zoomWindow.zoomedViewGestureRecognizer.numberOfTapsRequired = 2; - // That's it, when the user performs a double-tap on the targetView it get's zoomed + viewToZoom.zoomedSize = CGSizeMake(300,460); + viewToZoom.zoomedAutoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + viewToZoom.wrapInScrollViewWhenZoomed = YES; + + // find this awesome shortcut for UITapGestureRecognizer in @zwaldowski's BlocksKit + [viewToZoom whenTapped:^{ + [viewToZoom zoomIn]; + }]; Adding MTZoomWindow to your project ------------------ -1. Just copy over the files MTZoomWindow.h and MTZoomWindow.m to your project. +1. Just copy over the files MTZoomWindow.h, MTZoomWindow.m, UIView+MTZoom.h, UIView+MTZoom.m and MTZoomWindowDelegate.h to your project. 2. import "MTZoomWindow.h" everywhere where you want to use it 3. There is no step 3 :) diff --git a/UIView+MTZoom.h b/UIView+MTZoom.h index 065f88d..d987598 100644 --- a/UIView+MTZoom.h +++ b/UIView+MTZoom.h @@ -14,8 +14,7 @@ #import - -typedef void (^mt_zoom_block)(); +#import "MTZoomWindowDelegate.h" @interface UIView (MTZoom) @@ -23,13 +22,14 @@ typedef void (^mt_zoom_block)(); @property (nonatomic, assign, getter = isWrappedInScrollviewWhenZoomed) BOOL wrapInScrollviewWhenZoomed; /** The size of the view when zoomed in */ @property (nonatomic, assign) CGSize zoomedSize; +/** The autoresizing-maks of the view when zoomed in */ +@property (nonatomic, assign) UIViewAutoresizing zoomedAutoresizingMask; /** the view that acts as a placeholder while self is zoomedIn */ @property (nonatomic, retain) UIView *zoomPlaceholderView; +/** The delegate for zooming */ +@property (nonatomic, assign) id zoomDelegate; - (void)zoomIn; - (void)zoomOut; -- (void)zoomInWithPreparation:(mt_zoom_block)preparationBlock completion:(mt_zoom_block)completionBlock; -- (void)zoomOutWithPreparation:(mt_zoom_block)preparationBlock completion:(mt_zoom_block)completionBlock; - @end diff --git a/UIView+MTZoom.m b/UIView+MTZoom.m index fb08c47..aac6262 100644 --- a/UIView+MTZoom.m +++ b/UIView+MTZoom.m @@ -10,9 +10,22 @@ #import "MTZoomWindow.h" #import +#define kMTDefaultZoomedAutoresizingMask UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight + static char wrapKey; static char sizeKey; +static char autoresizingKey; static char placeholderKey; +static char delegateKey; + +@interface UIView () + +- (void)mt_callDelegateWillZoomIn; +- (void)mt_callDelegateDidZoomIn; +- (void)mt_callDelegateWillZoomOut; +- (void)mt_callDelegateDidZoomOut; + +@end @implementation UIView (MTZoom) @@ -22,42 +35,31 @@ @implementation UIView (MTZoom) //////////////////////////////////////////////////////////////////////// - (void)zoomIn { - [self zoomInWithPreparation:nil completion:nil]; -} - -- (void)zoomOut { - [self zoomOutWithPreparation:nil completion:nil]; -} - -- (void)zoomInWithPreparation:(mt_zoom_block)preparationBlock completion:(mt_zoom_block)completionBlock { - UIView *superview = self.superview; MTZoomWindow *zoomWindow = [MTZoomWindow sharedWindow]; - UIView *placeholderView = [[[UIView alloc] initWithFrame:self.frame] autorelease]; - - // setup invisible copy of self - placeholderView.autoresizingMask = self.autoresizingMask; - [superview insertSubview:placeholderView belowSubview:self]; - self.zoomPlaceholderView = placeholderView; - // call preparation-block before we are zooming in - if (preparationBlock != nil) { - preparationBlock(); + if (!zoomWindow.zoomedIn) { + UIView *superview = self.superview; + UIView *placeholderView = [[[UIView alloc] initWithFrame:self.frame] autorelease]; + + // setup invisible copy of self + placeholderView.autoresizingMask = self.autoresizingMask; + [superview insertSubview:placeholderView belowSubview:self]; + self.zoomPlaceholderView = placeholderView; + + [self mt_callDelegateWillZoomIn]; + + // Zoom view into fullscreen-mode and call delegate + [zoomWindow zoomView:self toSize:self.zoomedSize]; } - - // Zoom view into fullscreen-mode and call completion-block - [zoomWindow zoomView:self toSize:self.zoomedSize completion:completionBlock]; } -- (void)zoomOutWithPreparation:(mt_zoom_block)preparationBlock completion:(mt_zoom_block)completionBlock { +- (void)zoomOut { MTZoomWindow *zoomWindow = [MTZoomWindow sharedWindow]; - // call preparation-block before we are zooming out - if (preparationBlock != nil) { - preparationBlock(); - } + [self mt_callDelegateWillZoomOut]; - // zoom view back to original frame and call completion-block - [zoomWindow zoomOutWithCompletion:completionBlock]; + // zoom view back to original frame and call delegate + [zoomWindow zoomOut]; } //////////////////////////////////////////////////////////////////////// @@ -84,6 +86,28 @@ - (CGSize)zoomedSize { return [objc_getAssociatedObject(self, &sizeKey) CGSizeValue]; } +- (void)setZoomedAutoresizingMask:(UIViewAutoresizing)zoomedAutoresizingMask { + objc_setAssociatedObject(self, &autoresizingKey, [NSNumber numberWithInt:zoomedAutoresizingMask], OBJC_ASSOCIATION_RETAIN); +} + +- (UIViewAutoresizing)zoomedAutoresizingMask { + id autoresizingNumber = objc_getAssociatedObject(self, &autoresizingKey); + + if (autoresizingNumber == nil) { + return kMTDefaultZoomedAutoresizingMask; + } + + return (UIViewAutoresizing)[autoresizingNumber intValue]; +} + +- (void)setZoomDelegate:(id)zoomDelegate { + objc_setAssociatedObject(self, &delegateKey, zoomDelegate, OBJC_ASSOCIATION_ASSIGN); +} + +- (id)zoomDelegate { + return objc_getAssociatedObject(self, &delegateKey); +} + - (void)setZoomPlaceholderView:(UIView *)zoomPlaceholderView { objc_setAssociatedObject(self, &placeholderKey, zoomPlaceholderView, OBJC_ASSOCIATION_RETAIN); } @@ -92,4 +116,41 @@ - (UIView *)zoomPlaceholderView { return (UIView *)objc_getAssociatedObject(self, &placeholderKey); } +//////////////////////////////////////////////////////////////////////// +#pragma mark - +#pragma mark Delegate Calls +//////////////////////////////////////////////////////////////////////// + +- (void)mt_callDelegateWillZoomIn { + id delegate = self.zoomDelegate; + + if ([delegate respondsToSelector:@selector(zoomWindow:willZoomInView:)]) { + [delegate zoomWindow:[MTZoomWindow sharedWindow] willZoomInView:self]; + } +} + +- (void)mt_callDelegateDidZoomIn { + id delegate = self.zoomDelegate; + + if ([delegate respondsToSelector:@selector(zoomWindow:didZoomInView:)]) { + [delegate zoomWindow:[MTZoomWindow sharedWindow] didZoomInView:self]; + } +} + +- (void)mt_callDelegateWillZoomOut { + id delegate = self.zoomDelegate; + + if ([delegate respondsToSelector:@selector(zoomWindow:willZoomOutView:)]) { + [delegate zoomWindow:[MTZoomWindow sharedWindow] willZoomOutView:self]; + } +} + +- (void)mt_callDelegateDidZoomOut { + id delegate = self.zoomDelegate; + + if ([delegate respondsToSelector:@selector(zoomWindow:didZoomOutView:)]) { + [delegate zoomWindow:[MTZoomWindow sharedWindow] didZoomOutView:self]; + } +} + @end