diff --git a/sample/gesture_table/Rakefile b/sample/gesture_table/Rakefile new file mode 100644 index 00000000..1a4a253d --- /dev/null +++ b/sample/gesture_table/Rakefile @@ -0,0 +1,8 @@ +$:.unshift('../../lib') +require 'motion/project' + +Motion::Project::App.setup do |app| + # Use `rake config' to see complete project settings. + app.name = 'Gesture Table' + app.frameworks += ['QuartzCore'] +end diff --git a/sample/gesture_table/app/UIColor_extensions.rb b/sample/gesture_table/app/UIColor_extensions.rb new file mode 100644 index 00000000..f375f1dc --- /dev/null +++ b/sample/gesture_table/app/UIColor_extensions.rb @@ -0,0 +1,32 @@ +class UIColor + def colorWithBrightness(brightnessComponent) + hue = Pointer.new(:float) + saturation = Pointer.new(:float) + brightness = Pointer.new(:float) + red = Pointer.new(:float) + green = Pointer.new(:float) + blue = Pointer.new(:float) + white = Pointer.new(:float) + alpha = Pointer.new(:float) + + if getHue(hue, saturation: saturation, brightness: brightness, alpha: alpha) + UIColor.colorWithHue(hue[0], saturation: saturation[0], brightness: brightness[0] * brightnessComponent, alpha: alpha[0]) + elsif getRed(red, green: green, blue: blue, alpha: alpha) + UIColor.colorWithRed(red[0] * brightnessComponent, green: green[0] * brightnessComponent, blue: blue[0] * brightnessComponent, alpha: alpha[0]) + elsif getWhite(white, alpha: alpha) + UIColor.colorWithWhite(white[0] * brightnessComponent, alpha: alpha[0]) + end + end + + def colorWithHueOffset(hueOffset) + hue = Pointer.new(:float) + saturation = Pointer.new(:float) + brightness = Pointer.new(:float) + alpha = Pointer.new(:float) + + if getHue(hue, saturation: saturation, brightness: brightness, alpha: alpha) + newHue = (hue[0] + hueOffset) % 1 + UIColor.colorWithHue(newHue, saturation: saturation[0], brightness: brightness[0], alpha: alpha[0]) + end + end +end diff --git a/sample/gesture_table/app/UITableView_extensions.rb b/sample/gesture_table/app/UITableView_extensions.rb new file mode 100644 index 00000000..9ec27a17 --- /dev/null +++ b/sample/gesture_table/app/UITableView_extensions.rb @@ -0,0 +1,7 @@ +class UITableView + def reloadVisibleRowsExceptIndexPath(indexPath) + visibleRows = indexPathsForVisibleRows.mutableCopy + visibleRows.removeObject(indexPath) + reloadRowsAtIndexPaths(visibleRows, withRowAnimation: UITableViewRowAnimationNone) + end +end diff --git a/sample/gesture_table/app/app_delegate.rb b/sample/gesture_table/app/app_delegate.rb new file mode 100644 index 00000000..ec643749 --- /dev/null +++ b/sample/gesture_table/app/app_delegate.rb @@ -0,0 +1,9 @@ +class AppDelegate + def application(application, didFinishLaunchingWithOptions:launchOptions) + application.setStatusBarStyle(UIStatusBarStyleBlackOpaque) + @window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds) + @window.rootViewController = UINavigationController.alloc.initWithRootViewController(ViewController.new) + @window.makeKeyAndVisible + true + end +end diff --git a/sample/gesture_table/app/gesture_recognizer.rb b/sample/gesture_table/app/gesture_recognizer.rb new file mode 100644 index 00000000..7d6944a1 --- /dev/null +++ b/sample/gesture_table/app/gesture_recognizer.rb @@ -0,0 +1,376 @@ +class GestureRecognizer + CommitEditingRowDefaultRowHeight = 80 + RowAnimationDuration = 0.25 + CellSnapshotTag = 100000 + +# attr_accessor :delegate, :tableViewDelegate, :tableView, :addingRowHeight, :addingIndexPath, +# :addingCellState, :startPinchingUpperPoint, :panRecognizer, +# :longPressRecognizer, :state, :cellSnapshot, :scrollingRate, :movingTimer + + def initWithTableView(tableView, delegate:delegate) + if init + @tableView = tableView + @delegate= delegate + @state = :none + @tableViewDelegate = tableView.delegate + tableView.delegate = self + + @pinchRecognizer = UIPinchGestureRecognizer.alloc.initWithTarget(self, action: :"pinchGestureRecognizer:") + @panRecognizer = UIPanGestureRecognizer.alloc.initWithTarget(self, action: :"panGestureRecognizer:") + @longPressRecognizer = UILongPressGestureRecognizer.alloc.initWithTarget(self, action: :"longPressGestureRecognizer:") + tableView.gestureRecognizers += [@pinchRecognizer, @panRecognizer, @longPressRecognizer] + @pinchRecognizer.delegate = @panRecognizer.delegate = @longPressRecognizer.delegate = self + end + self + end + + def scrollTable + location = @longPressRecognizer.locationInView(@tableView) + + currentOffset = @tableView.contentOffset + @scrollingRate ||= 0 + newOffset = CGPointMake(currentOffset.x, currentOffset.y + @scrollingRate) + if newOffset.y < 0 + newOffset.y = 0 + elsif @tableView.contentSize.height < @tableView.frame.size.height + newOffset = currentOffset + elsif newOffset.y > @tableView.contentSize.height - @tableView.frame.size.height + newOffset.y = @tableView.contentSize.height - @tableView.frame.size.height + end + @tableView.setContentOffset(newOffset) + + if location.y >= 0 + cellSnapshotView = @tableView.viewWithTag(CellSnapshotTag) + cellSnapshotView.center = CGPointMake(@tableView.center.x, location.y) + end + + updateAddingIndexPathForCurrentLocation + end + + def updateAddingIndexPathForCurrentLocation + indexPath = indexPathFromRecognizer(@longPressRecognizer) + if indexPath != @addingIndexPath + @tableView.beginUpdates + @tableView.deleteRowsAtIndexPaths([@addingIndexPath], withRowAnimation: UITableViewRowAnimationNone) + @tableView.insertRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimationNone) + @delegate.gestureRecognizer(self, needsMoveRowAtIndexPath: @addingIndexPath, toIndexPath: indexPath) + @tableView.endUpdates + @addingIndexPath = indexPath + end + end + + def commitOrDiscardCell + cell = @tableView.cellForRowAtIndexPath(@addingIndexPath) + + @tableView.beginUpdates + + commitingCellHeight = @tableView.rowHeight + if @delegate.respond_to? :"gestureRecognizer:heightForCommittingRowAtIndexPath:" + commitingCellHeight = @delegate.gestureRecognizer(self, heightForCommittingRowAtIndexPath: @addingIndexPath) + end + + if cell.frame.size.height >= commitingCellHeight + @delegate.gestureRecognizer(self, needsCommitRowAtIndexPath: @addingIndexPath) + else + @delegate.gestureRecognizer(self, needsDiscardRowAtIndexPath: @addingIndexPath) + @tableView.deleteRowsAtIndexPaths([@addingIndexPath], withRowAnimation: UITableViewRowAnimationMiddle) + end + + @tableView.performSelector(:"reloadVisibleRowsExceptIndexPath:", withObject: @addingIndexPath, afterDelay: RowAnimationDuration) + @addingIndexPath = nil + + @tableView.endUpdates + + UIView.beginAnimations('', context: nil) + UIView.setAnimationBeginsFromCurrentState(true) + UIView.setAnimationDuration(0.5) + @tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0) + UIView.commitAnimations + + @state = :none + end + + def pinchGestureRecognizer(recognizer) + if recognizer.state == UIGestureRecognizerStateEnded || recognizer.numberOfTouches < 2 + self.commitOrDiscardCell if @addingIndexPath + return + end + + location1 = recognizer.locationOfTouch(0, inView: @tableView) + location2 = recognizer.locationOfTouch(1, inView: @tableView) + upperPoint = location1.y < location2.y ? location1 : location2 + + rect = CGRectMake(*location1, location2.x - location1.x, location2.y - location1.y) + + if recognizer.state == UIGestureRecognizerStateBegan + @state = :pinching + indexPaths = @tableView.indexPathsForRowsInRect(rect) + unless indexPaths.empty? + midIndex = ((indexPaths.first.row + indexPaths.last.row) / 2.0) + 0.5 + midIndexPath = NSIndexPath.indexPathForRow(midIndex, inSection: indexPaths.first.section) + + @startPinchingUpperPoint = upperPoint + + if @delegate.respond_to? :"gestureRecognizer:willCreateCellAtIndexPath:" + @addingIndexPath = @delegate.gestureRecognizer(self, willCreateCellAtIndexPath: midIndexPath) + else + @addingIndexPath = midIndexPath + end + + @tableView.contentInset = UIEdgeInsetsMake(@tableView.frame.size.height, 0, @tableView.frame.size.height, 0) + + if @addingIndexPath + @tableView.beginUpdates + @delegate.gestureRecognizer(self, needsAddRowAtIndexPath: @addingIndexPath) + @tableView.insertRowsAtIndexPaths([@addingIndexPath], withRowAnimation: UITableViewRowAnimationMiddle) + @tableView.endUpdates + end + end + elsif recognizer.state == UIGestureRecognizerStateChanged + diffRowHeight = CGRectGetHeight(rect) - CGRectGetHeight(rect)/recognizer.scale + if @addingRowHeight - diffRowHeight >= 1 || @addingRowHeight - diffRowHeight <= -1 + @addingRowHeight = diffRowHeight + @tableView.reloadData + end + + newUpperPoint = upperPoint + diffOffsetY = @startPinchingUpperPoint.y - newUpperPoint.y + newOffset = CGPointMake(@tableView.contentOffset.x, @tableView.contentOffset.y + diffOffsetY) + @tableView.setContentOffset(newOffset, animated: false) + end + end + + def panGestureRecognizer(recognizer) + if (recognizer.state == UIGestureRecognizerStateBegan || + recognizer.state == UIGestureRecognizerStateChanged) && + recognizer.numberOfTouches > 0 + + location1 = recognizer.locationOfTouch(0, inView: @tableView) + indexPath = @addingIndexPath + unless indexPath + indexPath = @tableView.indexPathForRowAtPoint(location1) + @addingIndexPath = indexPath + end + + @state = :panning + cell = @tableView.cellForRowAtIndexPath(indexPath) + translation = recognizer.translationInView(@tableView) + cell.contentView.frame = CGRectOffset(cell.contentView.bounds, translation.x, 0) + + if @delegate.respond_to? :"gestureRecognizer:didChangeContentViewTranslation:forRowAtIndexPath:" + @delegate.gestureRecognizer(self, didChangeContentViewTranslation: translation, forRowAtIndexPath: indexPath) + end + + commitEditingLength = CommitEditingRowDefaultRowHeight + if @delegate.respond_to? :"gestureRecognizer:lengthForCommitEditingRowAtIndexPath:" + commitEditingLength = @delegate.gestureRecognizer(self, lengthForCommitEditingRowAtIndexPath: indexPath) + end + if translation.x.abs >= commitEditingLength + if @addingCellState == :middle + @addingCellState = translation.x > 0 ? :right : :left + end + else + if @addingCellState != :middle + @addingCellState = :middle + end + end + + if @delegate.respond_to? :"gestureRecognizer:didEnterEditingState:forRowAtIndexPath:" + @delegate.gestureRecognizer(self, didEnterEditingState: @addingCellState, forRowAtIndexPath: indexPath) + end + elsif recognizer.state == UIGestureRecognizerStateEnded + cell = @tableView.cellForRowAtIndexPath(@addingIndexPath) + translation = recognizer.translationInView(@tableView) + + commitEditingLength = CommitEditingRowDefaultRowHeight + if @delegate.respond_to? :"gestureRecognizer:lengthForCommitEditingRowAtIndexPath:" + commitEditingLength = @delegate.gestureRecognizer(self, lengthForCommitEditingRowAtIndexPath: @addingIndexPath) + end + if translation.x.abs >= commitEditingLength + if @delegate.respond_to? :"gestureRecognizer:commitEditingState:forRowAtIndexPath:" + @delegate.gestureRecognizer(self, commitEditingState: @addingCellState, forRowAtIndexPath: @addingIndexPath) + end + else + UIView.beginAnimations('', context: nil) + cell.contentView.frame = cell.contentView.bounds + UIView.commitAnimations + end + + @addingCellState = :middle + @addingIndexPath = nil + @state = :none + end + end + + def longPressGestureRecognizer(recognizer) + location = recognizer.locationInView(@tableView) + indexPath = indexPathFromRecognizer(recognizer) + + case recognizer.state + when UIGestureRecognizerStateBegan + @state = :moving + + cell = @tableView.cellForRowAtIndexPath(indexPath) + UIGraphicsBeginImageContextWithOptions(cell.bounds.size, false, 0) + cell.layer.renderInContext(UIGraphicsGetCurrentContext()) + cellImage = UIGraphicsGetImageFromCurrentImageContext() + UIGraphicsEndImageContext() + + snapShotView = @tableView.viewWithTag(CellSnapshotTag) + unless snapShotView + snapShotView = UIImageView.alloc.initWithImage(cellImage) + snapShotView.tag = CellSnapshotTag + @tableView.addSubview(snapShotView) + rect = @tableView.rectForRowAtIndexPath(indexPath) + snapShotView.frame = CGRectOffset(snapShotView.bounds, rect.origin.x, rect.origin.y) + end + + UIView.beginAnimations('zoomCell', context: nil) + snapShotView.transform = CGAffineTransformMakeScale(1.1, 1.1) + snapShotView.center = CGPointMake(@tableView.center.x, location.y) + UIView.commitAnimations + + @tableView.beginUpdates + @tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimationNone) + @tableView.insertRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimationNone) + @delegate.gestureRecognizer(self, needsCreatePlaceholderForRowAtIndexPath: indexPath) + @addingIndexPath = indexPath + @tableView.endUpdates + + @movingTimer = NSTimer.timerWithTimeInterval((1/8.0), target: self, selector: :scrollTable, userInfo: nil, repeats: true) + NSRunLoop.mainRunLoop.addTimer(@movingTimer, forMode: NSDefaultRunLoopMode) + + when UIGestureRecognizerStateEnded + snapShotView = @tableView.viewWithTag(CellSnapshotTag) + indexPath = @addingIndexPath + + @movingTimer.invalidate + @movingTimer = nil + @scrollingRate = 0 + + UIView.animateWithDuration(RowAnimationDuration, + animations: -> do + rect = @tableView.rectForRowAtIndexPath(indexPath) + snapShotView.transform = CGAffineTransformIdentity + snapShotView.frame = CGRectOffset(snapShotView.bounds, rect.origin.x, rect.origin.y) + end, + completion: ->(finished) do + snapShotView.removeFromSuperview + + @tableView.beginUpdates + @tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimationNone) + @tableView.insertRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimationNone) + @delegate.gestureRecognizer(self, needsReplacePlaceholderForRowAtIndexPath: indexPath) + @tableView.endUpdates + + @tableView.reloadVisibleRowsExceptIndexPath(indexPath) + @cellSnapshot = nil + @addingIndexPath = nil + @state = :none + end) + + when UIGestureRecognizerStateChanged + snapShotView = @tableView.viewWithTag(CellSnapshotTag) + snapShotView.center = CGPointMake(@tableView.center.x, location.y) + + rect = @tableView.bounds + location = @longPressRecognizer.locationInView(@tableView) + location.y -= @tableView.contentOffset.y + + self.updateAddingIndexPathForCurrentLocation + + topDropZoneHeight = bottomDropZoneHeight = @tableView.bounds.size.height / 6.0 + bottomDiff = location.y - (rect.size.height - bottomDropZoneHeight) + if bottomDiff > 0 + @scrollingRate = bottomDiff / (bottomDropZoneHeight / 1) + elsif location.y <= topDropZoneHeight + @scrollingRate = -(topDropZoneHeight - [location.y, 0].max) / bottomDropZoneHeight + else + @scrollingRate = 0 + end + end + end + + def gestureRecognizerShouldBegin(gestureRecognizer) + indexPath = indexPathFromRecognizer(gestureRecognizer) + + case gestureRecognizer + when @panRecognizer + point = gestureRecognizer.translationInView(@tableView) + if point.y.abs > point.x.abs || indexPath.nil? + false + elsif indexPath + @delegate.gestureRecognizer(self, canEditRowAtIndexPath: indexPath) + end + when @longPressRecognizer + if indexPath + @delegate.gestureRecognizer(self, canMoveRowAtIndexPath: indexPath) + else + false + end + else + true + end + end + + def tableView(aTableView, heightForRowAtIndexPath: indexPath) + if indexPath == @addingIndexPath && (@state == :pinching || @state == :dragging) + [1, @addingRowHeight || 0].max + else + @tableViewDelegate.tableView(aTableView, heightForRowAtIndexPath: indexPath) + end + end + + def scrollViewDidScroll(scrollView) + if scrollView.contentOffset.y < 0 + if @addingIndexPath.nil? && @state == :none && !scrollView.isDecelerating + @state = :dragging + @addingIndexPath = NSIndexPath.indexPathForRow(0, inSection: 0) + if @delegate.respond_to? :"gestureRecognizer:willCreateCellAtIndexPath:" + @addingIndexPath = @delegate.gestureRecognizer(self, willCreateCellAtIndexPath: @addingIndexPath) + end + + @tableView.beginUpdates + @delegate.gestureRecognizer(self, needsAddRowAtIndexPath: @addingIndexPath) + @tableView.insertRowsAtIndexPaths([@addingIndexPath], withRowAnimation: UITableViewRowAnimationNone) + @addingRowHeight = scrollView.contentOffset.y.abs + @tableView.endUpdates + end + end + + if @state == :dragging + @addingRowHeight += scrollView.contentOffset.y * -1 + @tableView.reloadData + scrollView.setContentOffset(CGPointZero) + end + end + + def scrollViewDidEndDragging(scrollView, willDecelerate: decelerate) + if @state == :dragging + @state = :none + self.commitOrDiscardCell + end + end + + def forwardInvocation(anInvocation) + anInvocation.invokeWithTarget(@tableViewDelegate) + end + + def methodSignatureForSelector(aSelector) + @tableViewDelegate.methodSignatureForSelector(aSelector) + end + + def respondsToSelector(aSelector) + if @tableViewDelegate.respondsToSelector(aSelector) + true + end + self.class.instancesRespondToSelector(aSelector) + end + + private + def indexPathFromRecognizer(recognizer) + location = recognizer.locationInView(@tableView) + @tableView.indexPathForRowAtPoint(location) + end +end + diff --git a/sample/gesture_table/app/transformable_cells.rb b/sample/gesture_table/app/transformable_cells.rb new file mode 100644 index 00000000..9f658863 --- /dev/null +++ b/sample/gesture_table/app/transformable_cells.rb @@ -0,0 +1,92 @@ +class TransformableTableViewCell < UITableViewCell + attr_accessor :finishedHeight, :tintColor + + def self.transformableTableViewCellWithStyle(style, reuseIdentifier: reuseIdentifier) + case style + when :pullDown + PullDownTableViewCell.alloc.initWithStyle(UITableViewCellStyleDefault, reuseIdentifier: reuseIdentifier) + when :unfolding + UnfoldingTableViewCell.alloc.initWithStyle(UITableViewCellStyleSubtitle, reuseIdentifier: reuseIdentifier) + else + raise ArgumentError, "Style must be :pullDown or :unfolding" + end + end +end + +class UnfoldingTableViewCell < TransformableTableViewCell + def initWithStyle(style, reuseIdentifier: reuseIdentifier) + if super + transform = CATransform3DIdentity + transform.m34 = -1 / 500.to_f + contentView.layer.setSublayerTransform(transform) + + textLabel.layer.anchorPoint = CGPointMake(0.5, 0.0) + detailTextLabel.layer.anchorPoint = CGPointMake(0.5, 1.0) + + textLabel.autoresizingMask = UIViewAutoresizingFlexibleHeight + detailTextLabel.autoresizingMask = UIViewAutoresizingFlexibleHeight + + self.selectionStyle = UITableViewCellSelectionStyleNone + self.tintColor = UIColor.whiteColor + end + self + end + + def layoutSubviews + super + + fraction = self.frame.size.height / @finishedHeight.to_f + fraction = [[1, fraction].min, 0].max + + angle = (Math::PI / 2) - Math.asin(fraction) + transform = CATransform3DMakeRotation(angle, -1, 0, 0) + textLabel.layer.setTransform(transform) + detailTextLabel.layer.setTransform(CATransform3DMakeRotation(angle, 1, 0, 0)) + + textLabel.backgroundColor = @tintColor.colorWithBrightness(0.3 + 0.7*fraction) + detailTextLabel.backgroundColor = @tintColor.colorWithBrightness(0.5 + 0.5*fraction) + + contentViewSize = contentView.frame.size + contentViewMidY = contentViewSize.height / 2.0 + labelHeight = @finishedHeight / 2.0 + + textLabel.frame = [[0, contentViewMidY - (labelHeight * fraction)], [contentViewSize.width, labelHeight + 1]] + detailTextLabel.frame = [[0, contentViewMidY - (labelHeight * (1 - fraction))], [contentViewSize.width, labelHeight]] + end +end + +class PullDownTableViewCell < TransformableTableViewCell + def initWithStyle(style, reuseIdentifier: reuseIdentifier) + if super + transform = CATransform3DIdentity + transform.m34 = -1 / 500.to_f + contentView.layer.setSublayerTransform(transform) + + textLabel.layer.anchorPoint = CGPointMake(0.5, 1.0) + textLabel.autoresizingMask = UIViewAutoresizingFlexibleHeight + + self.selectionStyle = UITableViewCellSelectionStyleNone + + @tintColor = UIColor.whiteColor + end + self + end + + def layoutSubviews + super + + fraction = self.frame.size.height / @finishedHeight.to_f + fraction = [[1, fraction].min, 0].max + + angle = (Math::PI / 2) - Math.asin(fraction) + transform = CATransform3DMakeRotation(angle, 1, 0, 0) + textLabel.layer.setTransform(transform) + + textLabel.backgroundColor = @tintColor.colorWithBrightness(0.3 + 0.7*fraction) + + contentViewSize = self.contentView.frame.size + labelHeight = @finishedHeight + + self.textLabel.frame = [[0, contentViewSize.height - labelHeight], [contentViewSize.width, labelHeight]] + end +end diff --git a/sample/gesture_table/app/view_controller.rb b/sample/gesture_table/app/view_controller.rb new file mode 100644 index 00000000..5922199e --- /dev/null +++ b/sample/gesture_table/app/view_controller.rb @@ -0,0 +1,173 @@ +class ViewController < UITableViewController + AddingCell = 'Continue...' + DoneCell = 'Done' + DummyCell = 'Dummy' + CommittingCreateCellHeight = 60 + NormalCellFinishingHeight = 60 + + def loadView + self.tableView = UITableView.new + + @rows = ['Swipe to the right to complete', 'Swipe to left to delete', 'Drag down to create a new cell', 'Pinch two rows apart to create cell', 'Long hold to start reorder cell'] + @grabbedObject = nil + @tableViewRecognizer = GestureRecognizer.alloc.initWithTableView(self.tableView, delegate:self) + end + + def viewWillAppear(animated) + navigationController.setNavigationBarHidden(true, animated:false) + end + + def viewDidLoad + tableView.backgroundColor = UIColor.blackColor + tableView.separatorStyle = UITableViewCellSeparatorStyleNone + tableView.rowHeight = NormalCellFinishingHeight + end + + def numberOfSectionsInTableView(tableView) + 1 + end + + def tableView(tableView, numberOfRowsInSection: section) + @rows.count + end + + def tableView(tableView, heightForRowAtIndexPath: indexPath) + NormalCellFinishingHeight + end + + def tableView(tableView, cellForRowAtIndexPath: indexPath) + object = @rows[indexPath.row] + backgroundColor = backgroundColorForIndexPath(indexPath) + + if object == AddingCell + if indexPath.row == 0 + cellIdentifier = 'PullDownTableViewCell' + cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) + unless cell + cell = TransformableTableViewCell.transformableTableViewCellWithStyle(:pullDown, reuseIdentifier: cellIdentifier) + cell.textLabel.adjustsFontSizeToFitWidth = true + cell.textLabel.textColor = UIColor.whiteColor + cell.textLabel.textAlignment = UITextAlignmentCenter + end + + cell.tintColor = backgroundColor + cell.finishedHeight = CommittingCreateCellHeight + cell.textLabel.text = cell.frame.size.height > CommittingCreateCellHeight ? 'Release to create cell...' : 'Continue Pulling...' + cell.contentView.backgroundColor = UIColor.clearColor + else + cellIdentifier = 'UnfoldingTableViewCell' + cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) + unless cell + cell = TransformableTableViewCell.transformableTableViewCellWithStyle(:unfolding, reuseIdentifier: cellIdentifier) + cell.textLabel.adjustsFontSizeToFitWidth = true + cell.textLabel.textColor = UIColor.whiteColor + cell.textLabel.textAlignment = UITextAlignmentCenter + end + + cell.tintColor = backgroundColor + cell.finishedHeight = CommittingCreateCellHeight + cell.textLabel.text = cell.frame.size.height > CommittingCreateCellHeight ? 'Release to create cell...' : 'Continue Pinching...' + cell.contentView.backgroundColor = UIColor.clearColor + cell.detailTextLabel.text = ' ' + end + else + cellIdentifier = 'MyCell' + cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) + unless cell + cell = UITableViewCell.alloc.initWithStyle(UITableViewCellStyleDefault, reuseIdentifier: cellIdentifier) + cell.textLabel.adjustsFontSizeToFitWidth = true + cell.textLabel.backgroundColor = UIColor.clearColor + cell.selectionStyle = UITableViewCellSelectionStyleNone + end + + text = object.to_s + textColor = UIColor.whiteColor + if object == DoneCell + textColor = UIColor.grayColor + backgroundColor = UIColor.darkGrayColor + elsif object == DummyCell + text = '' + backgroundColor = UIColor.clearColor + end + + cell.textLabel.text = text + cell.textLabel.textColor = textColor + cell.contentView.backgroundColor = backgroundColor + end + + cell + end + + def gestureRecognizer(gestureRecognizer, needsAddRowAtIndexPath: indexPath) + @rows.insert(indexPath.row, AddingCell) + end + + def gestureRecognizer(gestureRecognizer, needsCommitRowAtIndexPath: indexPath) + @rows[indexPath.row] = 'Added!' + cell = gestureRecognizer.tableView.cellForRowAtIndexPath(indexPath) + cell.finishedHeight = NormalCellFinishingHeight + cell.textLabel.text = 'Just Added!' + end + + def gestureRecognizer(gestureRecognizer, needsDiscardRowAtIndexPath: indexPath) + @rows.delete_at(indexPath.row) + end + + def gestureRecognizer(gestureRecognizer, didEnterEditingState: state, forRowAtIndexPath: indexPath) + backgroundColor = case state + when :middle + backgroundColorForIndexPath(indexPath) + when :right + UIColor.greenColor + else + UIColor.darkGrayColor + end + + cell = tableView.cellForRowAtIndexPath(indexPath) + cell.contentView.backgroundColor = backgroundColor + cell.tintColor = backgroundColor if cell.kind_of? TransformableTableViewCell + end + + def gestureRecognizer(gestureRecognizer, canEditRowAtIndexPath: indexPath) + true + end + + def gestureRecognizer(gestureRecognizer, commitEditingState: state, forRowAtIndexPath: indexPath) + tableView.beginUpdates + case state + when :left + @rows.delete_at(indexPath.row) + tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimationLeft) + when :right + @rows[indexPath.row] = DoneCell + tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimationLeft) + end + tableView.endUpdates + + tableView.performSelector(:"reloadVisibleRowsExceptIndexPath:", withObject: indexPath, afterDelay: GestureRecognizer::RowAnimationDuration) + end + + def gestureRecognizer(gestureRecognizer, canMoveRowAtIndexPath: indexPath) + true + end + + def gestureRecognizer(gestureRecognizer, needsCreatePlaceholderForRowAtIndexPath: indexPath) + @grabbedObject = @rows[indexPath.row] + @rows[indexPath.row] = DummyCell + end + + def gestureRecognizer(gestureRecognizer, needsMoveRowAtIndexPath: sourceIndexPath, toIndexPath: destinationIndexPath) + object = @rows[sourceIndexPath.row] + @rows.delete_at(sourceIndexPath.row) + @rows.insert(destinationIndexPath.row, object) + end + + def gestureRecognizer(gestureRecognizer, needsReplacePlaceholderForRowAtIndexPath: indexPath) + @rows[indexPath.row] = @grabbedObject + @grabbedObject = nil + end + + def backgroundColorForIndexPath(indexPath) + UIColor.redColor.colorWithHueOffset(0.12 * indexPath.row / @rows.count) + end +end