From ea0a808e86c3f02642d239414773438083eace31 Mon Sep 17 00:00:00 2001 From: Pierre Bernard Date: Mon, 15 Oct 2012 18:12:54 +0200 Subject: [PATCH] Initial public release --- .../project.pbxproj | 328 ++++++++++ HHPanningTableViewCell/AppDelegate.h | 40 ++ HHPanningTableViewCell/AppDelegate.m | 73 +++ HHPanningTableViewCell/HHAppDelegate.h | 19 + HHPanningTableViewCell/HHAppDelegate.m | 52 ++ .../HHDirectionPanGestureRecognizer.h | 45 ++ .../HHDirectionPanGestureRecognizer.m | 109 ++++ HHPanningTableViewCell/HHInnerShadowView.h | 33 + HHPanningTableViewCell/HHInnerShadowView.m | 102 +++ .../HHPanningTableViewCell-Info.plist | 38 ++ .../HHPanningTableViewCell-Prefix.pch | 14 + .../HHPanningTableViewCell.h | 51 ++ .../HHPanningTableViewCell.m | 588 ++++++++++++++++++ .../HHTableViewController.h | 16 + .../HHTableViewController.m | 123 ++++ .../HHTableViewController.xib | 146 +++++ HHPanningTableViewCell/TableViewController.h | 36 ++ HHPanningTableViewCell/TableViewController.m | 145 +++++ .../TableViewController.xib | 132 ++++ HHPanningTableViewCell/dark_dotted.png | Bin 0 -> 108 bytes HHPanningTableViewCell/dark_dotted@2X.png | Bin 0 -> 3593 bytes .../en.lproj/InfoPlist.strings | 2 + HHPanningTableViewCell/innerShadow.png | Bin 0 -> 586 bytes HHPanningTableViewCell/main.m | 38 ++ 24 files changed, 2130 insertions(+) create mode 100644 HHPanningTableViewCell.xcodeproj/project.pbxproj create mode 100644 HHPanningTableViewCell/AppDelegate.h create mode 100644 HHPanningTableViewCell/AppDelegate.m create mode 100644 HHPanningTableViewCell/HHAppDelegate.h create mode 100644 HHPanningTableViewCell/HHAppDelegate.m create mode 100644 HHPanningTableViewCell/HHDirectionPanGestureRecognizer.h create mode 100644 HHPanningTableViewCell/HHDirectionPanGestureRecognizer.m create mode 100644 HHPanningTableViewCell/HHInnerShadowView.h create mode 100644 HHPanningTableViewCell/HHInnerShadowView.m create mode 100644 HHPanningTableViewCell/HHPanningTableViewCell-Info.plist create mode 100644 HHPanningTableViewCell/HHPanningTableViewCell-Prefix.pch create mode 100644 HHPanningTableViewCell/HHPanningTableViewCell.h create mode 100644 HHPanningTableViewCell/HHPanningTableViewCell.m create mode 100644 HHPanningTableViewCell/HHTableViewController.h create mode 100644 HHPanningTableViewCell/HHTableViewController.m create mode 100644 HHPanningTableViewCell/HHTableViewController.xib create mode 100644 HHPanningTableViewCell/TableViewController.h create mode 100644 HHPanningTableViewCell/TableViewController.m create mode 100644 HHPanningTableViewCell/TableViewController.xib create mode 100644 HHPanningTableViewCell/dark_dotted.png create mode 100644 HHPanningTableViewCell/dark_dotted@2X.png create mode 100644 HHPanningTableViewCell/en.lproj/InfoPlist.strings create mode 100644 HHPanningTableViewCell/innerShadow.png create mode 100644 HHPanningTableViewCell/main.m diff --git a/HHPanningTableViewCell.xcodeproj/project.pbxproj b/HHPanningTableViewCell.xcodeproj/project.pbxproj new file mode 100644 index 0000000..5bd8c18 --- /dev/null +++ b/HHPanningTableViewCell.xcodeproj/project.pbxproj @@ -0,0 +1,328 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 8F150F3715B1559D00EE1B9C /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8F150F3615B1559D00EE1B9C /* UIKit.framework */; }; + 8F150F3915B1559D00EE1B9C /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8F150F3815B1559D00EE1B9C /* Foundation.framework */; }; + 8F150F3B15B1559D00EE1B9C /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8F150F3A15B1559D00EE1B9C /* CoreGraphics.framework */; }; + 8F150F4115B1559D00EE1B9C /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8F150F3F15B1559D00EE1B9C /* InfoPlist.strings */; }; + 8F150F4315B1559D00EE1B9C /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 8F150F4215B1559D00EE1B9C /* main.m */; }; + 8F150F4715B1559D00EE1B9C /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 8F150F4615B1559D00EE1B9C /* AppDelegate.m */; }; + 8F150F5615B155D300EE1B9C /* TableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8F150F5415B155D300EE1B9C /* TableViewController.m */; }; + 8F150F5715B155D300EE1B9C /* TableViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 8F150F5515B155D300EE1B9C /* TableViewController.xib */; }; + 8F150F5A15B1586B00EE1B9C /* HHPanningTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 8F150F5915B1586A00EE1B9C /* HHPanningTableViewCell.m */; }; + 8F3F12BB15B56854002B8762 /* HHInnerShadowView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8F3F12BA15B56854002B8762 /* HHInnerShadowView.m */; }; + 8F6D1C1D15B3392900706C97 /* HHDirectionPanGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 8F6D1C1C15B3392900706C97 /* HHDirectionPanGestureRecognizer.m */; }; + 8F92F43F162C5F3B0066B3F8 /* dark_dotted.png in Resources */ = {isa = PBXBuildFile; fileRef = 8F92F43D162C5F3B0066B3F8 /* dark_dotted.png */; }; + 8F92F440162C5F3B0066B3F8 /* dark_dotted@2X.png in Resources */ = {isa = PBXBuildFile; fileRef = 8F92F43E162C5F3B0066B3F8 /* dark_dotted@2X.png */; }; + 8FC0367C15B4477900EE4AFA /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8FC0367B15B4477900EE4AFA /* QuartzCore.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 8F150F3215B1559D00EE1B9C /* HHPanningTableViewCell.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HHPanningTableViewCell.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 8F150F3615B1559D00EE1B9C /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + 8F150F3815B1559D00EE1B9C /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 8F150F3A15B1559D00EE1B9C /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + 8F150F3E15B1559D00EE1B9C /* HHPanningTableViewCell-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "HHPanningTableViewCell-Info.plist"; sourceTree = ""; }; + 8F150F4015B1559D00EE1B9C /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + 8F150F4215B1559D00EE1B9C /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 8F150F4415B1559D00EE1B9C /* HHPanningTableViewCell-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "HHPanningTableViewCell-Prefix.pch"; sourceTree = ""; }; + 8F150F4515B1559D00EE1B9C /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = HHPanningTableViewCell/AppDelegate.h; sourceTree = ""; }; + 8F150F4615B1559D00EE1B9C /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = HHPanningTableViewCell/AppDelegate.m; sourceTree = ""; }; + 8F150F5315B155D300EE1B9C /* TableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TableViewController.h; path = HHPanningTableViewCell/TableViewController.h; sourceTree = ""; }; + 8F150F5415B155D300EE1B9C /* TableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TableViewController.m; path = HHPanningTableViewCell/TableViewController.m; sourceTree = ""; }; + 8F150F5515B155D300EE1B9C /* TableViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = TableViewController.xib; path = HHPanningTableViewCell/TableViewController.xib; sourceTree = ""; }; + 8F150F5815B1586A00EE1B9C /* HHPanningTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HHPanningTableViewCell.h; sourceTree = ""; }; + 8F150F5915B1586A00EE1B9C /* HHPanningTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HHPanningTableViewCell.m; sourceTree = ""; }; + 8F3F12B915B56854002B8762 /* HHInnerShadowView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HHInnerShadowView.h; sourceTree = ""; }; + 8F3F12BA15B56854002B8762 /* HHInnerShadowView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HHInnerShadowView.m; sourceTree = ""; }; + 8F6D1C1B15B3392900706C97 /* HHDirectionPanGestureRecognizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HHDirectionPanGestureRecognizer.h; sourceTree = ""; }; + 8F6D1C1C15B3392900706C97 /* HHDirectionPanGestureRecognizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HHDirectionPanGestureRecognizer.m; sourceTree = ""; }; + 8F92F43D162C5F3B0066B3F8 /* dark_dotted.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = dark_dotted.png; sourceTree = ""; }; + 8F92F43E162C5F3B0066B3F8 /* dark_dotted@2X.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "dark_dotted@2X.png"; sourceTree = ""; }; + 8FC0367B15B4477900EE4AFA /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8F150F2F15B1559D00EE1B9C /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8F150F3715B1559D00EE1B9C /* UIKit.framework in Frameworks */, + 8F150F3915B1559D00EE1B9C /* Foundation.framework in Frameworks */, + 8F150F3B15B1559D00EE1B9C /* CoreGraphics.framework in Frameworks */, + 8FC0367C15B4477900EE4AFA /* QuartzCore.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 8F150F2715B1559D00EE1B9C = { + isa = PBXGroup; + children = ( + 8FC0367915B438BD00EE4AFA /* Demo */, + 8F150F3C15B1559D00EE1B9C /* HHPanningTableViewCell */, + 8FC0367A15B438D100EE4AFA /* Images */, + 8F150F3515B1559D00EE1B9C /* Frameworks */, + 8F150F3315B1559D00EE1B9C /* Products */, + ); + sourceTree = ""; + }; + 8F150F3315B1559D00EE1B9C /* Products */ = { + isa = PBXGroup; + children = ( + 8F150F3215B1559D00EE1B9C /* HHPanningTableViewCell.app */, + ); + name = Products; + sourceTree = ""; + }; + 8F150F3515B1559D00EE1B9C /* Frameworks */ = { + isa = PBXGroup; + children = ( + 8FC0367B15B4477900EE4AFA /* QuartzCore.framework */, + 8F150F3615B1559D00EE1B9C /* UIKit.framework */, + 8F150F3815B1559D00EE1B9C /* Foundation.framework */, + 8F150F3A15B1559D00EE1B9C /* CoreGraphics.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 8F150F3C15B1559D00EE1B9C /* HHPanningTableViewCell */ = { + isa = PBXGroup; + children = ( + 8F6D1C1B15B3392900706C97 /* HHDirectionPanGestureRecognizer.h */, + 8F6D1C1C15B3392900706C97 /* HHDirectionPanGestureRecognizer.m */, + 8F3F12B915B56854002B8762 /* HHInnerShadowView.h */, + 8F3F12BA15B56854002B8762 /* HHInnerShadowView.m */, + 8F150F5815B1586A00EE1B9C /* HHPanningTableViewCell.h */, + 8F150F5915B1586A00EE1B9C /* HHPanningTableViewCell.m */, + ); + path = HHPanningTableViewCell; + sourceTree = ""; + }; + 8F150F3D15B1559D00EE1B9C /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 8F150F3E15B1559D00EE1B9C /* HHPanningTableViewCell-Info.plist */, + 8F150F3F15B1559D00EE1B9C /* InfoPlist.strings */, + 8F150F4215B1559D00EE1B9C /* main.m */, + 8F150F4415B1559D00EE1B9C /* HHPanningTableViewCell-Prefix.pch */, + ); + name = "Supporting Files"; + path = HHPanningTableViewCell; + sourceTree = ""; + }; + 8FC0367915B438BD00EE4AFA /* Demo */ = { + isa = PBXGroup; + children = ( + 8F150F4515B1559D00EE1B9C /* AppDelegate.h */, + 8F150F4615B1559D00EE1B9C /* AppDelegate.m */, + 8F150F3D15B1559D00EE1B9C /* Supporting Files */, + 8F150F5315B155D300EE1B9C /* TableViewController.h */, + 8F150F5415B155D300EE1B9C /* TableViewController.m */, + 8F150F5515B155D300EE1B9C /* TableViewController.xib */, + ); + name = Demo; + sourceTree = ""; + }; + 8FC0367A15B438D100EE4AFA /* Images */ = { + isa = PBXGroup; + children = ( + 8F92F43D162C5F3B0066B3F8 /* dark_dotted.png */, + 8F92F43E162C5F3B0066B3F8 /* dark_dotted@2X.png */, + ); + name = Images; + path = HHPanningTableViewCell; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 8F150F3115B1559D00EE1B9C /* HHPanningTableViewCell */ = { + isa = PBXNativeTarget; + buildConfigurationList = 8F150F5015B1559D00EE1B9C /* Build configuration list for PBXNativeTarget "HHPanningTableViewCell" */; + buildPhases = ( + 8F150F2E15B1559D00EE1B9C /* Sources */, + 8F150F2F15B1559D00EE1B9C /* Frameworks */, + 8F150F3015B1559D00EE1B9C /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = HHPanningTableViewCell; + productName = HHPanningTableViewCell; + productReference = 8F150F3215B1559D00EE1B9C /* HHPanningTableViewCell.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 8F150F2915B1559D00EE1B9C /* Project object */ = { + isa = PBXProject; + attributes = { + CLASSPREFIX = HH; + LastUpgradeCheck = 0440; + ORGANIZATIONNAME = "Pierre Bernard"; + }; + buildConfigurationList = 8F150F2C15B1559D00EE1B9C /* Build configuration list for PBXProject "HHPanningTableViewCell" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 8F150F2715B1559D00EE1B9C; + productRefGroup = 8F150F3315B1559D00EE1B9C /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 8F150F3115B1559D00EE1B9C /* HHPanningTableViewCell */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 8F150F3015B1559D00EE1B9C /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8F150F4115B1559D00EE1B9C /* InfoPlist.strings in Resources */, + 8F150F5715B155D300EE1B9C /* TableViewController.xib in Resources */, + 8F92F43F162C5F3B0066B3F8 /* dark_dotted.png in Resources */, + 8F92F440162C5F3B0066B3F8 /* dark_dotted@2X.png in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 8F150F2E15B1559D00EE1B9C /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8F150F4315B1559D00EE1B9C /* main.m in Sources */, + 8F150F4715B1559D00EE1B9C /* AppDelegate.m in Sources */, + 8F150F5615B155D300EE1B9C /* TableViewController.m in Sources */, + 8F150F5A15B1586B00EE1B9C /* HHPanningTableViewCell.m in Sources */, + 8F6D1C1D15B3392900706C97 /* HHDirectionPanGestureRecognizer.m in Sources */, + 8F3F12BB15B56854002B8762 /* HHInnerShadowView.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 8F150F3F15B1559D00EE1B9C /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 8F150F4015B1559D00EE1B9C /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 8F150F4E15B1559D00EE1B9C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 5.1; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 8F150F4F15B1559D00EE1B9C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_VERSION = com.apple.compilers.llvm.clang.1_0; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 5.1; + OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 8F150F5115B1559D00EE1B9C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "HHPanningTableViewCell/HHPanningTableViewCell-Prefix.pch"; + INFOPLIST_FILE = "HHPanningTableViewCell/HHPanningTableViewCell-Info.plist"; + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = app; + }; + name = Debug; + }; + 8F150F5215B1559D00EE1B9C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "HHPanningTableViewCell/HHPanningTableViewCell-Prefix.pch"; + INFOPLIST_FILE = "HHPanningTableViewCell/HHPanningTableViewCell-Info.plist"; + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = app; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 8F150F2C15B1559D00EE1B9C /* Build configuration list for PBXProject "HHPanningTableViewCell" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8F150F4E15B1559D00EE1B9C /* Debug */, + 8F150F4F15B1559D00EE1B9C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 8F150F5015B1559D00EE1B9C /* Build configuration list for PBXNativeTarget "HHPanningTableViewCell" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8F150F5115B1559D00EE1B9C /* Debug */, + 8F150F5215B1559D00EE1B9C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 8F150F2915B1559D00EE1B9C /* Project object */; +} diff --git a/HHPanningTableViewCell/AppDelegate.h b/HHPanningTableViewCell/AppDelegate.h new file mode 100644 index 0000000..fa66964 --- /dev/null +++ b/HHPanningTableViewCell/AppDelegate.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2012, Pierre Bernard & Houdah Software s.à r.l. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#import + + +@class TableViewController; + +@interface AppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + +@property (strong, nonatomic) TableViewController *viewController; + +@end diff --git a/HHPanningTableViewCell/AppDelegate.m b/HHPanningTableViewCell/AppDelegate.m new file mode 100644 index 0000000..9d5316b --- /dev/null +++ b/HHPanningTableViewCell/AppDelegate.m @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2012, Pierre Bernard & Houdah Software s.à r.l. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#import "AppDelegate.h" + +#import "TableViewController.h" + + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; + // Override point for customization after application launch. + self.viewController = [[TableViewController alloc] init]; + self.window.rootViewController = self.viewController; + [self.window makeKeyAndVisible]; + return YES; +} + +- (void)applicationWillResignActive:(UIApplication *)application +{ + // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. + // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. +} + +- (void)applicationDidEnterBackground:(UIApplication *)application +{ + // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. +} + +- (void)applicationWillEnterForeground:(UIApplication *)application +{ + // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. +} + +- (void)applicationDidBecomeActive:(UIApplication *)application +{ + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. +} + +- (void)applicationWillTerminate:(UIApplication *)application +{ + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. +} + +@end diff --git a/HHPanningTableViewCell/HHAppDelegate.h b/HHPanningTableViewCell/HHAppDelegate.h new file mode 100644 index 0000000..8876f4d --- /dev/null +++ b/HHPanningTableViewCell/HHAppDelegate.h @@ -0,0 +1,19 @@ +// +// HHAppDelegate.h +// HHPanningTableViewCell +// +// Created by Pierre Bernard on 14/7/12. +// Copyright (c) 2012 Pierre Bernard. All rights reserved. +// + +#import + +@class HHTableViewController; + +@interface HHAppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + +@property (strong, nonatomic) HHTableViewController *viewController; + +@end diff --git a/HHPanningTableViewCell/HHAppDelegate.m b/HHPanningTableViewCell/HHAppDelegate.m new file mode 100644 index 0000000..a5a5f4e --- /dev/null +++ b/HHPanningTableViewCell/HHAppDelegate.m @@ -0,0 +1,52 @@ +// +// HHAppDelegate.m +// HHPanningTableViewCell +// +// Created by Pierre Bernard on 14/7/12. +// Copyright (c) 2012 Pierre Bernard. All rights reserved. +// + +#import "HHAppDelegate.h" + +#import "HHTableViewController.h" + +@implementation HHAppDelegate + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; + // Override point for customization after application launch. + self.viewController = [[HHTableViewController alloc] initWithNibName:@"HHTableViewController" bundle:nil]; + self.window.rootViewController = self.viewController; + [self.window makeKeyAndVisible]; + return YES; +} + +- (void)applicationWillResignActive:(UIApplication *)application +{ + // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. + // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. +} + +- (void)applicationDidEnterBackground:(UIApplication *)application +{ + // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. +} + +- (void)applicationWillEnterForeground:(UIApplication *)application +{ + // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. +} + +- (void)applicationDidBecomeActive:(UIApplication *)application +{ + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. +} + +- (void)applicationWillTerminate:(UIApplication *)application +{ + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. +} + +@end diff --git a/HHPanningTableViewCell/HHDirectionPanGestureRecognizer.h b/HHPanningTableViewCell/HHDirectionPanGestureRecognizer.h new file mode 100644 index 0000000..c067def --- /dev/null +++ b/HHPanningTableViewCell/HHDirectionPanGestureRecognizer.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2012, Pierre Bernard & Houdah Software s.à r.l. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#import + + +typedef enum { + HHDirectionPanGestureRecognizerHorizontal = (UISwipeGestureRecognizerDirectionRight | UISwipeGestureRecognizerDirectionLeft), + HHDirectionPangestureRecognizerVertical = (UISwipeGestureRecognizerDirectionUp | UISwipeGestureRecognizerDirectionDown), +} HHDirectionPangestureRecognizerDirection; + + +@interface HHDirectionPanGestureRecognizer : UIPanGestureRecognizer +{ +} + +@property (nonatomic, assign) HHDirectionPangestureRecognizerDirection direction; +@property (nonatomic, assign, readonly) BOOL panRecognized; + +@end diff --git a/HHPanningTableViewCell/HHDirectionPanGestureRecognizer.m b/HHPanningTableViewCell/HHDirectionPanGestureRecognizer.m new file mode 100644 index 0000000..bf8fae5 --- /dev/null +++ b/HHPanningTableViewCell/HHDirectionPanGestureRecognizer.m @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2012, Pierre Bernard & Houdah Software s.à r.l. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#import "HHDirectionPanGestureRecognizer.h" + +#import + + +static CGFloat const kDirectionPanThreshold = 5.0; + + +@interface HHDirectionPanGestureRecognizer () + +@property (nonatomic, assign) BOOL panRecognized; + +@end + + +@implementation HHDirectionPanGestureRecognizer + +#pragma mark - +#pragma mark Initialization + +- (id)initWithTarget:(id)target action:(SEL)action +{ + self = [super initWithTarget:target action:action]; + + if (self != nil) { + self.direction = HHDirectionPanGestureRecognizerHorizontal; + } + + return self; +} + + +#pragma mark - +#pragma mark Accessors + +@synthesize direction = _direction; +@synthesize panRecognized = _panRecognized; + + +#pragma mark - +#pragma mark Instance methods + +- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event +{ + [super touchesMoved:touches withEvent:event]; + + if (self.state == UIGestureRecognizerStateFailed) { + return; + } + + if (!self.panRecognized) { + HHDirectionPangestureRecognizerDirection direction = self.direction; + CGPoint translation = [self translationInView:self.view]; + + if (fabsf(translation.x) > kDirectionPanThreshold) { + if (direction == HHDirectionPangestureRecognizerVertical) { + self.state = UIGestureRecognizerStateFailed; + } + else { + self.panRecognized = YES; + } + } + else if (fabsf(translation.y) > kDirectionPanThreshold) { + if (direction == HHDirectionPanGestureRecognizerHorizontal) { + self.state = UIGestureRecognizerStateFailed; + } + else { + self.panRecognized = YES; + } + } + } +} + +- (void)reset +{ + [super reset]; + + self.panRecognized = NO; +} + +@end diff --git a/HHPanningTableViewCell/HHInnerShadowView.h b/HHPanningTableViewCell/HHInnerShadowView.h new file mode 100644 index 0000000..a1255d8 --- /dev/null +++ b/HHPanningTableViewCell/HHInnerShadowView.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2012, Pierre Bernard & Houdah Software s.à r.l. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#import + +@interface HHInnerShadowView : UIView + +@end diff --git a/HHPanningTableViewCell/HHInnerShadowView.m b/HHPanningTableViewCell/HHInnerShadowView.m new file mode 100644 index 0000000..ab3879c --- /dev/null +++ b/HHPanningTableViewCell/HHInnerShadowView.m @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2012, Pierre Bernard & Houdah Software s.à r.l. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#import "HHInnerShadowView.h" + +#import + + +@interface HHInnerShadowView () + +@end + + +@implementation HHInnerShadowView + +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + // Initialization code + } + return self; +} + + +#pragma mark - +#pragma mark Accessors + + +#pragma mark - +#pragma mark Drawing + +- (void)drawRect:(CGRect)rect +{ + // http://stackoverflow.com/questions/4431292/inner-shadow-effect-on-uiview-layer + + CGRect bounds = [self bounds]; + CGContextRef context = UIGraphicsGetCurrentContext(); + + // Create the shape of the shadow + CGMutablePathRef visiblePath = CGPathCreateMutable(); + CGPathAddRect(visiblePath, NULL, bounds); + + [[UIColor clearColor] setFill]; + + CGContextAddPath(context, visiblePath); + CGContextFillPath(context); + + // Now create a larger rectangle, which we're going to subtract the visible path from and apply a shadow + CGMutablePathRef path = CGPathCreateMutable(); + CGPathAddRect(path, NULL, CGRectInset(bounds, -10.0, -10.0)); + + // Add the visible path (so that it gets subtracted for the shadow) + CGPathAddPath(path, NULL, visiblePath); + CGPathCloseSubpath(path); + + // Add the visible paths as the clipping path to the context + CGContextAddPath(context, visiblePath); + CGContextClip(context); + + // Now setup the shadow properties on the context + CGContextSaveGState(context); + CGContextSetShadowWithColor(context, CGSizeMake(0.0f, 1.0f), 10.0f, [[UIColor blackColor] CGColor]); + + // Now fill the rectangle, so the shadow gets drawn + [[UIColor blackColor] setFill]; + + CGContextSaveGState(context); + CGContextAddPath(context, path); + CGContextEOFillPath(context); + + // Release the paths + CGPathRelease(path); + CGPathRelease(visiblePath); +} + +@end diff --git a/HHPanningTableViewCell/HHPanningTableViewCell-Info.plist b/HHPanningTableViewCell/HHPanningTableViewCell-Info.plist new file mode 100644 index 0000000..b715d5e --- /dev/null +++ b/HHPanningTableViewCell/HHPanningTableViewCell-Info.plist @@ -0,0 +1,38 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + ${PRODUCT_NAME} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + com.houdah.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/HHPanningTableViewCell/HHPanningTableViewCell-Prefix.pch b/HHPanningTableViewCell/HHPanningTableViewCell-Prefix.pch new file mode 100644 index 0000000..5ba5258 --- /dev/null +++ b/HHPanningTableViewCell/HHPanningTableViewCell-Prefix.pch @@ -0,0 +1,14 @@ +// +// Prefix header for all source files of the 'HHPanningTableViewCell' target in the 'HHPanningTableViewCell' project +// + +#import + +#ifndef __IPHONE_4_0 +#warning "This project uses features only available in iOS SDK 4.0 and later." +#endif + +#ifdef __OBJC__ + #import + #import +#endif diff --git a/HHPanningTableViewCell/HHPanningTableViewCell.h b/HHPanningTableViewCell/HHPanningTableViewCell.h new file mode 100644 index 0000000..f01f8ba --- /dev/null +++ b/HHPanningTableViewCell/HHPanningTableViewCell.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2012, Pierre Bernard & Houdah Software s.à r.l. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#import + + +typedef enum { + HHPanningTableViewCellDirectionRight = UISwipeGestureRecognizerDirectionRight, + HHPanningTableViewCellDirectionLeft = UISwipeGestureRecognizerDirectionLeft, +} HHPanningTableViewCellDirection; + + +@interface HHPanningTableViewCell : UITableViewCell + +- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString*)reuseIdentifier; + + +@property (nonatomic, strong) IBOutlet UIView* drawerView; + +@property (nonatomic, assign) NSInteger directionMask; +@property (nonatomic, assign) BOOL shouldBounce; + +- (BOOL)isDrawerRevealed; +- (void)setDrawerRevealed:(BOOL)revealed animated:(BOOL)animated; + +@end diff --git a/HHPanningTableViewCell/HHPanningTableViewCell.m b/HHPanningTableViewCell/HHPanningTableViewCell.m new file mode 100644 index 0000000..5c9b0c4 --- /dev/null +++ b/HHPanningTableViewCell/HHPanningTableViewCell.m @@ -0,0 +1,588 @@ +/* + * Copyright (c) 2012, Pierre Bernard & Houdah Software s.à r.l. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#import "HHPanningTableViewCell.h" + +#import "HHDirectionPanGestureRecognizer.h" +#import "HHInnerShadowView.h" + +#import +#import + + +#define HH_PANNING_ANIMATION_DURATION 0.1f +#define HH_PANNING_BOUNCE_DISTANCE 20.0f +#define HH_PANNING_MINIMUM_PAN 50.0f +#define HH_PANNING_TRIGGER_OFFSET 100.0f + + +@interface HHPanningTableViewCell () + +@property (nonatomic, assign, getter = isDrawerRevealed) BOOL drawerRevealed; +@property (nonatomic, assign, getter = isAnimationInProgress) BOOL animationInProgress; + +@property (nonatomic, strong) UIView* containerView; +@property (nonatomic, strong) UIView* shadowView; +@property (nonatomic, strong) UIPanGestureRecognizer* panGestureRecognizer; +@property (nonatomic, assign) CGFloat panOriginX; +@property (nonatomic, assign, getter = isPanning) BOOL panning; + +- (void)panningTableViewCellInit; + +- (UIView*)createContainerView; +- (UIView*)createShadowView; +- (UIPanGestureRecognizer*)createPanGesureRecognizer; + +- (void)setDrawerRevealed:(BOOL)revealed direction:(HHPanningTableViewCellDirection)direction animated:(BOOL)animated; + +- (void)updateShadowFrame; + +@end + + +static NSString * const kDrawerRevealedContext = @"drawerRevealed"; +static NSString * const kContainerFrameContext = @"containerFrame"; + +static HHPanningTableViewCellDirection HHOppositeDirection(HHPanningTableViewCellDirection direction); + + +@implementation HHPanningTableViewCell + +#pragma mark - +#pragma mark Initialization + +- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString*)reuseIdentifier +{ + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + + if (self != nil) { + [self panningTableViewCellInit]; + } + + return self; +} + +- (id)initWithCoder:(NSCoder*)coder +{ + self = [super initWithCoder:coder]; + + if (self != nil) { + [self panningTableViewCellInit]; + } + + return self; +} + +- (void)panningTableViewCellInit +{ + self.containerView = [self createContainerView]; + self.shadowView = [self createShadowView]; + self.panGestureRecognizer = [self createPanGesureRecognizer]; + + [self addGestureRecognizer:self.panGestureRecognizer]; + + self.directionMask = 0; + self.shouldBounce = YES; + + [self addObserver:self forKeyPath:@"drawerRevealed" options:0 context:(__bridge void *)kDrawerRevealedContext]; + [self addObserver:self forKeyPath:@"containerView.frame" options:0 context:(__bridge void *)kContainerFrameContext]; +} + +- (void)awakeFromNib +{ + if ([super respondsToSelector:@selector(awakeFromNib)]) { + [super awakeFromNib]; + } +} + +- (void)prepareForReuse +{ + [super prepareForReuse]; + + [self setDrawerRevealed:NO animated:NO]; +} + +- (UIView*)createContainerView +{ + UIView* containerView = [[UIView alloc] initWithFrame:self.bounds]; + + [containerView setOpaque:YES]; + [containerView setAutoresizesSubviews:YES]; + [containerView setAutoresizingMask:UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight]; + + [containerView setBackgroundColor:[UIColor whiteColor]]; + + return containerView; +} + +- (UIView*)createShadowView +{ + UIView* shadowView = [[HHInnerShadowView alloc] initWithFrame:self.bounds]; + + [shadowView setOpaque:NO]; + [shadowView setUserInteractionEnabled:NO]; + [shadowView setAutoresizesSubviews:YES]; + [shadowView setAutoresizingMask:UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight]; + + return shadowView; +} + +- (UIPanGestureRecognizer*)createPanGesureRecognizer +{ + HHDirectionPanGestureRecognizer* gestureRecognizer = [[HHDirectionPanGestureRecognizer alloc] initWithTarget:self + action:@selector(gestureRecognizerDidPan:)]; + + gestureRecognizer.direction = HHDirectionPanGestureRecognizerHorizontal; + gestureRecognizer.delegate = self; + + return gestureRecognizer; +} + + +#pragma mark - +#pragma mark Finalization + +- (void)dealloc +{ + [self removeObserver:self forKeyPath:@"drawerRevealed"]; + [self removeObserver:self forKeyPath:@"containerView.frame"]; +} + + +#pragma mark - +#pragma mark Accessors + +@synthesize drawerView = _drawerView; + +@synthesize directionMask = _directionMask; +@synthesize shouldBounce = _shouldBounce; + +@synthesize drawerRevealed = _drawerRevealed; +@synthesize animationInProgress = _animationInProgress; + +@synthesize containerView = _containerView; +@synthesize shadowView = _shadowView; +@synthesize panGestureRecognizer = _panGestureRecognizer; + +@synthesize panOriginX = _panOriginX; +@synthesize panning = _panning; + +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context +{ + if (context == (__bridge void *)kDrawerRevealedContext) { + if (self.drawerRevealed) { + UIView* tableView = [self superview]; + + if ([tableView isKindOfClass:[UITableView class]]) { + for (UITableViewCell *cell in [(UITableView*)tableView visibleCells]) { + if ((cell != self) && [cell isKindOfClass:[HHPanningTableViewCell class]]) { + [(HHPanningTableViewCell*)cell setDrawerRevealed:NO animated:YES]; + } + } + } + } + } + else if (context == (__bridge void *)kContainerFrameContext) { + [self updateShadowFrame]; + } + else { + [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; + } +} + + +#pragma mark - +#pragma mark API + +- (void)setSelected:(BOOL)selected animated:(BOOL)animated +{ + [super setSelected:selected animated:animated]; +} + +- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated +{ + if (highlighted && [self isDrawerRevealed]) { + return; + } + + [super setHighlighted:highlighted animated:animated]; +} + +- (void)setEditing:(BOOL)editing animated:(BOOL)animated; +{ + if (editing && [self isDrawerRevealed]) { + [self setDrawerRevealed:NO animated:NO]; + } + + [super setEditing:editing animated:animated]; +} + +- (void)setDrawerRevealed:(BOOL)revealed animated:(BOOL)animated +{ + NSInteger directionMask = self.directionMask; + + if (HHPanningTableViewCellDirectionRight & directionMask) { + [self setDrawerRevealed:revealed direction:HHPanningTableViewCellDirectionRight animated:animated]; + } + else if (HHPanningTableViewCellDirectionLeft & directionMask) { + [self setDrawerRevealed:revealed direction:HHPanningTableViewCellDirectionLeft animated:animated]; + } +} + +- (void)setDrawerRevealed:(BOOL)revealed direction:(HHPanningTableViewCellDirection)direction animated:(BOOL)animated +{ + if ([self isEditing] || (self.drawerView == nil)) { + return; + } + + self.drawerRevealed = revealed; + + UIView *drawerView = self.drawerView; + UIView *shadowView = self.shadowView; + UIView *containerView = self.containerView; + CGRect frame = [containerView frame]; + + UIView *cellView = self; + CGRect bounds = [cellView bounds]; + CGFloat duration = animated ? HH_PANNING_ANIMATION_DURATION : 0.0f; + + [cellView addSubview:drawerView]; + [cellView addSubview:shadowView]; + [cellView addSubview:containerView]; + + if (revealed) { + if (direction == HHPanningTableViewCellDirectionRight) { + frame.origin.x = bounds.origin.x + bounds.size.width; + } + else { + frame.origin.x = bounds.origin.x - bounds.size.width; + } + + self.animationInProgress = YES; + + [UIView animateWithDuration:duration + delay:0.0f + options:UIViewAnimationOptionCurveEaseOut + animations:^{ + [containerView setFrame:frame]; + } completion:^(BOOL finished) { + [containerView removeFromSuperview]; + + self.animationInProgress = NO; + }]; + } + else { + frame.origin.x = 0.0; + + BOOL shouldBounce = self.shouldBounce; + + if (shouldBounce) { + CGFloat bounceDuration = duration; + CGFloat offsetX = containerView.frame.origin.x; + CGFloat bounceMultiplier = fminf(fabsf(offsetX / HH_PANNING_TRIGGER_OFFSET), 1.0f); + CGFloat bounceDistance = bounceMultiplier * HH_PANNING_BOUNCE_DISTANCE; + + if (offsetX < 0.0f) { + bounceDistance *= -1.0; + } + + self.animationInProgress = YES; + + [UIView animateWithDuration:duration + delay:0.0f + options:UIViewAnimationOptionCurveEaseOut + animations:^{ + [containerView setFrame:frame]; + } completion:^(BOOL finished) { + [UIView animateWithDuration:bounceDuration + delay:0.0f + options:UIViewAnimationCurveLinear + animations:^{ + [containerView setFrame:CGRectOffset(frame, bounceDistance, 0.0f)]; + } completion:^(BOOL finished) { + [UIView animateWithDuration:bounceDuration + delay:0.0f + options:UIViewAnimationCurveLinear + animations:^{ + [containerView setFrame:frame]; + } completion:^(BOOL finished) { + [drawerView removeFromSuperview]; + [shadowView removeFromSuperview]; + + self.animationInProgress = NO; + }]; + }]; + }]; + } + else { + self.animationInProgress = YES; + + [UIView animateWithDuration:duration + delay:0.0f + options:UIViewAnimationOptionCurveEaseOut + animations:^{ + [containerView setFrame:frame]; + } completion:^(BOOL finished) { + [drawerView removeFromSuperview]; + [shadowView removeFromSuperview]; + + self.animationInProgress = NO; + }]; + } + } +} + + +#pragma mark - +#pragma mark Gesture recognizer + +- (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer shouldReceiveTouch:(UITouch*)touch +{ + BOOL shouldReceiveTouch = (! self.animationInProgress) && (! self.editing) && (self.drawerView != nil); + + return shouldReceiveTouch; +} + +- (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer +{ + if ([gestureRecognizer isKindOfClass:[HHDirectionPanGestureRecognizer class]]) { + HHDirectionPanGestureRecognizer *panGestureRecognizer = (HHDirectionPanGestureRecognizer*)gestureRecognizer; + + return (!panGestureRecognizer.panRecognized); + } + + return YES; +} + +- (void)gestureRecognizerDidPan:(UIPanGestureRecognizer*)gestureRecognizer +{ + if (self.animationInProgress) { + return; + } + + UIGestureRecognizerState state = gestureRecognizer.state; + + if (state == UIGestureRecognizerStateBegan) { + UIView *drawerView = self.drawerView; + UIView *shadowView = self.shadowView; + UIView *containerView = self.containerView; + + [self addSubview:drawerView]; + [self addSubview:shadowView]; + [self addSubview:containerView]; + [self setSelected:NO]; + + self.panOriginX = containerView.frame.origin.x; + self.panning = NO; + } + else if (state == UIGestureRecognizerStateChanged) { + CGPoint translation = [gestureRecognizer translationInView:self]; + CGFloat totalPanX = translation.x; + + if (!self.panning) { + if (fabsf(totalPanX) <= HH_PANNING_MINIMUM_PAN) { + totalPanX = 0.0f; + } + else { + self.panning = YES; + } + } + + UIView *containerView = self.containerView; + CGRect containerViewFrame = [containerView frame]; + + containerViewFrame.origin.x = self.panOriginX + totalPanX; + + CGFloat width = self.bounds.size.width; + NSInteger directionMask = self.directionMask; + CGFloat leftLimit = (directionMask & HHPanningTableViewCellDirectionLeft) ? (-1.0 * width) : 0.0f; + CGFloat rightLimit = (directionMask & HHPanningTableViewCellDirectionRight) ? width : 0.0f; + + if (containerViewFrame.origin.x <= leftLimit) { + containerViewFrame.origin.x = leftLimit; + } + else if (containerViewFrame.origin.x >= rightLimit) { + containerViewFrame.origin.x = rightLimit; + } + + [containerView setFrame:containerViewFrame]; + } + else if ((state == UIGestureRecognizerStateEnded) || (state == UIGestureRecognizerStateCancelled)) { + BOOL drawerRevealed = self.drawerRevealed; + BOOL drawerWasRevealed = drawerRevealed; + + CGPoint translation = [gestureRecognizer translationInView:self]; + CGFloat totalPanX = translation.x; + CGFloat panOriginX = self.panOriginX; + BOOL isOffsetRight = (panOriginX > 0.0); + HHPanningTableViewCellDirection panDirection = (totalPanX > 0.0f) ? HHPanningTableViewCellDirectionRight : HHPanningTableViewCellDirectionLeft; + HHPanningTableViewCellDirection normalizedPanDirection = drawerRevealed ? HHOppositeDirection(panDirection) : panDirection; + NSInteger directionMask = self.directionMask; + + if (drawerRevealed) { + directionMask = isOffsetRight ? HHPanningTableViewCellDirectionRight : HHPanningTableViewCellDirectionLeft; + } + + if (normalizedPanDirection & directionMask) { + CGFloat triggerOffset = HH_PANNING_TRIGGER_OFFSET; + + if (fabsf(totalPanX) > triggerOffset) { + drawerRevealed = !drawerRevealed; + } + else { + CGPoint velocity = [gestureRecognizer velocityInView:self]; + CGFloat velocityX = velocity.x; + + if (fabsf(velocityX) > triggerOffset) { + drawerRevealed = !drawerRevealed; + } + } + } + + HHPanningTableViewCellDirection direction = panDirection; + + if (drawerRevealed == drawerWasRevealed) { + direction = isOffsetRight ? HHPanningTableViewCellDirectionRight : HHPanningTableViewCellDirectionLeft; + } + + [self setDrawerRevealed:drawerRevealed direction:direction animated:YES]; + + self.panning = NO; + } +} + +- (void)layoutSubviews +{ + [super layoutSubviews]; + + UIView* cellView = self; + UIView* containerView = self.containerView; + UIView* drawerView = self.drawerView; + UIView* shadowView = self.shadowView; + UIView* backgroundView = self.backgroundView; + UIView* contentView = self.contentView; + + if (!self.animationInProgress) { + CGRect cellBounds = [cellView bounds]; + CGRect contentBounds = [contentView bounds]; + CGRect containerFrame = cellBounds; + + containerFrame.size.height = contentBounds.size.height; + + if (self.drawerRevealed) { + CGRect frame = [containerView frame]; + + frame.size.height = contentBounds.size.height; + frame.size.width = contentBounds.size.width; + + if (frame.origin.x > cellBounds.origin.x) { + frame.origin.x = cellBounds.origin.x + cellBounds.size.width; + } + else { + frame.origin.x = cellBounds.origin.x - cellBounds.size.width; + } + + [containerView setFrame:frame]; + + [containerView addSubview:backgroundView]; + [containerView addSubview:contentView]; + + [self insertSubview:drawerView belowSubview:containerView]; + [self insertSubview:shadowView aboveSubview:drawerView]; + } + else { + [containerView setFrame:containerFrame]; + [containerView addSubview:backgroundView]; + [containerView addSubview:contentView]; + + [self addSubview:containerView]; + } + } + + // Move other subviews. E.g. drag reorder control + for (UIView *subview in [self.subviews reverseObjectEnumerator]) { + if (subview == containerView) { + continue; + } + + if (subview == drawerView) { + continue; + } + + if (subview == shadowView) { + continue; + } + + if (subview == backgroundView) { + continue; + } + + if (subview == contentView) { + continue; + } + + [containerView insertSubview:subview atIndex:0]; + } + + [drawerView setFrame:contentView.frame]; + [self updateShadowFrame]; +} + +- (void)updateShadowFrame +{ + UIView* cellView = self; + CGRect cellBounds = [cellView bounds]; + UIView* containerView = self.containerView; + UIView* shadowView = self.shadowView; + CGRect containerFrame = [containerView frame]; + CGRect shadowFrame = containerFrame; + + shadowFrame.size.width *= 2.0; + + if (containerFrame.origin.x < cellBounds.origin.x) { + shadowFrame.origin.x = containerFrame.origin.x + containerFrame.size.width; + } + else { + shadowFrame.origin.x = shadowFrame.origin.x - shadowFrame.size.width; + } + + [shadowView setFrame:shadowFrame]; +} + +@end + + +static HHPanningTableViewCellDirection HHOppositeDirection(HHPanningTableViewCellDirection direction) +{ + switch (direction) { + case HHPanningTableViewCellDirectionRight: + return HHPanningTableViewCellDirectionLeft; + case HHPanningTableViewCellDirectionLeft: + return HHPanningTableViewCellDirectionRight; + } +} diff --git a/HHPanningTableViewCell/HHTableViewController.h b/HHPanningTableViewCell/HHTableViewController.h new file mode 100644 index 0000000..0ed00a3 --- /dev/null +++ b/HHPanningTableViewCell/HHTableViewController.h @@ -0,0 +1,16 @@ +// +// HHTableViewController.h +// HHPanningTableViewCell +// +// Created by Pierre Bernard on 14/7/12. +// Copyright (c) 2012 Pierre Bernard. All rights reserved. +// + +#import + + +@interface HHTableViewController : UITableViewController + +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil; + +@end diff --git a/HHPanningTableViewCell/HHTableViewController.m b/HHPanningTableViewCell/HHTableViewController.m new file mode 100644 index 0000000..926348f --- /dev/null +++ b/HHPanningTableViewCell/HHTableViewController.m @@ -0,0 +1,123 @@ +// +// HHTableViewController.m +// HHPanningTableViewCell +// +// Created by Pierre Bernard on 14/7/12. +// Copyright (c) 2012 Pierre Bernard. All rights reserved. +// + +#import "HHTableViewController.h" + +#import "HHPanningTableViewCell.h" + + +@interface HHTableViewController () + +@property (nonatomic, retain) NSArray *rowTitles; + +@end + + +@implementation HHTableViewController + +#pragma mark - +#pragma mark Initialization + +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + + if (self != nil) { + self.rowTitles = [NSArray arrayWithObjects:@"Pan direction: None", @"Pan direction: Right", @"Pan direction: Left", @"Pan direction: Both", nil]; + } + + return self; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + // Uncomment the following line to preserve selection between presentations. + // self.clearsSelectionOnViewWillAppear = NO; + + // Uncomment the following line to display an Edit button in the navigation bar for this view controller. + // self.navigationItem.rightBarButtonItem = self.editButtonItem; +} + +#pragma mark - +#pragma mark Accessors + +@synthesize rowTitles = _rowTitles; + + +#pragma mark - +#pragma mark Rotation + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation +{ + return (interfaceOrientation == UIInterfaceOrientationPortrait); +} + + +#pragma mark - +#pragma mark Table view data source + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView +{ + // Return the number of sections. + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + // Return the number of rows in the section. + return [self.rowTitles count]; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + static NSString *CellIdentifier = @"Cell"; + HHPanningTableViewCell *cell = (HHPanningTableViewCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier]; + + if (cell == nil) { + cell = [[HHPanningTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault + reuseIdentifier:CellIdentifier]; + + UIView *drawerView = [[UIView alloc] initWithFrame:cell.frame]; + + drawerView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"dottedPattern.png"]]; + + cell.drawerView = drawerView; + cell.directionMask = indexPath.row; + } + + cell.textLabel.text = [self.rowTitles objectAtIndex:indexPath.row]; + + return cell; +} + + +#pragma mark - +#pragma mark Table view delegate + +- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + + if ([cell isKindOfClass:[HHPanningTableViewCell class]]) { + HHPanningTableViewCell *panningTableViewCell = (HHPanningTableViewCell*)cell; + + if ([panningTableViewCell isDrawerRevealed]) { + return nil; + } + } + + return indexPath; +} + +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ +} + +@end diff --git a/HHPanningTableViewCell/HHTableViewController.xib b/HHPanningTableViewCell/HHTableViewController.xib new file mode 100644 index 0000000..ce5a4b3 --- /dev/null +++ b/HHPanningTableViewCell/HHTableViewController.xib @@ -0,0 +1,146 @@ + + + + 1296 + 12A269 + 2549 + 1187 + 624.00 + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + 1498 + + + IBProxyObject + IBUITableView + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + PluginDependencyRecalculationVersion + + + + + IBFilesOwner + IBCocoaTouchFramework + + + IBFirstResponder + IBCocoaTouchFramework + + + + 274 + {{0, 20}, {320, 460}} + + + + + 3 + MQA + + NO + YES + NO + + IBCocoaTouchFramework + NO + 1 + 0 + YES + 74 + 22 + 22 + + + + + + + view + + + + 5 + + + + dataSource + + + + 6 + + + + delegate + + + + 7 + + + + + + 0 + + + + + + -1 + + + File's Owner + + + -2 + + + + + 4 + + + + + + + HHTableViewController + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + UIResponder + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + 7 + + + + + HHTableViewController + UITableViewController + + IBProjectSource + ./Classes/HHTableViewController.h + + + + + 0 + IBCocoaTouchFramework + + com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS + + + YES + 3 + 1498 + + diff --git a/HHPanningTableViewCell/TableViewController.h b/HHPanningTableViewCell/TableViewController.h new file mode 100644 index 0000000..10bb812 --- /dev/null +++ b/HHPanningTableViewCell/TableViewController.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2012, Pierre Bernard & Houdah Software s.à r.l. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#import + + +@interface TableViewController : UITableViewController + +- (id)init; + +@end diff --git a/HHPanningTableViewCell/TableViewController.m b/HHPanningTableViewCell/TableViewController.m new file mode 100644 index 0000000..55597e8 --- /dev/null +++ b/HHPanningTableViewCell/TableViewController.m @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2012, Pierre Bernard & Houdah Software s.à r.l. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#import "TableViewController.h" + +#import "HHPanningTableViewCell.h" + + +@interface TableViewController () + +@property (nonatomic, retain) NSArray *rowTitles; + +@end + + +@implementation TableViewController + +#pragma mark - +#pragma mark Initialization + +- (id)init +{ + self = [super initWithNibName:@"TableViewController" bundle:nil]; + + if (self != nil) { + self.rowTitles = [NSArray arrayWithObjects:@"Pan direction: None", @"Pan direction: Right", @"Pan direction: Left", @"Pan direction: Both", nil]; + } + + return self; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + // Uncomment the following line to preserve selection between presentations. + // self.clearsSelectionOnViewWillAppear = NO; + + // Uncomment the following line to display an Edit button in the navigation bar for this view controller. + // self.navigationItem.rightBarButtonItem = self.editButtonItem; +} + +#pragma mark - +#pragma mark Accessors + +@synthesize rowTitles = _rowTitles; + + +#pragma mark - +#pragma mark Rotation + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation +{ + return YES; +} + + +#pragma mark - +#pragma mark Table view data source + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView +{ + // Return the number of sections. + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + // Return the number of rows in the section. + return [self.rowTitles count]; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + static NSString *CellIdentifier = @"Cell"; + HHPanningTableViewCell *cell = (HHPanningTableViewCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier]; + + if (cell == nil) { + cell = [[HHPanningTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault + reuseIdentifier:CellIdentifier]; + + UIView *drawerView = [[UIView alloc] initWithFrame:cell.frame]; + + // dark_dotted.png obtained from http://subtlepatterns.com/dark-dot/ + // Made by Tsvetelin Nikolov http://dribbble.com/bscsystem + drawerView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"dark_dotted"]]; + + cell.drawerView = drawerView; + cell.directionMask = indexPath.row; + } + + cell.textLabel.text = [self.rowTitles objectAtIndex:indexPath.row]; + + return cell; +} + + +#pragma mark - +#pragma mark Table view delegate + +- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + + if ([cell isKindOfClass:[HHPanningTableViewCell class]]) { + HHPanningTableViewCell *panningTableViewCell = (HHPanningTableViewCell*)cell; + + if ([panningTableViewCell isDrawerRevealed]) { + return nil; + } + } + + return indexPath; +} + +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ +} + +@end diff --git a/HHPanningTableViewCell/TableViewController.xib b/HHPanningTableViewCell/TableViewController.xib new file mode 100644 index 0000000..c19af74 --- /dev/null +++ b/HHPanningTableViewCell/TableViewController.xib @@ -0,0 +1,132 @@ + + + + 1296 + 12A269 + 2549 + 1187 + 624.00 + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + 1498 + + + IBProxyObject + IBUITableView + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + PluginDependencyRecalculationVersion + + + + + IBFilesOwner + IBCocoaTouchFramework + + + IBFirstResponder + IBCocoaTouchFramework + + + + 274 + {{0, 20}, {320, 460}} + + 3 + MQA + + NO + YES + NO + + IBCocoaTouchFramework + NO + 1 + 0 + YES + 74 + 22 + 22 + + + + + + + view + + + + 5 + + + + dataSource + + + + 6 + + + + delegate + + + + 7 + + + + + + 0 + + + + + + -1 + + + File's Owner + + + -2 + + + + + 4 + + + + + + + TableViewController + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + UIResponder + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + 7 + + + 0 + IBCocoaTouchFramework + + com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS + + + YES + 3 + 1498 + + diff --git a/HHPanningTableViewCell/dark_dotted.png b/HHPanningTableViewCell/dark_dotted.png new file mode 100644 index 0000000000000000000000000000000000000000..27555fdadf2f27cb72ef0ec200f994059223836c GIT binary patch literal 108 zcmeAS@N?(olHy`uVBq!ia0vp^tRT$63?z4LymlQ(aR&H=xQdC1NlQyBDJcax2Gsxs z~Wp4iCCz`)aNaN@uF^rhUJ7(~Own4ex}WGrNm2%d9#9Z)5Mr>mdKI;Vst E0LRE0+W-In literal 0 HcmV?d00001 diff --git a/HHPanningTableViewCell/dark_dotted@2X.png b/HHPanningTableViewCell/dark_dotted@2X.png new file mode 100644 index 0000000000000000000000000000000000000000..19604cbe28ebf2c59739fdf4fdd160c844543962 GIT binary patch literal 3593 zcmV+k4)*bhP)KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z00093P)t-s78Vv88yg}bA_D^h1Ox;H1qB8M1_uWR2nYxX2?+`c3JVJh3=9kn4Gj(s z4i66x5D*X%5fKs+5)%^>6ciK{6%`g178e&67#J8C85tTH8XFrM92^`S9UUGX9v>ec zARr(iAt53nA|oRsBqSsyB_$>%CMPE+C@3f?DJd!{Dl021EG#T7EiEoCE-x=HFfcGN zF)=bSGBYzXG&D3dH8nOiHa9mnI5;>tIXOByIy*Z%JUl!-Jv}}?K0iM{KtMo2K|w-7 zLPJACL_|bIMMXwNMn^|SNJvOYNl8jdN=r*iOiWBoO-)WtPESuyP*6}&QBhJ-Qd3h? zR8&+|RaI72R##V7SXfwDSy@_IT3cINTwGjTU0q&YUSD5dU|?WjVPRroVq;@tWMpJz zWo2e&W@l$-XlQ6@X=!R|YHMq2Y;0_8ZEbFDZf|dIaBy&OadC2Ta&vQYbaZreb#-=j zc6WDoczAeud3kzzdV70&e0+R;eSLm@et&;|fPjF3fq{a8f`fyDgoK2Jg@uNOhKGlT zh=_=ZiHVAeii?YjjEszpjg5|uj*pLzkdTm(k&%*;l9Q8@l$4Z}m6ev3mY0{8n3$NE znVFiJnwy)OoSdAUot>VZo}ZteprD|kp`oIpqNAguq@<*!rKP5(rl+T;sHmu^si~@} zs;jH3tgNi9t*x%EuCK4Ju&}VPv9YqUva_?Zw6wIfwY9dkwzs#pxVX5vxw*Q!y1To( zyu7@dCU$jHda$;ryf%FD~k%*@Qq z&CSlv&d<-!(9qD)(b3Y<($mw^)YR0~)z#M4*4Nk9*x1lt)=I7_<=;-L_>FMg~>g((4?Ck9A?d|UF?(gsK z@bK{Q@$vHV^7Hfa^z`)g_4W4l_V@Sq`1ttw`T6?#`uqF){QUg={r&#_{{R2~p${yu z0000eNklc>LMW P00000NkvXXu0mjf05-PW literal 0 HcmV?d00001 diff --git a/HHPanningTableViewCell/en.lproj/InfoPlist.strings b/HHPanningTableViewCell/en.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/HHPanningTableViewCell/en.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/HHPanningTableViewCell/innerShadow.png b/HHPanningTableViewCell/innerShadow.png new file mode 100644 index 0000000000000000000000000000000000000000..f72d08382441128f23f79e5ba4f9d7d821bc4fea GIT binary patch literal 586 zcmV-Q0=4~#P)$e;-{JH2pcC-B(TehSXd>mVrr;!W`jJY{(ra-{A``$)M0P6UK z#vCx9SVsr6PKj)G$|2a13kGj}|HKBIW2M&wDgm$>7Ko)3*M$N*G8n0^jRdr=GU+9W z1MLaA0nQ7jZ`B!L$Q`fE&+Y5aMwOCMFH&_?4+Y0Zx#((tcqdAJn1{iDYccb0kb?(rfaiJ>! zxUCy?{8>M-j*s3QYun7NQnQaa_Uhwr3_sueOvlK;0-Lx|J++o=&8_F_rj0S?J8CeH zk3;1RdMdKCaD{gBu3h`#70LnB&sg84`Px&jj0=^BM^7twJ}4&qX6Y*Oh&3C^w(rlJ zCUanMfMSS^aVC&qV*T25-Uf$I7sD@8CjuqE@{1}x#7%ND}iP!W690G6FX@Zxh&3RS>T$f;}_f#6g*}8 Y4{-UgygRc4O8@`>07*qoM6N<$f=iPTv;Y7A literal 0 HcmV?d00001 diff --git a/HHPanningTableViewCell/main.m b/HHPanningTableViewCell/main.m new file mode 100644 index 0000000..59820c9 --- /dev/null +++ b/HHPanningTableViewCell/main.m @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2012, Pierre Bernard & Houdah Software s.à r.l. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#import + +#import "AppDelegate.h" + +int main(int argc, char *argv[]) +{ + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +}