diff --git a/LICENSE b/LICENSE index d7b9ac1..31c3d1c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2011 Luke Redpath +Copyright (c) 2011–2012 Luke Redpath and Alexsander Akers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/LRSlidingTableViewCell.podspec b/LRSlidingTableViewCell.podspec new file mode 100644 index 0000000..8028bd2 --- /dev/null +++ b/LRSlidingTableViewCell.podspec @@ -0,0 +1,14 @@ +Pod::Spec.new do |s| + s.name = 'LRSlidingTableViewCell' + s.version = '1.0' + s.license = 'MIT' + s.summary = 'A simple implementation of sliding table cells, first seen in Tweetie for iPhone.' + s.homepage = 'https://github.com/pandamonia/LRSlidingTableViewCell' + s.author = { 'Alexsander Akers' => 'a2@pandamonia.us', + 'Luke Redpath' => 'luke@lukeredpath.co.uk' } + s.source = { :git => 'https://github.com/pandamonia/LRSlidingTableViewCell.git', :tag => 'v1.0' } + s.platform = :ios + s.source_files = 'SlidingTableCell/LRSlidingTableViewCell.{h,m}' + s.clean_paths = 'SlidingTableCell.xcodeproj/', 'SlidingTableCell/Sample/' + s.requires_arc = true +end diff --git a/SlidingTableCell.xcodeproj/project.pbxproj b/SlidingTableCell.xcodeproj/project.pbxproj index 7916dcb..3112bf6 100644 --- a/SlidingTableCell.xcodeproj/project.pbxproj +++ b/SlidingTableCell.xcodeproj/project.pbxproj @@ -16,7 +16,7 @@ A3D9A34A138EA2D100AFBA90 /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = A3D9A348138EA2D100AFBA90 /* MainWindow.xib */; }; A3D9A34D138EA2D100AFBA90 /* SlidingTableCellViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A3D9A34C138EA2D100AFBA90 /* SlidingTableCellViewController.m */; }; A3D9A350138EA2D100AFBA90 /* SlidingTableCellViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = A3D9A34E138EA2D100AFBA90 /* SlidingTableCellViewController.xib */; }; - A3D9A358138EA40900AFBA90 /* LRSlidingTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = A3D9A357138EA40900AFBA90 /* LRSlidingTableViewCell.m */; }; + A3D9A358138EA40900AFBA90 /* LRSlidingTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = A3D9A357138EA40900AFBA90 /* LRSlidingTableViewCell.m */; settings = {COMPILER_FLAGS = "-fobjc-arc"; }; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -43,9 +43,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - A3D9A337138EA2D100AFBA90 /* UIKit.framework in Frameworks */, - A3D9A339138EA2D100AFBA90 /* Foundation.framework in Frameworks */, A3D9A33B138EA2D100AFBA90 /* CoreGraphics.framework in Frameworks */, + A3D9A339138EA2D100AFBA90 /* Foundation.framework in Frameworks */, + A3D9A337138EA2D100AFBA90 /* UIKit.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -141,6 +141,7 @@ A3D9A329138EA2D100AFBA90 /* Project object */ = { isa = PBXProject; attributes = { + LastUpgradeCheck = 0420; ORGANIZATIONNAME = "LJR Software Limited"; }; buildConfigurationList = A3D9A32C138EA2D100AFBA90 /* Build configuration list for PBXProject "SlidingTableCell" */; @@ -227,7 +228,7 @@ GCC_VERSION = com.apple.compilers.llvmgcc42; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 4.3; + IPHONEOS_DEPLOYMENT_TARGET = 5.0; SDKROOT = iphoneos; }; name = Debug; @@ -241,7 +242,7 @@ GCC_VERSION = com.apple.compilers.llvmgcc42; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 4.3; + IPHONEOS_DEPLOYMENT_TARGET = 5.0; OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; SDKROOT = iphoneos; }; @@ -255,6 +256,7 @@ GCC_DYNAMIC_NO_PIC = NO; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "SlidingTableCell/Sample/SlidingTableCell-Prefix.pch"; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; INFOPLIST_FILE = "SlidingTableCell/Sample/SlidingTableCell-Info.plist"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; @@ -268,6 +270,7 @@ COPY_PHASE_STRIP = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "SlidingTableCell/Sample/SlidingTableCell-Prefix.pch"; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; INFOPLIST_FILE = "SlidingTableCell/Sample/SlidingTableCell-Info.plist"; PRODUCT_NAME = "$(TARGET_NAME)"; VALIDATE_PRODUCT = YES; diff --git a/SlidingTableCell/LRSlidingTableViewCell.h b/SlidingTableCell/LRSlidingTableViewCell.h index a33c296..9590d9d 100644 --- a/SlidingTableCell/LRSlidingTableViewCell.h +++ b/SlidingTableCell/LRSlidingTableViewCell.h @@ -1,8 +1,10 @@ // -// SlidingTableCell.h -// SlidingTableCell +// LRSlidingTableViewCell.h +// LRSlidingTableViewCell +// +// Created by Luke Redpath on 5/26/2011. +// Modified by Alexsander Akers on 1/20/2012. // -// Created by Luke Redpath on 26/05/2011. // Copyright 2011 LJR Software Limited. All rights reserved. // @@ -11,26 +13,39 @@ @class LRSlidingTableViewCell; typedef enum { - LRSlidingTableViewCellSwipeDirectionRight = 0, - LRSlidingTableViewCellSwipeDirectionLeft, - LRSlidingTableViewCellSwipeDirectionBoth, - LRSlidingTableViewCellSwipeDirectionNone, + LRSlidingTableViewCellSwipeDirectionNone = 0, + LRSlidingTableViewCellSwipeDirectionRight = UISwipeGestureRecognizerDirectionRight, + LRSlidingTableViewCellSwipeDirectionLeft = UISwipeGestureRecognizerDirectionLeft, + LRSlidingTableViewCellSwipeDirectionBoth = LRSlidingTableViewCellSwipeDirectionRight | LRSlidingTableViewCellSwipeDirectionLeft } LRSlidingTableViewCellSwipeDirection; @protocol LRSlidingTableViewCellDelegate -- (void)cellDidReceiveSwipe:(LRSlidingTableViewCell *)cell; + +- (void) slidingTableViewCellDidReceiveSwipe: (LRSlidingTableViewCell *) cell; + +@optional +- (BOOL) slidingTableViewCellShouldSwipe: (LRSlidingTableViewCell *) cell; + @end -@interface LRSlidingTableViewCell : UITableViewCell { - id delegate; +@interface LRSlidingTableViewCell : UITableViewCell +{ + __weak id _delegate; + BOOL _backgroundViewVisible; + LRSlidingTableViewCellSwipeDirection _swipeDirection; + UISwipeGestureRecognizerDirection _lastRecognizedDirection; } -@property (nonatomic, assign) id delegate; -@property (nonatomic, assign) LRSlidingTableViewCellSwipeDirection swipeDirection; -@property (nonatomic, retain) UISwipeGestureRecognizer *lastGestureRecognized; -/** Slides the content view out to the right to reveal the background view. */ -- (void)slideOutContentView; +@property (nonatomic) LRSlidingTableViewCellSwipeDirection swipeDirection; +@property (nonatomic, weak) id delegate; + +/** A Boolean indicator of whether the background view is visible. */ +- (BOOL) isBackgroundViewVisible; + +/** Slides the content view out to the right or left to reveal the background view. */ +- (void) slideOutContentView: (UISwipeGestureRecognizerDirection) direction; /** Slides the content view back in to cover the background view. */ -- (void)slideInContentView; +- (void) slideInContentView; + @end diff --git a/SlidingTableCell/LRSlidingTableViewCell.m b/SlidingTableCell/LRSlidingTableViewCell.m index 719c2e3..ff17d82 100644 --- a/SlidingTableCell/LRSlidingTableViewCell.m +++ b/SlidingTableCell/LRSlidingTableViewCell.m @@ -1,153 +1,197 @@ // -// SlidingTableCell.m -// SlidingTableCell +// LRSlidingTableViewCell.m +// LRSlidingTableViewCell +// +// Created by Luke Redpath on 5/26/2011. +// Modified by Alexsander Akers on 1/20/2012. // -// Created by Luke Redpath on 26/05/2011. // Copyright 2011 LJR Software Limited. All rights reserved. // #import "LRSlidingTableViewCell.h" @interface LRSlidingTableViewCell () -- (void)addSwipeGestureRecognizer:(UISwipeGestureRecognizerDirection)direction; + +@property (nonatomic) UISwipeGestureRecognizerDirection lastRecognizedDirection; + +- (void) addSwipeGestureRecognizer: (UISwipeGestureRecognizerDirection) direction; + @end @implementation LRSlidingTableViewCell -@synthesize delegate; -@synthesize swipeDirection; -@synthesize lastGestureRecognized; +@synthesize delegate = _delegate; +@synthesize swipeDirection = _swipeDirection; +@synthesize lastRecognizedDirection = _lastRecognizedDirection; -- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier +- (BOOL) isBackgroundViewVisible { - if ((self = [super initWithStyle:style reuseIdentifier:reuseIdentifier])) { - - self.swipeDirection = LRSlidingTableViewCellSwipeDirectionRight; - - /** Add a default empty background view to make it clear that it's all working */ - UIView *defaultBackgroundView = [[UIView alloc] initWithFrame:self.contentView.frame]; - defaultBackgroundView.backgroundColor = [UIColor darkGrayColor]; - self.backgroundView = defaultBackgroundView; - [defaultBackgroundView release]; - } - - return self; + return _backgroundViewVisible; } -- (void)dealloc +- (id) initWithStyle: (UITableViewCellStyle) style reuseIdentifier: (NSString *) reuseIdentifier { - [lastGestureRecognized release]; - [super dealloc]; + if ((self = [super initWithStyle:style reuseIdentifier:reuseIdentifier])) + { + self.swipeDirection = LRSlidingTableViewCellSwipeDirectionRight; + self.lastRecognizedDirection = UISwipeGestureRecognizerDirectionRight; + + /** Add a default empty background view to make it clear that it's all working */ + UIView *defaultBackgroundView = [[UIView alloc] initWithFrame: self.contentView.frame]; + defaultBackgroundView.backgroundColor = [UIColor darkGrayColor]; + self.backgroundView = defaultBackgroundView; + } + + return self; } - -- (void)handleSwipe:(UISwipeGestureRecognizer *)gesture +- (id) initWithCoder: (NSCoder *) decoder { - [self setLastGestureRecognized:gesture]; - [self slideOutContentView]; - [self.delegate cellDidReceiveSwipe:self]; + if ((self = [super initWithCoder: decoder])) + { + if (!self.swipeDirection) self.swipeDirection = LRSlidingTableViewCellSwipeDirectionRight; + if (!self.lastRecognizedDirection) self.lastRecognizedDirection = UISwipeGestureRecognizerDirectionRight; + } + + return self; } -- (void)setSwipeDirection:(LRSlidingTableViewCellSwipeDirection)direction +- (void) addSwipeGestureRecognizer: (UISwipeGestureRecognizerDirection) direction; { - swipeDirection = direction; - - NSArray *existingGestures = [self gestureRecognizers]; - for (UIGestureRecognizer *gesture in existingGestures) { - [self removeGestureRecognizer:gesture]; - } - - switch (swipeDirection) { - case LRSlidingTableViewCellSwipeDirectionLeft: - [self addSwipeGestureRecognizer:UISwipeGestureRecognizerDirectionLeft]; - break; - case LRSlidingTableViewCellSwipeDirectionRight: - [self addSwipeGestureRecognizer:UISwipeGestureRecognizerDirectionRight]; - break; - case LRSlidingTableViewCellSwipeDirectionBoth: - [self addSwipeGestureRecognizer:UISwipeGestureRecognizerDirectionLeft]; - [self addSwipeGestureRecognizer:UISwipeGestureRecognizerDirectionRight]; - default: - break; - } + UISwipeGestureRecognizer *swipeGesture = [[UISwipeGestureRecognizer alloc] initWithTarget: self action: @selector(handleSwipe:)]; + swipeGesture.direction = direction; + + [self addGestureRecognizer: swipeGesture]; } - -- (void)addSwipeGestureRecognizer:(UISwipeGestureRecognizerDirection)direction; +- (void) handleSwipe: (UISwipeGestureRecognizer *) gesture { - UISwipeGestureRecognizer *swipeGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipe:)]; - swipeGesture.direction = direction; - [self addGestureRecognizer:swipeGesture]; - [swipeGesture release]; + if (_backgroundViewVisible) + return; + + BOOL canSwipe = YES; + if (self.delegate && [self.delegate respondsToSelector: @selector(slidingTableViewCellShouldSwipe:)]) + canSwipe = [self.delegate slidingTableViewCellShouldSwipe: self]; + + if (!canSwipe) + return; + + [self slideOutContentView: gesture.direction]; +} +- (void) layoutSubviews +{ + [super layoutSubviews]; + + self.contentView.frame = self.bounds; +} +- (void) setSwipeDirection: (LRSlidingTableViewCellSwipeDirection) direction +{ + if (_swipeDirection == direction) + return; + + _swipeDirection = direction; + + NSArray *existingGestures = [self gestureRecognizers]; + [existingGestures enumerateObjectsUsingBlock: ^(UIGestureRecognizer *gesture, NSUInteger idx, BOOL *stop) { + [self removeGestureRecognizer: gesture]; + }]; + + switch (_swipeDirection) + { + case LRSlidingTableViewCellSwipeDirectionLeft: + [self addSwipeGestureRecognizer: UISwipeGestureRecognizerDirectionLeft]; + break; + + case LRSlidingTableViewCellSwipeDirectionRight: + [self addSwipeGestureRecognizer: UISwipeGestureRecognizerDirectionRight]; + break; + + case LRSlidingTableViewCellSwipeDirectionBoth: + [self addSwipeGestureRecognizer: UISwipeGestureRecognizerDirectionLeft]; + [self addSwipeGestureRecognizer: UISwipeGestureRecognizerDirectionRight]; + break; + + default: + break; + } } - #pragma mark Sliding content view #define kBOUNCE_DISTANCE 20.0 +void LR_offsetView(UIView *view, CGFloat offsetX, CGFloat offsetY); void LR_offsetView(UIView *view, CGFloat offsetX, CGFloat offsetY) { - view.frame = CGRectOffset(view.frame, offsetX, offsetY); + view.frame = CGRectOffset(view.frame, offsetX, offsetY); } -- (void)slideOutContentView; +- (void) slideInContentView { - CGFloat offsetX; - - switch (self.lastGestureRecognized.direction) { - case UISwipeGestureRecognizerDirectionLeft: - offsetX = -self.contentView.frame.size.width; - break; - case UISwipeGestureRecognizerDirectionRight: - offsetX = self.contentView.frame.size.width; - break; - default: - @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Unhandled gesture direction" userInfo:[NSDictionary dictionaryWithObject:self.lastGestureRecognized forKey:@"lastGestureRecognized"]]; - break; - } - - [UIView animateWithDuration:0.2 - delay:0 - options:UIViewAnimationOptionCurveEaseOut - animations:^{ LR_offsetView(self.contentView, offsetX, 0); } - completion:NULL]; + if (!_backgroundViewVisible) + return; + + CGFloat offsetX, bounceDistance; + + switch (self.lastRecognizedDirection) + { + case UISwipeGestureRecognizerDirectionLeft: + offsetX = self.contentView.frame.size.width; + bounceDistance = -kBOUNCE_DISTANCE; + break; + + case UISwipeGestureRecognizerDirectionRight: + offsetX = -self.contentView.frame.size.width; + bounceDistance = kBOUNCE_DISTANCE; + break; + + default: + @throw [NSException exceptionWithName: NSInternalInconsistencyException reason: @"Unhandled gesture direction" userInfo: [NSDictionary dictionaryWithObject: [NSNumber numberWithInt: self.lastRecognizedDirection] forKey: @"lastRecognizedDirection"]]; + break; + } + + [UIView animateWithDuration: 0.1 delay: 0 options: (UIViewAnimationOptionCurveEaseOut | UIViewAnimationOptionAllowUserInteraction) animations: ^{ + LR_offsetView(self.contentView, offsetX, 0); + } completion: ^(BOOL finished) { + [UIView animateWithDuration: 0.1 delay: 0 options: UIViewAnimationCurveLinear animations: ^{ + LR_offsetView(self.contentView, bounceDistance, 0); + } completion: ^(BOOL finished) { + [UIView animateWithDuration: 0.1 delay: 0 options: UIViewAnimationCurveLinear animations: ^{ + LR_offsetView(self.contentView, -bounceDistance, 0); + } completion: ^(BOOL finished) { + _backgroundViewVisible = NO; + }]; + }]; + }]; } - -- (void)slideInContentView; +- (void) slideOutContentView: (UISwipeGestureRecognizerDirection) direction { - CGFloat offsetX, bounceDistance; - - switch (self.lastGestureRecognized.direction) { - case UISwipeGestureRecognizerDirectionLeft: - offsetX = self.contentView.frame.size.width; - bounceDistance = -kBOUNCE_DISTANCE; - break; - case UISwipeGestureRecognizerDirectionRight: - offsetX = -self.contentView.frame.size.width; - bounceDistance = kBOUNCE_DISTANCE; - break; - default: - @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Unhandled gesture direction" userInfo:[NSDictionary dictionaryWithObject:self.lastGestureRecognized forKey:@"lastGestureRecognized"]]; - break; - } - - [UIView animateWithDuration:0.1 - delay:0 - options:UIViewAnimationOptionCurveEaseOut|UIViewAnimationOptionAllowUserInteraction - animations:^{ LR_offsetView(self.contentView, offsetX, 0); } - completion:^(BOOL f) { - - [UIView animateWithDuration:0.1 delay:0 - options:UIViewAnimationCurveLinear - animations:^{ LR_offsetView(self.contentView, bounceDistance, 0); } - completion:^(BOOL f) { - - [UIView animateWithDuration:0.1 delay:0 - options:UIViewAnimationCurveLinear - animations:^{ LR_offsetView(self.contentView, -bounceDistance, 0); } - completion:NULL]; - } - ]; - }]; + if (_backgroundViewVisible) + return; + + self.lastRecognizedDirection = direction; + + CGFloat offsetX; + + switch (direction) + { + case UISwipeGestureRecognizerDirectionLeft: + offsetX = -self.contentView.frame.size.width; + break; + + case UISwipeGestureRecognizerDirectionRight: + offsetX = self.contentView.frame.size.width; + break; + + default: + @throw [NSException exceptionWithName: NSInternalInconsistencyException reason: @"Unhandled gesture direction" userInfo: [NSDictionary dictionaryWithObject: [NSNumber numberWithInt: self.lastRecognizedDirection] forKey: @"lastRecognizedDirection"]]; + break; + } + + [UIView animateWithDuration: 0.2 delay: 0 options: UIViewAnimationOptionCurveEaseOut animations: ^{ + LR_offsetView(self.contentView, offsetX, 0); + } completion: ^(BOOL finished) { + _backgroundViewVisible = YES; + [self.delegate slidingTableViewCellDidReceiveSwipe: self]; + }]; } @end diff --git a/SlidingTableCell/Sample/SlidingTableCellViewController.m b/SlidingTableCell/Sample/SlidingTableCellViewController.m index 78b4c37..2bd4860 100644 --- a/SlidingTableCell/Sample/SlidingTableCellViewController.m +++ b/SlidingTableCell/Sample/SlidingTableCellViewController.m @@ -75,7 +75,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N * This allows us to slide the cell's content back in again if the user * starts dragging the table view or swipes a different cell. */ -- (void)cellDidReceiveSwipe:(LRSlidingTableViewCell *)cell +- (void)slidingTableViewCellDidReceiveSwipe:(LRSlidingTableViewCell *)cell { self.currentlyActiveSlidingCell = cell; }