Skip to content
Browse files

- Refactored using JTTableViewGestureRecognizer

  • Loading branch information...
1 parent 76f78c2 commit 2c4c8bd746ce3bc94096a2cf8546584917b49642 @jamztang jamztang committed Feb 13, 2012
View
8 JTGestureBasedTableViewDemo.xcodeproj/project.pbxproj
@@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
+ 523708F214E9461E00A955C4 /* JTTableViewGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 523708F114E9461E00A955C4 /* JTTableViewGestureRecognizer.m */; };
52D6217D14DF7F1E00400117 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D6217C14DF7F1E00400117 /* UIKit.framework */; };
52D6217F14DF7F1E00400117 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D6217E14DF7F1E00400117 /* Foundation.framework */; };
52D6218114DF7F1E00400117 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D6218014DF7F1E00400117 /* CoreGraphics.framework */; };
@@ -36,6 +37,8 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
+ 523708F014E9461E00A955C4 /* JTTableViewGestureRecognizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JTTableViewGestureRecognizer.h; sourceTree = "<group>"; };
+ 523708F114E9461E00A955C4 /* JTTableViewGestureRecognizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JTTableViewGestureRecognizer.m; sourceTree = "<group>"; };
52D6217814DF7F1E00400117 /* JTGestureBasedTableViewDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JTGestureBasedTableViewDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
52D6217C14DF7F1E00400117 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
52D6217E14DF7F1E00400117 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
@@ -126,6 +129,8 @@
52D6218F14DF7F1E00400117 /* ViewController.m */,
52D621B814DF84A500400117 /* TransformableTableViewCell.h */,
52D621B914DF84A500400117 /* TransformableTableViewCell.m */,
+ 523708F014E9461E00A955C4 /* JTTableViewGestureRecognizer.h */,
+ 523708F114E9461E00A955C4 /* JTTableViewGestureRecognizer.m */,
52D6219114DF7F1E00400117 /* ViewController_iPhone.xib */,
52D6219414DF7F1E00400117 /* ViewController_iPad.xib */,
52D6218314DF7F1E00400117 /* Supporting Files */,
@@ -274,6 +279,7 @@
52D6218D14DF7F1E00400117 /* AppDelegate.m in Sources */,
52D6219014DF7F1E00400117 /* ViewController.m in Sources */,
52D621BA14DF84A500400117 /* TransformableTableViewCell.m in Sources */,
+ 523708F214E9461E00A955C4 /* JTTableViewGestureRecognizer.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -454,6 +460,7 @@
52D621B014DF7F1E00400117 /* Release */,
);
defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
};
52D621B114DF7F1E00400117 /* Build configuration list for PBXNativeTarget "JTGestureBasedTableViewDemoTests" */ = {
isa = XCConfigurationList;
@@ -462,6 +469,7 @@
52D621B314DF7F1E00400117 /* Release */,
);
defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
View
42 JTGestureBasedTableViewDemo/JTTableViewGestureRecognizer.h
@@ -0,0 +1,42 @@
+//
+// JTTableViewGestureDelegate.h
+// JTGestureBasedTableViewDemo
+//
+// Created by James Tang on 2/13/12.
+// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@protocol JTTableViewGestureDelegate;
+
+@interface JTTableViewGestureRecognizer : NSObject <UITableViewDelegate>
+
+@property (nonatomic, assign, readonly) UITableView *tableView;
+
++ (JTTableViewGestureRecognizer *)gestureRecognizerWithTableView:(UITableView *)tableView delegate:(id <JTTableViewGestureDelegate>)delegate;
+
+@end
+
+
+@protocol JTTableViewGestureDelegate <NSObject, UITableViewDelegate>
+
+- (void)gestureRecognizer:(JTTableViewGestureRecognizer *)gestureRecognizer needsAddRowAtIndexPath:(NSIndexPath *)indexPath;
+- (void)gestureRecognizer:(JTTableViewGestureRecognizer *)gestureRecognizer needsCommitRowAtIndexPath:(NSIndexPath *)indexPath;
+- (void)gestureRecognizer:(JTTableViewGestureRecognizer *)gestureRecognizer needsDiscardRowAtIndexPath:(NSIndexPath *)indexPath;
+@optional
+
+- (NSIndexPath *)gestureRecognizer:(JTTableViewGestureRecognizer *)gestureRecognizer willCreateCellAtIndexPath:(NSIndexPath *)indexPath;
+- (CGFloat)heightForCommittingRowForGestureRecognizer:(JTTableViewGestureRecognizer *)gestureRecognizer;
+
+@end
+
+
+
+
+
+@interface UITableView (JTTableViewGestureDelegate)
+
+- (JTTableViewGestureRecognizer *)enableGestureTableViewWithDelegate:(id <JTTableViewGestureDelegate>)delegate;
+
+@end
View
161 JTGestureBasedTableViewDemo/JTTableViewGestureRecognizer.m
@@ -0,0 +1,161 @@
+//
+// JTTableViewGestureDelegate.m
+// JTGestureBasedTableViewDemo
+//
+// Created by James Tang on 2/13/12.
+// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
+//
+
+#import "JTTableViewGestureRecognizer.h"
+
+@interface JTTableViewGestureRecognizer ()
+@property (nonatomic, assign) id <UITableViewDelegate, JTTableViewGestureDelegate> delegate;
+@property (nonatomic, assign) UITableView *tableView;
+@property (nonatomic, assign) CGFloat addingRowHeight;
+@property (nonatomic, retain) NSIndexPath *addingIndexPath;
+@property (nonatomic, assign) CGPoint startPinchingUpperPoint;
+@property (nonatomic, retain) UIPinchGestureRecognizer *pinchRecognizer;
+@end
+
+@implementation JTTableViewGestureRecognizer
+@synthesize delegate, tableView;
+@synthesize addingIndexPath, startPinchingUpperPoint, addingRowHeight;
+@synthesize pinchRecognizer;
+
+#pragma mark Action
+
+- (void)pinchGestureRecognizer:(UIPinchGestureRecognizer *)recognizer {
+ NSLog(@"%d %f %f", [recognizer numberOfTouches], [recognizer velocity], [recognizer scale]);
+ if (recognizer.state == UIGestureRecognizerStateEnded || [recognizer numberOfTouches] < 2) {
+ if (self.addingIndexPath) {
+ UITableViewCell *cell = (UITableViewCell *)[self.tableView cellForRowAtIndexPath:self.addingIndexPath];
+ [self.tableView beginUpdates];
+
+
+ CGFloat commitingCellHeight = self.tableView.rowHeight;
+ if ([self.delegate respondsToSelector:@selector(heightForCommittingRowForGestureRecognizer:)]) {
+ commitingCellHeight = [self.delegate heightForCommittingRowForGestureRecognizer:self];
+ }
+
+ if (cell.frame.size.height >= commitingCellHeight) {
+ [self.delegate gestureRecognizer:self needsCommitRowAtIndexPath:self.addingIndexPath];
+ } else {
+ [self.delegate gestureRecognizer:self needsDiscardRowAtIndexPath:self.addingIndexPath];
+ [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:self.addingIndexPath] withRowAnimation:UITableViewRowAnimationMiddle];
+ }
+ self.addingIndexPath = nil;
+ [self.tableView endUpdates];
+
+ // Restore contentInset while touch ends
+ [UIView beginAnimations:@"" context:nil];
+ [UIView setAnimationBeginsFromCurrentState:YES];
+ [UIView setAnimationDuration:0.5]; // Should not be less than the duration of row animation
+ self.tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
+ [UIView commitAnimations];
+ }
+ return;
+ }
+
+ CGPoint location1 = [recognizer locationOfTouch:0 inView:self.tableView];
+ CGPoint location2 = [recognizer locationOfTouch:1 inView:self.tableView];
+ CGPoint upperPoint = location1.y < location2.y ? location1 : location2;
+
+ CGRect rect = (CGRect){location1, location2.x - location1.x, location2.y - location1.y};
+
+ if (recognizer.state == UIGestureRecognizerStateBegan) {
+ NSArray *indexPaths = [self.tableView indexPathsForRowsInRect:rect];
+
+ NSIndexPath *firstIndexPath = [indexPaths objectAtIndex:0];
+ NSIndexPath *lastIndexPath = [indexPaths lastObject];
+ NSInteger midIndex = ((float)(firstIndexPath.row + lastIndexPath.row) / 2) + 0.5;
+ NSIndexPath *midIndexPath = [NSIndexPath indexPathForRow:midIndex inSection:firstIndexPath.section];
+
+ // Setting up properties for referencing later when touches changes
+ self.startPinchingUpperPoint = upperPoint;
+
+ if ([self.delegate respondsToSelector:@selector(gestureRecognizer:willCreateCellAtIndexPath:)]) {
+ self.addingIndexPath = [self.delegate gestureRecognizer:self willCreateCellAtIndexPath:midIndexPath];
+ } else {
+ self.addingIndexPath = midIndexPath;
+ }
+
+ // Creating contentInset to fulfill the whole screen, so our tableview won't occasionaly
+ // bounds back to the top while we don't have enough cells on the screen
+ self.tableView.contentInset = UIEdgeInsetsMake(self.tableView.frame.size.height, 0, self.tableView.frame.size.height, 0);
+
+ if (self.addingIndexPath) {
+ [self.tableView beginUpdates];
+ // [self.rows insertObject:ADDING_CELL atIndex:midIndex];
+
+ [self.delegate gestureRecognizer:self needsAddRowAtIndexPath:self.addingIndexPath];
+
+ [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:self.addingIndexPath] withRowAnimation:UITableViewRowAnimationMiddle];
+ [self.tableView endUpdates];
+ }
+
+ } else if (recognizer.state == UIGestureRecognizerStateChanged) {
+
+ CGFloat diffRowHeight = CGRectGetHeight(rect) - CGRectGetHeight(rect)/[recognizer scale];
+
+ NSLog(@"%f %f %f", CGRectGetHeight(rect), CGRectGetHeight(rect)/[recognizer scale], [recognizer scale]);
+ if (self.addingRowHeight - diffRowHeight >= 1 || self.addingRowHeight - diffRowHeight <= -1) {
+ self.addingRowHeight = diffRowHeight;
+ [self.tableView reloadData];
+ }
+
+ // Scrolls tableview according to the upper touch point to mimic a realistic
+ // dragging gesture
+ CGPoint newUpperPoint = upperPoint;
+ CGFloat diffOffsetY = self.startPinchingUpperPoint.y - newUpperPoint.y;
+ CGPoint newOffset = (CGPoint){self.tableView.contentOffset.x, self.tableView.contentOffset.y+diffOffsetY};
+ [self.tableView setContentOffset:newOffset animated:NO];
+ }
+}
+
+- (CGFloat)tableView:(UITableView *)aTableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
+ if ([indexPath isEqual:self.addingIndexPath]) {
+ return MAX(1, self.addingRowHeight);
+ }
+
+ CGFloat normalCellHeight = 44;
+ if ([self.delegate respondsToSelector:@selector(tableView:heightForRowAtIndexPath:)]) {
+ normalCellHeight = [self.delegate tableView:aTableView heightForRowAtIndexPath:indexPath];
+ }
+ return normalCellHeight;
+}
+
+#pragma mark NSProxy
+
+- (void)forwardInvocation:(NSInvocation *)anInvocation {
+ [anInvocation invokeWithTarget:self.delegate];
+}
+
+- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
+ return [(NSObject *)self.delegate methodSignatureForSelector:aSelector];
+}
+
+#pragma mark Class method
+
++ (JTTableViewGestureRecognizer *)gestureRecognizerWithTableView:(UITableView *)tableView delegate:(id<JTTableViewGestureDelegate>)delegate {
+ JTTableViewGestureRecognizer *recognizer = [[JTTableViewGestureRecognizer alloc] init];
+ tableView.delegate = recognizer;
+ recognizer.delegate = delegate;
+ recognizer.tableView = tableView;
+
+ UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:recognizer action:@selector(pinchGestureRecognizer:)];
+ [tableView addGestureRecognizer:pinch];
+ recognizer.pinchRecognizer = pinch;
+ return recognizer;
+}
+
+@end
+
+
+@implementation UITableView (JTTableViewGestureDelegate)
+
+- (JTTableViewGestureRecognizer *)enableGestureTableViewWithDelegate:(id <JTTableViewGestureDelegate>)delegate {
+ JTTableViewGestureRecognizer *recognizer = [JTTableViewGestureRecognizer gestureRecognizerWithTableView:self delegate:delegate];
+ return recognizer;
+}
+
+@end
View
5 JTGestureBasedTableViewDemo/TransformableTableViewCell.m
@@ -41,10 +41,11 @@ - (void)setSelected:(BOOL)selected animated:(BOOL)animated
- (void)layoutSubviews {
[super layoutSubviews];
- CGFloat fraction = (self.contentView.frame.size.height / self.finishedHeight);
+ CGFloat fraction = (self.frame.size.height / self.finishedHeight);
fraction = MAX(MIN(1, fraction), 0);
- CATransform3D transform = CATransform3DMakeRotation((M_PI / 2) - asinf(fraction), -1, 0, 0);
+ CGFloat angle = (M_PI / 2) - asinf(fraction);
+ CATransform3D transform = CATransform3DMakeRotation(angle, -1, 0, 0);
[self.textLabel.layer setTransform:transform];
[self.detailTextLabel.layer setTransform:CATransform3DMakeRotation((M_PI / 2) - asinf(fraction), 1, 0, 0)];
View
119 JTGestureBasedTableViewDemo/ViewController.m
@@ -8,18 +8,21 @@
#import "ViewController.h"
#import "TransformableTableViewCell.h"
+#import "JTTableViewGestureRecognizer.h"
#import <QuartzCore/QuartzCore.h>
-@interface ViewController ()
+@interface ViewController () <JTTableViewGestureDelegate>
@property (nonatomic, strong) NSMutableArray *rows;
@property (nonatomic, strong) NSIndexPath *addingIndexPath;
@property (nonatomic, assign) CGFloat addingRowHeight;
@property (nonatomic, assign) CGPoint startPinchingUpperPoint;
+@property (nonatomic, strong) JTTableViewGestureRecognizer *tableViewRecognizer;
@end
@implementation ViewController
@synthesize rows;
@synthesize addingIndexPath, addingRowHeight, startPinchingUpperPoint;
+@synthesize tableViewRecognizer;
#define ADDING_CELL @"Continue to pinch..."
#define COMMITING_CREATE_CELL_HEIGHT 60
@@ -29,7 +32,15 @@ @implementation ViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
- self.rows = [NSMutableArray arrayWithObjects:@"Try to pinch between this cell", @"And this cell to create a new one", nil];
+ self.rows = [NSMutableArray arrayWithObjects:
+ @"Try to pinch between any cell to create a new one",
+ @"example cell 1",
+ @"example cell 2",
+ @"example cell 3",
+ @"example cell 4",
+ @"example cell 5",
+ @"example cell 6",
+ nil];
}
return self;
}
@@ -38,84 +49,8 @@ - (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
- UIPinchGestureRecognizer *recognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchGestureRecognizer:)];
- [self.tableView addGestureRecognizer:recognizer];
-}
-
-#pragma mark Action
-
-- (void)pinchGestureRecognizer:(UIPinchGestureRecognizer *)recognizer {
-// NSLog(@"%d %f %f", [recognizer numberOfTouches], [recognizer velocity], [recognizer scale]);
- if (recognizer.state == UIGestureRecognizerStateEnded || [recognizer numberOfTouches] < 2) {
- if (self.addingIndexPath) {
- TransformableTableViewCell *cell = (TransformableTableViewCell *)[self.tableView cellForRowAtIndexPath:self.addingIndexPath];
- [self.tableView beginUpdates];
-
- if (cell.frame.size.height >= COMMITING_CREATE_CELL_HEIGHT) {
- [self.rows replaceObjectAtIndex:self.addingIndexPath.row withObject:@"Added!"];
- cell.textLabel.text = @"Added!";
- cell.finishedHeight = NORMAL_CELL_FINISHING_HEIGHT;
- } else {
- [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:self.addingIndexPath] withRowAnimation:UITableViewRowAnimationMiddle];
- [self.rows removeObject:ADDING_CELL];
- }
- self.addingIndexPath = nil;
- [self.tableView endUpdates];
-
- // Restore contentInset while touch ends
- [UIView beginAnimations:@"" context:nil];
- [UIView setAnimationBeginsFromCurrentState:YES];
- [UIView setAnimationDuration:0.5]; // Should not be less than the duration of row animation
- self.tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
- [UIView commitAnimations];
- }
- return;
- }
- CGPoint location1 = [recognizer locationOfTouch:0 inView:self.tableView];
- CGPoint location2 = [recognizer locationOfTouch:1 inView:self.tableView];
- CGPoint upperPoint = location1.y < location2.y ? location1 : location2;
-
- CGRect rect = (CGRect){location1, location2.x - location1.x, location2.y - location1.y};
-
- if (recognizer.state == UIGestureRecognizerStateBegan) {
- NSArray *indexPaths = [self.tableView indexPathsForRowsInRect:rect];
-
- NSIndexPath *firstIndexPath = [indexPaths objectAtIndex:0];
- NSIndexPath *lastIndexPath = [indexPaths lastObject];
- NSInteger midIndex = ((float)(firstIndexPath.row + lastIndexPath.row) / 2) + 0.5;
- NSIndexPath *midIndexPath = [NSIndexPath indexPathForRow:midIndex inSection:firstIndexPath.section];
-
- // Setting up properties for referencing later when touches changes
- self.startPinchingUpperPoint = upperPoint;
- self.addingIndexPath = midIndexPath;
-
- // Creating contentInset to fulfill the whole screen, so our tableview won't occasionaly
- // bounds back to the top while we don't have enough cells on the screen
- self.tableView.contentInset = UIEdgeInsetsMake(self.view.frame.size.height, 0, self.view.frame.size.height, 0);
-
- [self.tableView beginUpdates];
- [self.rows insertObject:ADDING_CELL atIndex:midIndex];
- [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:self.addingIndexPath] withRowAnimation:UITableViewRowAnimationMiddle];
- [self.tableView endUpdates];
-
- } else if (recognizer.state == UIGestureRecognizerStateChanged) {
-
- CGFloat diffRowHeight = CGRectGetHeight(rect) - CGRectGetHeight(rect)/[recognizer scale];
-
- NSLog(@"%f %f %f", CGRectGetHeight(rect), CGRectGetHeight(rect)/[recognizer scale], [recognizer scale]);
- if (self.addingRowHeight - diffRowHeight >= 1 || self.addingRowHeight - diffRowHeight <= -1) {
- self.addingRowHeight = diffRowHeight;
- [self.tableView reloadData];
- }
-
- // Scrolls tableview according to the upper touch point to mimic a realistic
- // dragging gesture
- CGPoint newUpperPoint = upperPoint;
- CGFloat diffOffsetY = self.startPinchingUpperPoint.y - newUpperPoint.y;
- CGPoint newOffset = (CGPoint){self.tableView.contentOffset.x, self.tableView.contentOffset.y+diffOffsetY};
- [self.tableView setContentOffset:newOffset animated:NO];
- }
+ self.tableViewRecognizer = [self.tableView enableGestureTableViewWithDelegate:self];
}
#pragma mark UITableViewDatasource
@@ -146,26 +81,34 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N
cell.detailTextLabel.text = @" ";
} else {
cell.finishedHeight = NORMAL_CELL_FINISHING_HEIGHT;
- cell.textLabel.text = [NSString stringWithFormat:@"%d %@", indexPath.row, (NSString *)object];
+ cell.textLabel.text = [NSString stringWithFormat:@"%@", (NSString *)object];
cell.detailTextLabel.text = @" ";
}
-
-
+
return cell;
}
#pragma mark UITableViewDelegate
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
- if ([indexPath isEqual:self.addingIndexPath]) {
- return MAX(1, self.addingRowHeight);
- }
return NORMAL_CELL_FINISHING_HEIGHT;
}
-- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
- [tableView beginUpdates];
- [tableView endUpdates];
+#pragma mark JTTableViewGestureRecognizer
+
+- (void)gestureRecognizer:(JTTableViewGestureRecognizer *)gestureRecognizer needsAddRowAtIndexPath:(NSIndexPath *)indexPath {
+ [self.rows insertObject:ADDING_CELL atIndex:indexPath.row];
+}
+
+- (void)gestureRecognizer:(JTTableViewGestureRecognizer *)gestureRecognizer needsCommitRowAtIndexPath:(NSIndexPath *)indexPath {
+ [self.rows replaceObjectAtIndex:indexPath.row withObject:@"Added!"];
+ TransformableTableViewCell *cell = (id)[gestureRecognizer.tableView cellForRowAtIndexPath:indexPath];
+ cell.finishedHeight = NORMAL_CELL_FINISHING_HEIGHT;
+ cell.textLabel.text = @"Just Added!";
+}
+
+- (void)gestureRecognizer:(JTTableViewGestureRecognizer *)gestureRecognizer needsDiscardRowAtIndexPath:(NSIndexPath *)indexPath {
+ [self.rows removeObjectAtIndex:indexPath.row];
}
@end

0 comments on commit 2c4c8bd

Please sign in to comment.
Something went wrong with that request. Please try again.