Permalink
Browse files

Added support for any view to be the main view for transforming/sorti…

…ng space so that gestures can continue outisde of the frame of the view
  • Loading branch information...
1 parent 2f94480 commit 8ae124bb44c482a7410f724b6878d41334c27115 @gmoledina committed Nov 11, 2011
Showing with 102 additions and 51 deletions.
  1. +5 −4 GMGridView/API/GMGridView.h
  2. +87 −47 GMGridView/API/GMGridView.m
  3. +10 −0 GMGridView/ViewController.m
View
9 GMGridView/API/GMGridView.h
@@ -50,20 +50,21 @@ typedef enum
}
// Delegates
-@property (nonatomic, weak) NSObject<GMGridViewDataSource> *dataSource; // Required
-@property (nonatomic, weak) NSObject<GMGridViewSortingDelegate> *sortingDelegate; // Required to enable sorting
-@property (nonatomic, weak) NSObject<GMGridViewTransformationDelegate> *transformDelegate; // Required to enable fullsize mode
+@property (nonatomic, weak) NSObject<GMGridViewDataSource> *dataSource; // Required
+@property (nonatomic, weak) NSObject<GMGridViewSortingDelegate> *sortingDelegate; // Required to enable sorting
+@property (nonatomic, weak) NSObject<GMGridViewTransformationDelegate> *transformDelegate; // Required to enable fullsize mode
// Layout Strategy
@property (nonatomic, strong) id<GMGridViewLayoutStrategy> layoutStrategy; // Default is GMGridViewLayoutVerticalStrategy
// Customizing Options
+@property (nonatomic, weak) UIView *mainSuperView; // Default is self
@property (nonatomic) GMGridViewStyle style; // Default is GMGridViewStyleSwap
@property (nonatomic) NSInteger itemSpacing; // Default is 10
@property (nonatomic) BOOL centerGrid; // Default is YES
@property (nonatomic) UIEdgeInsets minEdgeInsets; // Default is (5, 5, 5, 5)
@property (nonatomic) CFTimeInterval minimumPressDuration; // Default is 0.2; if set to 0, the scrollView will not be scrollable
-@property (nonatomic) BOOL showFullSizeViewWithAlphaWhenTransforming; // Default is YES
+@property (nonatomic) BOOL showFullSizeViewWithAlphaWhenTransforming; // Default is YES - not working right now
// Actions
- (void)reloadData;
View
134 GMGridView/API/GMGridView.m
@@ -32,9 +32,9 @@
#import "GMGridViewLayoutStrategies.h"
#import "UIGestureRecognizer+GMGridViewAdditions.h"
-
-static const CGFloat kDefaultAnimationDuration = 0.3;
static const NSUInteger kTagOffset = 50;
+static const CGFloat kDefaultAnimationDuration = 0.3;
+static const UIViewAnimationOptions kDefaultAnimationOptions = UIViewAnimationOptionBeginFromCurrentState;
//////////////////////////////////////////////////////////////
@@ -76,7 +76,6 @@ @interface GMGridView () <UIGestureRecognizerDelegate>
BOOL _inFullSizeMode;
}
-
@property (nonatomic, readonly) BOOL itemsSubviewsCacheIsValid;
@property (nonatomic, strong) NSArray *itemSubviewsCache;
@@ -99,7 +98,6 @@ - (void)sortingAutoScrollMovementCheck;
- (void)transformingGestureDidBeginWithGesture:(UIGestureRecognizer *)gesture;
- (void)transformingGestureDidFinish;
- (BOOL)isInTransformingState;
-- (void)exitFullSizePinchGestureUpdated:(UIPinchGestureRecognizer *)pinchGesture;
// Helpers & more
- (void)recomputeSize;
@@ -122,6 +120,7 @@ - (void)setSubviewsCacheAsInvalid;
@implementation GMGridView
@synthesize sortingDelegate = _sortingDelegate, dataSource = _dataSource, transformDelegate = _transformDelegate;
+@synthesize mainSuperView = _mainSuperView;
@synthesize layoutStrategy = _layoutStrategy;
@synthesize itemSpacing = _itemSpacing;
@synthesize style = _style;
@@ -157,7 +156,7 @@ - (id)initWithFrame:(CGRect)frame
_tapGesture.numberOfTouchesRequired = 1;
[_scrollView addGestureRecognizer:_tapGesture];
-
+ /////////////////////////////
// Transformation gestures :
_pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchGestureUpdated:)];
@@ -174,6 +173,7 @@ - (id)initWithFrame:(CGRect)frame
[_panGesture setMinimumNumberOfTouches:2];
[self addGestureRecognizer:_panGesture];
+ //////////////////////
// Sorting gestures :
_sortingPanGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(sortingPanGestureUpdated:)];
@@ -185,18 +185,20 @@ - (id)initWithFrame:(CGRect)frame
_sortingLongPressGesture.delegate = self;
[_scrollView addGestureRecognizer:_sortingLongPressGesture];
-
+ ////////////////////////
// Gesture dependencies
[_scrollView.panGestureRecognizer setMaximumNumberOfTouches:1];
[_scrollView.panGestureRecognizer requireGestureRecognizerToFail:_sortingPanGesture];
self.layoutStrategy = [GMGridViewLayoutStrategyFactory strategyFromType:GMGridViewLayoutVertical];
+ self.mainSuperView = self;
self.itemSpacing = 10;
self.style = GMGridViewStyleSwap;
self.minimumPressDuration = 0.2;
self.showFullSizeViewWithAlphaWhenTransforming = YES;
self.minEdgeInsets = UIEdgeInsetsMake(5, 5, 5, 5);
+ self.clipsToBounds = NO;
_sortFuturePosition = GMGV_INVALID_POSITION;
_itemSize = CGSizeZero;
@@ -236,6 +238,11 @@ - (void)setDataSource:(NSObject<GMGridViewDataSource> *)dataSource
[self reloadData];
}
+- (void)setMainSuperView:(UIView *)mainSuperView
+{
+ _mainSuperView = mainSuperView != nil ? mainSuperView : self;
+}
+
- (void)setLayoutStrategy:(id<GMGridViewLayoutStrategy>)layoutStrategy
{
_layoutStrategy = layoutStrategy;
@@ -435,7 +442,7 @@ - (void)sortingAutoScrollMovementCheck
offset.y = _maxPossibleContentOffset.y;
}
}
- // Going leftz
+ // Going left
else if (locationInMainView.y - threshhold <= 0)
{
offset.y -= _itemSize.height;
@@ -449,8 +456,8 @@ - (void)sortingAutoScrollMovementCheck
if (offset.x != _scrollView.contentOffset.x || offset.y != _scrollView.contentOffset.y)
{
[UIView animateWithDuration:kDefaultAnimationDuration
- delay:0
- options:0
+ delay:0
+ options:kDefaultAnimationOptions
animations:^{
_scrollView.contentOffset = offset;
}
@@ -481,11 +488,11 @@ - (void)sortingMoveDidStartAtPoint:(CGPoint)point
[_scrollView bringSubviewToFront:item];
_sortMovingItem = item;
- CGRect frameInMainView = [_scrollView convertRect:_sortMovingItem.frame toView:self];
+ CGRect frameInMainView = [_scrollView convertRect:_sortMovingItem.frame toView:self.mainSuperView];
[_sortMovingItem removeFromSuperview];
_sortMovingItem.frame = frameInMainView;
- [self addSubview:_sortMovingItem];
+ [self.mainSuperView addSubview:_sortMovingItem];
_sortFuturePosition = _sortMovingItem.tag - kTagOffset;
_sortMovingItem.tag = 0;
@@ -511,7 +518,7 @@ - (void)sortingMoveDidStopAtPoint:(CGPoint)point
_sortMovingItem.tag = _sortFuturePosition + kTagOffset;
- CGRect frameInScroll = [self convertRect:_sortMovingItem.frame toView:_scrollView];
+ CGRect frameInScroll = [self.mainSuperView convertRect:_sortMovingItem.frame toView:_scrollView];
[_sortMovingItem removeFromSuperview];
_sortMovingItem.frame = frameInScroll;
@@ -521,6 +528,8 @@ - (void)sortingMoveDidStopAtPoint:(CGPoint)point
CGRect newFrame = CGRectMake(newOrigin.x, newOrigin.y, _itemSize.width, _itemSize.height);
[UIView animateWithDuration:kDefaultAnimationDuration
+ delay:0
+ options:0
animations:^{
_sortMovingItem.transform = CGAffineTransformIdentity;
_sortMovingItem.frame = newFrame;
@@ -601,7 +610,7 @@ - (void)sortingMoveDidContinueToPoint:(CGPoint)point
[UIView animateWithDuration:kDefaultAnimationDuration
delay:0
- options:UIViewAnimationOptionAllowAnimatedContent | UIViewAnimationOptionBeginFromCurrentState
+ options:kDefaultAnimationOptions
animations:^{
v.frame = CGRectMake(origin.x, origin.y, _itemSize.width, _itemSize.height);
}
@@ -648,6 +657,11 @@ - (void)panGestureUpdated:(UIPanGestureRecognizer *)panGesture
}
case UIGestureRecognizerStateChanged:
{
+ if (panGesture.numberOfTouches != 2)
+ {
+ [panGesture end];
+ }
+
CGPoint translate = [panGesture translationInView:_scrollView];
[_transformingItem.contentView setCenter:CGPointMake(_transformingItem.contentView.center.x + translate.x, _transformingItem.contentView.center.y + translate.y)];
[panGesture setTranslation:CGPointZero inView:_scrollView];
@@ -698,7 +712,9 @@ - (void)pinchGestureUpdated:(UIPinchGestureRecognizer *)pinchGesture
_lastScale = [_pinchGesture scale];
- CGFloat alpha = 1 - (2.5 - currentScale);
+ currentScale += scale;
+
+ CGFloat alpha = 1 - (kMaxScale - currentScale);
alpha = MAX(0, alpha);
alpha = MIN(1, alpha);
@@ -707,7 +723,7 @@ - (void)pinchGestureUpdated:(UIPinchGestureRecognizer *)pinchGesture
[_transformingItem stepToFullsizeWithAlpha:alpha];
}
- _transformingItem.backgroundColor = [[UIColor darkGrayColor] colorWithAlphaComponent:MIN(alpha, 0.7)];
+ _transformingItem.backgroundColor = [[UIColor darkGrayColor] colorWithAlphaComponent:MIN(alpha, 0.9)];
}
break;
@@ -754,30 +770,36 @@ - (void)rotationGestureUpdated:(UIRotationGestureRecognizer *)rotationGesture
- (void)transformingGestureDidBeginWithGesture:(UIGestureRecognizer *)gesture
{
- if (_inFullSizeMode)
+ if (_inFullSizeMode && [gesture isKindOfClass:[UIPinchGestureRecognizer class]])
{
+ _pinchGesture.scale = 2.5;
+ }
+
+ if (_inFullSizeMode)
+ {
_inFullSizeMode = NO;
-
- _lastScale = 1.0;
+
+ CGPoint center = _transformingItem.fullSizeView.center;
[_transformingItem switchToFullSizeMode:NO];
- CGAffineTransform newTransform = CGAffineTransformMakeScale(3, 3);
+ CGAffineTransform newTransform = CGAffineTransformMakeScale(2.5, 2.5);
_transformingItem.contentView.transform = newTransform;
+ _transformingItem.contentView.center = center;
}
else if (!_transformingItem)
{
CGPoint locationTouch = [gesture locationOfTouch:0 inView:_scrollView];
NSInteger positionTouch = [self.layoutStrategy itemPositionFromLocation:locationTouch];
_transformingItem = [self itemSubViewForPosition:positionTouch];
- CGRect frameInMainView = [_scrollView convertRect:_transformingItem.frame toView:self];
+ CGRect frameInMainView = [_scrollView convertRect:_transformingItem.frame toView:self.mainSuperView];
[_transformingItem removeFromSuperview];
- _transformingItem.frame = self.bounds;
+ _transformingItem.frame = self.mainSuperView.bounds;
_transformingItem.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
_transformingItem.contentView.frame = frameInMainView;
- [self addSubview:_transformingItem];
- [self bringSubviewToFront:_transformingItem];
+ [self.mainSuperView addSubview:_transformingItem];
+ [self.mainSuperView bringSubviewToFront:_transformingItem];
_transformingItem.fullSize = [self.transformDelegate GMGridView:self sizeInFullSizeForView:_transformingItem.contentView];
_transformingItem.fullSizeView = [self.transformDelegate GMGridView:self fullSizeViewForView:_transformingItem];
@@ -798,61 +820,79 @@ - (void)transformingGestureDidFinish
{
if ([self isInTransformingState])
{
- if (_lastScale > 2)
- {
+ if (_lastScale > 2 && !_inFullSizeMode)
+ {
_lastRotation = 0;
- _lastScale = 1.0;
+ _lastScale = 1;
[self bringSubviewToFront:_transformingItem];
-
+
+ CGFloat rotationValue = atan2f(_transformingItem.contentView.transform.b, _transformingItem.contentView.transform.a);
+
_transformingItem.contentView.transform = CGAffineTransformIdentity;
[_transformingItem switchToFullSizeMode:YES];
- _transformingItem.backgroundColor = [[UIColor darkGrayColor] colorWithAlphaComponent:0.7];
+ _transformingItem.backgroundColor = [[UIColor darkGrayColor] colorWithAlphaComponent:0.9];
+
+ _transformingItem.fullSizeView.transform = CGAffineTransformMakeRotation(rotationValue);
+ [UIView animateWithDuration:0.3 animations:^{
+ _transformingItem.fullSizeView.transform = CGAffineTransformIdentity;
+ }];
_inFullSizeMode = YES;
if ([self.transformDelegate respondsToSelector:@selector(GMGridView:didEnterFullSizeForView:)])
{
[self.transformDelegate GMGridView:self didEnterFullSizeForView:_transformingItem.contentView];
}
+
+ // Transfer the gestures on the fullscreen to make is they are accessible (depends on self.mainSuperView)
+ [_transformingItem.fullSizeView addGestureRecognizer:_pinchGesture];
+ [_transformingItem.fullSizeView addGestureRecognizer:_rotationGesture];
+ [_transformingItem.fullSizeView addGestureRecognizer:_panGesture];
}
- else
+ else if (!_inFullSizeMode)
{
_lastRotation = 0;
_lastScale = 1.0;
GMGridViewCell *transformingView = _transformingItem;
_transformingItem = nil;
- transformingView.contentView.transform = CGAffineTransformIdentity;
- transformingView.backgroundColor = [UIColor clearColor];
-
- CGRect frameInScroll = [self convertRect:transformingView.contentView.frame toView:_scrollView];
-
- [transformingView removeFromSuperview];
- transformingView.frame = frameInScroll;
- transformingView.contentView.frame = transformingView.bounds;
- [_scrollView addSubview:transformingView];
-
NSInteger position = [self positionForItemSubview:transformingView];
CGPoint origin = [self.layoutStrategy originForItemAtPosition:position];
+ CGRect finalFrameInScroll = CGRectMake(origin.x, origin.y, _itemSize.width, _itemSize.height);
+ CGRect finalFrameInSuperview = [_scrollView convertRect:finalFrameInScroll toView:self.mainSuperView];
[transformingView switchToFullSizeMode:NO];
transformingView.autoresizingMask = UIViewAutoresizingNone;
- [UIView animateWithDuration:kDefaultAnimationDuration
+ [UIView animateWithDuration: kDefaultAnimationDuration
+ delay:0
+ options: kDefaultAnimationOptions
animations:^{
- transformingView.frame = CGRectMake(origin.x, origin.y, _itemSize.width, _itemSize.height);
+ transformingView.contentView.transform = CGAffineTransformIdentity;
+ transformingView.contentView.frame = finalFrameInSuperview;
+ transformingView.backgroundColor = [UIColor clearColor];
}
completion:^(BOOL finished){
+
+ [transformingView removeFromSuperview];
+ transformingView.frame = finalFrameInScroll;
+ transformingView.contentView.frame = transformingView.bounds;
+ [_scrollView addSubview:transformingView];
+
transformingView.fullSizeView = nil;
- [self relayoutItems];
if ([self.transformDelegate respondsToSelector:@selector(GMGridView:didEndTransformingView:)])
{
[self.transformDelegate GMGridView:self didEndTransformingView:transformingView.contentView];
}
+
+ // Transfer the gestures back
+ [self addGestureRecognizer:_pinchGesture];
+ [self addGestureRecognizer:_rotationGesture];
+ [self addGestureRecognizer:_panGesture];
}
];
}
@@ -1021,7 +1061,7 @@ - (void)relayoutItems
{
[UIView animateWithDuration:kDefaultAnimationDuration
delay:0
- options:UIViewAnimationOptionAllowAnimatedContent | UIViewAnimationOptionBeginFromCurrentState
+ options:kDefaultAnimationOptions
animations:^{
for (UIView *view in [self itemSubviews])
@@ -1091,8 +1131,8 @@ - (void)reloadObjectAtIndex:(NSInteger)index
currentView.tag = kTagOffset - 1;
[UIView animateWithDuration:kDefaultAnimationDuration
- delay:0
- options:0
+ delay:0
+ options:kDefaultAnimationOptions
animations:^{
currentView.alpha = 0;
cell.alpha = 1;
@@ -1145,8 +1185,8 @@ - (void)removeObjectAtIndex:(NSInteger)index
cell.tag = kTagOffset - 1;
[UIView animateWithDuration:kDefaultAnimationDuration
- delay:0
- options:0
+ delay:0
+ options:kDefaultAnimationOptions
animations:^{
cell.alpha = 0;
}
View
10 GMGridView/ViewController.m
@@ -133,6 +133,16 @@ - (void)loadView
}
}
+- (void)viewDidLoad
+{
+ [super viewDidLoad];
+ _gmGridView.mainSuperView = [UIApplication sharedApplication].keyWindow.rootViewController.view;
+}
+
+- (void)viewDidAppear:(BOOL)animated
+{
+ [super viewDidAppear:animated];
+}
//////////////////////////////////////////////////////////////
#pragma mark memory management

0 comments on commit 8ae124b

Please sign in to comment.