Skip to content

Commit

Permalink
Finished redesign
Browse files Browse the repository at this point in the history
  • Loading branch information
myell0w committed Oct 31, 2011
1 parent d45d508 commit 1c6e3c5
Show file tree
Hide file tree
Showing 7 changed files with 233 additions and 123 deletions.
10 changes: 6 additions & 4 deletions MTZoomWindow.h
Expand Up @@ -22,19 +22,21 @@ typedef enum {
MTZoomGesturePinch = 4
} MTZoomGesture;

typedef NSInteger MTZoomGestureMask;

@interface MTZoomWindow : UIWindow <UIScrollViewDelegate>

@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
160 changes: 83 additions & 77 deletions MTZoomWindow.m
Expand Up @@ -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"

Expand All @@ -26,6 +27,7 @@ - (void)handleGesture:(UIGestureRecognizer *)gestureRecognizer;

- (void)orientationWillChange:(NSNotification *)note;
- (void)orientationDidChange:(NSNotification *)note;
- (void)setupForOrientation:(UIInterfaceOrientation)orientation forceLayout:(BOOL)forceLayout;

@end

Expand All @@ -40,8 +42,7 @@ @implementation MTZoomWindow
@synthesize scrollView = scrollView_;
@synthesize zoomedView = zoomedView_;
@synthesize gestureRecognizers = gestureRecognizers_;

#import <QuartzCore/QuartzCore.h>
@synthesize maximumZoomScale = maximumZoomScale_;

////////////////////////////////////////////////////////////////////////
#pragma mark -
Expand All @@ -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
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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<MTZoomWindowDelegate> 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<MTZoomWindowDelegate> 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 {
Expand All @@ -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];
}
}

Expand All @@ -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;
Expand Down Expand Up @@ -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];
}

////////////////////////////////////////////////////////////////////////
Expand Down
14 changes: 14 additions & 0 deletions MTZoomWindow.xcodeproj/project.pbxproj
Expand Up @@ -9,13 +9,20 @@
/* 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 */

/* Begin PBXFileReference section */
392B15A61326592500BF254A /* MTZoomWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTZoomWindow.h; sourceTree = "<group>"; };
392B15A71326592500BF254A /* MTZoomWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTZoomWindow.m; sourceTree = "<group>"; };
9B0D373F145F3B0E00DB01C5 /* UIView+MTZoom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+MTZoom.h"; sourceTree = "<group>"; };
9B0D3740145F3B0E00DB01C5 /* UIView+MTZoom.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+MTZoom.m"; sourceTree = "<group>"; };
9B0D3744145F3B1400DB01C5 /* Readme.mdown */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Readme.mdown; sourceTree = "<group>"; };
9B0D3745145F3BC400DB01C5 /* MTZoomWindowDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTZoomWindowDelegate.h; sourceTree = "<group>"; };
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; };
Expand Down Expand Up @@ -65,13 +72,17 @@
children = (
392B15A61326592500BF254A /* MTZoomWindow.h */,
392B15A71326592500BF254A /* MTZoomWindow.m */,
9B0D3745145F3BC400DB01C5 /* MTZoomWindowDelegate.h */,
9B0D373F145F3B0E00DB01C5 /* UIView+MTZoom.h */,
9B0D3740145F3B0E00DB01C5 /* UIView+MTZoom.m */,
);
name = Classes;
sourceTree = "<group>";
};
32C88DFF0371C24200C91783 /* Other Sources */ = {
isa = PBXGroup;
children = (
9B0D3744145F3B1400DB01C5 /* Readme.mdown */,
AA747D9E0F9514B9006C5449 /* MTZoomWindow_Prefix.pch */,
);
name = "Other Sources";
Expand All @@ -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;
};
Expand Down Expand Up @@ -143,6 +156,7 @@
buildActionMask = 2147483647;
files = (
392B15A91326592500BF254A /* MTZoomWindow.m in Sources */,
9B0D3742145F3B0E00DB01C5 /* UIView+MTZoom.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down

0 comments on commit 1c6e3c5

Please sign in to comment.