From 9dad7b7f718f26e5d0c4ba117a2c87ac9fbded24 Mon Sep 17 00:00:00 2001 From: Eli Wang Date: Wed, 20 Jul 2011 23:49:21 +0800 Subject: [PATCH] Initial layout for public release --- .gitignore | 5 + .../project.pbxproj | 339 +++++++ .../contents.xcworkspacedata | 7 + MultiColumnTableView/EWHeaderHighlightLayer.h | 31 + MultiColumnTableView/EWHeaderHighlightLayer.m | 38 + MultiColumnTableView/EWMultiColumnTableView.h | 158 ++++ MultiColumnTableView/EWMultiColumnTableView.m | 847 ++++++++++++++++++ .../EWMultiColumnTableViewBGScrollView.h | 39 + .../EWMultiColumnTableViewBGScrollView.m | 71 ++ .../EWMultiColumnTableViewCell.h | 33 + .../EWMultiColumnTableViewCell.m | 46 + ...ultiColumnTableViewContentBackgroundView.h | 35 + ...ultiColumnTableViewContentBackgroundView.m | 32 + .../EWMultiColumnTableViewDefaults.h | 36 + .../MultiColumnTableView-Info.plist | 39 + .../MultiColumnTableView-Prefix.pch | 14 + .../MultiColumnTableViewAppDelegate.h | 36 + .../MultiColumnTableViewAppDelegate.m | 90 ++ .../MultiColumnTableViewViewController.h | 39 + .../MultiColumnTableViewViewController.m | 336 +++++++ MultiColumnTableView/UIView+AddLine.h | 33 + MultiColumnTableView/UIView+AddLine.m | 54 ++ .../en.lproj/InfoPlist.strings | 2 + MultiColumnTableView/en.lproj/MainWindow.xib | 436 +++++++++ .../MultiColumnTableViewViewController.xib | 150 ++++ MultiColumnTableView/main.m | 32 + README | 1 + 27 files changed, 2979 insertions(+) create mode 100644 .gitignore create mode 100644 MultiColumnTableView.xcodeproj/project.pbxproj create mode 100644 MultiColumnTableView.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 MultiColumnTableView/EWHeaderHighlightLayer.h create mode 100644 MultiColumnTableView/EWHeaderHighlightLayer.m create mode 100644 MultiColumnTableView/EWMultiColumnTableView.h create mode 100644 MultiColumnTableView/EWMultiColumnTableView.m create mode 100644 MultiColumnTableView/EWMultiColumnTableViewBGScrollView.h create mode 100644 MultiColumnTableView/EWMultiColumnTableViewBGScrollView.m create mode 100644 MultiColumnTableView/EWMultiColumnTableViewCell.h create mode 100644 MultiColumnTableView/EWMultiColumnTableViewCell.m create mode 100644 MultiColumnTableView/EWMultiColumnTableViewContentBackgroundView.h create mode 100644 MultiColumnTableView/EWMultiColumnTableViewContentBackgroundView.m create mode 100644 MultiColumnTableView/EWMultiColumnTableViewDefaults.h create mode 100644 MultiColumnTableView/MultiColumnTableView-Info.plist create mode 100644 MultiColumnTableView/MultiColumnTableView-Prefix.pch create mode 100644 MultiColumnTableView/MultiColumnTableViewAppDelegate.h create mode 100644 MultiColumnTableView/MultiColumnTableViewAppDelegate.m create mode 100644 MultiColumnTableView/MultiColumnTableViewViewController.h create mode 100644 MultiColumnTableView/MultiColumnTableViewViewController.m create mode 100644 MultiColumnTableView/UIView+AddLine.h create mode 100644 MultiColumnTableView/UIView+AddLine.m create mode 100644 MultiColumnTableView/en.lproj/InfoPlist.strings create mode 100644 MultiColumnTableView/en.lproj/MainWindow.xib create mode 100644 MultiColumnTableView/en.lproj/MultiColumnTableViewViewController.xib create mode 100644 MultiColumnTableView/main.m create mode 100644 README diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..09089be --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +project.xcuserdata/ +xcuserdata/ +.~ +.*.swp +.DS_Store diff --git a/MultiColumnTableView.xcodeproj/project.pbxproj b/MultiColumnTableView.xcodeproj/project.pbxproj new file mode 100644 index 0000000..0765a96 --- /dev/null +++ b/MultiColumnTableView.xcodeproj/project.pbxproj @@ -0,0 +1,339 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + BB29157A13D6E76000CFA999 /* EWMultiColumnTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = BB29156E13D6E76000CFA999 /* EWMultiColumnTableView.m */; }; + BB29157B13D6E76000CFA999 /* EWMultiColumnTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = BB29157013D6E76000CFA999 /* EWMultiColumnTableViewCell.m */; }; + BB29157C13D6E76000CFA999 /* EWMultiColumnTableViewContentBackgroundView.m in Sources */ = {isa = PBXBuildFile; fileRef = BB29157313D6E76000CFA999 /* EWMultiColumnTableViewContentBackgroundView.m */; }; + BB29157D13D6E76000CFA999 /* EWMultiColumnTableViewBGScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = BB29157513D6E76000CFA999 /* EWMultiColumnTableViewBGScrollView.m */; }; + BB29157E13D6E76000CFA999 /* EWHeaderHighlightLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = BB29157713D6E76000CFA999 /* EWHeaderHighlightLayer.m */; }; + BB29157F13D6E76000CFA999 /* UIView+AddLine.m in Sources */ = {isa = PBXBuildFile; fileRef = BB29157913D6E76000CFA999 /* UIView+AddLine.m */; }; + BBB77CE913A38A850080351B /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BBB77CE813A38A850080351B /* QuartzCore.framework */; }; + BBF25B16139F20A800CE773F /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BBF25B15139F20A800CE773F /* UIKit.framework */; }; + BBF25B18139F20A800CE773F /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BBF25B17139F20A800CE773F /* Foundation.framework */; }; + BBF25B1A139F20A800CE773F /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BBF25B19139F20A800CE773F /* CoreGraphics.framework */; }; + BBF25B20139F20A800CE773F /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = BBF25B1E139F20A800CE773F /* InfoPlist.strings */; }; + BBF25B23139F20A800CE773F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = BBF25B22139F20A800CE773F /* main.m */; }; + BBF25B26139F20A800CE773F /* MultiColumnTableViewAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = BBF25B25139F20A800CE773F /* MultiColumnTableViewAppDelegate.m */; }; + BBF25B29139F20A800CE773F /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = BBF25B27139F20A800CE773F /* MainWindow.xib */; }; + BBF25B2C139F20A800CE773F /* MultiColumnTableViewViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = BBF25B2B139F20A800CE773F /* MultiColumnTableViewViewController.m */; }; + BBF25B2F139F20A800CE773F /* MultiColumnTableViewViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = BBF25B2D139F20A800CE773F /* MultiColumnTableViewViewController.xib */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + BB29156D13D6E76000CFA999 /* EWMultiColumnTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; path = EWMultiColumnTableView.h; sourceTree = ""; }; + BB29156E13D6E76000CFA999 /* EWMultiColumnTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EWMultiColumnTableView.m; sourceTree = ""; }; + BB29156F13D6E76000CFA999 /* EWMultiColumnTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; path = EWMultiColumnTableViewCell.h; sourceTree = ""; }; + BB29157013D6E76000CFA999 /* EWMultiColumnTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EWMultiColumnTableViewCell.m; sourceTree = ""; }; + BB29157113D6E76000CFA999 /* EWMultiColumnTableViewDefaults.h */ = {isa = PBXFileReference; fileEncoding = 4; path = EWMultiColumnTableViewDefaults.h; sourceTree = ""; }; + BB29157213D6E76000CFA999 /* EWMultiColumnTableViewContentBackgroundView.h */ = {isa = PBXFileReference; fileEncoding = 4; path = EWMultiColumnTableViewContentBackgroundView.h; sourceTree = ""; }; + BB29157313D6E76000CFA999 /* EWMultiColumnTableViewContentBackgroundView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EWMultiColumnTableViewContentBackgroundView.m; sourceTree = ""; }; + BB29157413D6E76000CFA999 /* EWMultiColumnTableViewBGScrollView.h */ = {isa = PBXFileReference; fileEncoding = 4; path = EWMultiColumnTableViewBGScrollView.h; sourceTree = ""; }; + BB29157513D6E76000CFA999 /* EWMultiColumnTableViewBGScrollView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EWMultiColumnTableViewBGScrollView.m; sourceTree = ""; }; + BB29157613D6E76000CFA999 /* EWHeaderHighlightLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; path = EWHeaderHighlightLayer.h; sourceTree = ""; }; + BB29157713D6E76000CFA999 /* EWHeaderHighlightLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EWHeaderHighlightLayer.m; sourceTree = ""; }; + BB29157813D6E76000CFA999 /* UIView+AddLine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+AddLine.h"; sourceTree = ""; }; + BB29157913D6E76000CFA999 /* UIView+AddLine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+AddLine.m"; sourceTree = ""; }; + BBB77CE813A38A850080351B /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; + BBF25B11139F20A800CE773F /* MultiColumnTableView.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MultiColumnTableView.app; sourceTree = BUILT_PRODUCTS_DIR; }; + BBF25B15139F20A800CE773F /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + BBF25B17139F20A800CE773F /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + BBF25B19139F20A800CE773F /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + BBF25B1D139F20A800CE773F /* MultiColumnTableView-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "MultiColumnTableView-Info.plist"; sourceTree = ""; }; + BBF25B1F139F20A800CE773F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + BBF25B21139F20A800CE773F /* MultiColumnTableView-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MultiColumnTableView-Prefix.pch"; sourceTree = ""; }; + BBF25B22139F20A800CE773F /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + BBF25B24139F20A800CE773F /* MultiColumnTableViewAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MultiColumnTableViewAppDelegate.h; sourceTree = ""; }; + BBF25B25139F20A800CE773F /* MultiColumnTableViewAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MultiColumnTableViewAppDelegate.m; sourceTree = ""; }; + BBF25B28139F20A800CE773F /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainWindow.xib; sourceTree = ""; }; + BBF25B2A139F20A800CE773F /* MultiColumnTableViewViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MultiColumnTableViewViewController.h; sourceTree = ""; }; + BBF25B2B139F20A800CE773F /* MultiColumnTableViewViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MultiColumnTableViewViewController.m; sourceTree = ""; }; + BBF25B2E139F20A800CE773F /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MultiColumnTableViewViewController.xib; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + BBF25B0E139F20A800CE773F /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + BBB77CE913A38A850080351B /* QuartzCore.framework in Frameworks */, + BBF25B16139F20A800CE773F /* UIKit.framework in Frameworks */, + BBF25B18139F20A800CE773F /* Foundation.framework in Frameworks */, + BBF25B1A139F20A800CE773F /* CoreGraphics.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + BB8C983E13C74ABA00FC2FAC /* MultiColumnTableView */ = { + isa = PBXGroup; + children = ( + BB29156D13D6E76000CFA999 /* EWMultiColumnTableView.h */, + BB29156E13D6E76000CFA999 /* EWMultiColumnTableView.m */, + BB29156F13D6E76000CFA999 /* EWMultiColumnTableViewCell.h */, + BB29157013D6E76000CFA999 /* EWMultiColumnTableViewCell.m */, + BB29157113D6E76000CFA999 /* EWMultiColumnTableViewDefaults.h */, + BB29157213D6E76000CFA999 /* EWMultiColumnTableViewContentBackgroundView.h */, + BB29157313D6E76000CFA999 /* EWMultiColumnTableViewContentBackgroundView.m */, + BB29157413D6E76000CFA999 /* EWMultiColumnTableViewBGScrollView.h */, + BB29157513D6E76000CFA999 /* EWMultiColumnTableViewBGScrollView.m */, + BB29157613D6E76000CFA999 /* EWHeaderHighlightLayer.h */, + BB29157713D6E76000CFA999 /* EWHeaderHighlightLayer.m */, + BB29157813D6E76000CFA999 /* UIView+AddLine.h */, + BB29157913D6E76000CFA999 /* UIView+AddLine.m */, + ); + name = MultiColumnTableView; + sourceTree = ""; + }; + BBF25B06139F20A800CE773F = { + isa = PBXGroup; + children = ( + BBF25B1B139F20A800CE773F /* MultiColumnTableView */, + BBF25B14139F20A800CE773F /* Frameworks */, + BBF25B12139F20A800CE773F /* Products */, + ); + sourceTree = ""; + }; + BBF25B12139F20A800CE773F /* Products */ = { + isa = PBXGroup; + children = ( + BBF25B11139F20A800CE773F /* MultiColumnTableView.app */, + ); + name = Products; + sourceTree = ""; + }; + BBF25B14139F20A800CE773F /* Frameworks */ = { + isa = PBXGroup; + children = ( + BBB77CE813A38A850080351B /* QuartzCore.framework */, + BBF25B15139F20A800CE773F /* UIKit.framework */, + BBF25B17139F20A800CE773F /* Foundation.framework */, + BBF25B19139F20A800CE773F /* CoreGraphics.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + BBF25B1B139F20A800CE773F /* MultiColumnTableView */ = { + isa = PBXGroup; + children = ( + BBF25B24139F20A800CE773F /* MultiColumnTableViewAppDelegate.h */, + BBF25B25139F20A800CE773F /* MultiColumnTableViewAppDelegate.m */, + BBF25B27139F20A800CE773F /* MainWindow.xib */, + BBF25B2A139F20A800CE773F /* MultiColumnTableViewViewController.h */, + BBF25B2B139F20A800CE773F /* MultiColumnTableViewViewController.m */, + BBF25B2D139F20A800CE773F /* MultiColumnTableViewViewController.xib */, + BB8C983E13C74ABA00FC2FAC /* MultiColumnTableView */, + BBF25B1C139F20A800CE773F /* Supporting Files */, + ); + path = MultiColumnTableView; + sourceTree = ""; + }; + BBF25B1C139F20A800CE773F /* Supporting Files */ = { + isa = PBXGroup; + children = ( + BBF25B1D139F20A800CE773F /* MultiColumnTableView-Info.plist */, + BBF25B1E139F20A800CE773F /* InfoPlist.strings */, + BBF25B21139F20A800CE773F /* MultiColumnTableView-Prefix.pch */, + BBF25B22139F20A800CE773F /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + BBF25B10139F20A800CE773F /* MultiColumnTableView */ = { + isa = PBXNativeTarget; + buildConfigurationList = BBF25B32139F20A800CE773F /* Build configuration list for PBXNativeTarget "MultiColumnTableView" */; + buildPhases = ( + BBF25B0D139F20A800CE773F /* Sources */, + BBF25B0E139F20A800CE773F /* Frameworks */, + BBF25B0F139F20A800CE773F /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = MultiColumnTableView; + productName = MultiColumnTableView; + productReference = BBF25B11139F20A800CE773F /* MultiColumnTableView.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + BBF25B08139F20A800CE773F /* Project object */ = { + isa = PBXProject; + attributes = { + ORGANIZATIONNAME = Newegg.com; + }; + buildConfigurationList = BBF25B0B139F20A800CE773F /* Build configuration list for PBXProject "MultiColumnTableView" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = BBF25B06139F20A800CE773F; + productRefGroup = BBF25B12139F20A800CE773F /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + BBF25B10139F20A800CE773F /* MultiColumnTableView */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + BBF25B0F139F20A800CE773F /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + BBF25B20139F20A800CE773F /* InfoPlist.strings in Resources */, + BBF25B29139F20A800CE773F /* MainWindow.xib in Resources */, + BBF25B2F139F20A800CE773F /* MultiColumnTableViewViewController.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + BBF25B0D139F20A800CE773F /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + BBF25B23139F20A800CE773F /* main.m in Sources */, + BBF25B26139F20A800CE773F /* MultiColumnTableViewAppDelegate.m in Sources */, + BBF25B2C139F20A800CE773F /* MultiColumnTableViewViewController.m in Sources */, + BB29157A13D6E76000CFA999 /* EWMultiColumnTableView.m in Sources */, + BB29157B13D6E76000CFA999 /* EWMultiColumnTableViewCell.m in Sources */, + BB29157C13D6E76000CFA999 /* EWMultiColumnTableViewContentBackgroundView.m in Sources */, + BB29157D13D6E76000CFA999 /* EWMultiColumnTableViewBGScrollView.m in Sources */, + BB29157E13D6E76000CFA999 /* EWHeaderHighlightLayer.m in Sources */, + BB29157F13D6E76000CFA999 /* UIView+AddLine.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + BBF25B1E139F20A800CE773F /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + BBF25B1F139F20A800CE773F /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; + BBF25B27139F20A800CE773F /* MainWindow.xib */ = { + isa = PBXVariantGroup; + children = ( + BBF25B28139F20A800CE773F /* en */, + ); + name = MainWindow.xib; + sourceTree = ""; + }; + BBF25B2D139F20A800CE773F /* MultiColumnTableViewViewController.xib */ = { + isa = PBXVariantGroup; + children = ( + BBF25B2E139F20A800CE773F /* en */, + ); + name = MultiColumnTableViewViewController.xib; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + BBF25B30139F20A800CE773F /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_UNIVERSAL_IPHONE_OS)"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = DEBUG; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_VERSION = com.apple.compilers.llvmgcc42; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 4.3; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = 2; + }; + name = Debug; + }; + BBF25B31139F20A800CE773F /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_UNIVERSAL_IPHONE_OS)"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_VERSION = com.apple.compilers.llvmgcc42; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 4.3; + OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = 2; + }; + name = Release; + }; + BBF25B33139F20A800CE773F /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "MultiColumnTableView/MultiColumnTableView-Prefix.pch"; + INFOPLIST_FILE = "MultiColumnTableView/MultiColumnTableView-Info.plist"; + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = app; + }; + name = Debug; + }; + BBF25B34139F20A800CE773F /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = YES; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "MultiColumnTableView/MultiColumnTableView-Prefix.pch"; + INFOPLIST_FILE = "MultiColumnTableView/MultiColumnTableView-Info.plist"; + PRODUCT_NAME = "$(TARGET_NAME)"; + VALIDATE_PRODUCT = YES; + WRAPPER_EXTENSION = app; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + BBF25B0B139F20A800CE773F /* Build configuration list for PBXProject "MultiColumnTableView" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BBF25B30139F20A800CE773F /* Debug */, + BBF25B31139F20A800CE773F /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + BBF25B32139F20A800CE773F /* Build configuration list for PBXNativeTarget "MultiColumnTableView" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BBF25B33139F20A800CE773F /* Debug */, + BBF25B34139F20A800CE773F /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = BBF25B08139F20A800CE773F /* Project object */; +} diff --git a/MultiColumnTableView.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/MultiColumnTableView.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..ce3e282 --- /dev/null +++ b/MultiColumnTableView.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/MultiColumnTableView/EWHeaderHighlightLayer.h b/MultiColumnTableView/EWHeaderHighlightLayer.h new file mode 100644 index 0000000..7f6cd3b --- /dev/null +++ b/MultiColumnTableView/EWHeaderHighlightLayer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 Eli Wang + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + + +#import +#import + +@interface EWHeaderHighlightLayer : CALayer { + +} + +@end diff --git a/MultiColumnTableView/EWHeaderHighlightLayer.m b/MultiColumnTableView/EWHeaderHighlightLayer.m new file mode 100644 index 0000000..28e0586 --- /dev/null +++ b/MultiColumnTableView/EWHeaderHighlightLayer.m @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2011 Eli Wang + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + + +#import "EWHeaderHighlightLayer.h" + + +@implementation EWHeaderHighlightLayer + +- (void)drawInContext:(CGContextRef)ctx +{ + CGContextSetRGBStrokeColor(ctx, 0.0f, 1.0f, 0.0f, 1.0f); + CGContextMoveToPoint(ctx, 0.0f, 0.0f); + CGContextSetLineWidth(ctx, 4.0f); + CGContextAddLineToPoint(ctx, self.frame.size.width, self.frame.size.height); + CGContextStrokePath(ctx); +} + +@end diff --git a/MultiColumnTableView/EWMultiColumnTableView.h b/MultiColumnTableView/EWMultiColumnTableView.h new file mode 100644 index 0000000..2eca0fb --- /dev/null +++ b/MultiColumnTableView/EWMultiColumnTableView.h @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2011 Eli Wang + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + + +#import +#import +#import "EWMultiColumnTableViewContentBackgroundView.h" +#import "EWMultiColumnTableViewDefaults.h" +#import "EWMultiColumnTableViewBGScrollView.h" + +@protocol EWMultiColumnTableViewDataSource; + + + +@interface EWMultiColumnTableView : UIView { + BOOL respondsToReuseIdAtIndexPath; + BOOL respondsToNumberOfSections; + + BOOL respondsToHeightForCell; + BOOL respondsToHeightForHeaderCell; + BOOL respondsToLeftHeaderCell; + BOOL respondsToWidthForHeaderCell; + BOOL respondsToWidthForColumn; + + BOOL respondsToHeightForSectionHeaderCell; + BOOL respondsToHeightForHeaderCellInSectionHeader; + + BOOL respondsToSetContentForHeaderCellAtRow; + BOOL respondsToHeaderCellForColumn; + BOOL respondsToSetContentForHeaderCellAtColumn; + BOOL respondsToHeightForTopHeaderCell; + + NSInteger selectedColumn; + + EWMultiColumnTableViewBGScrollView *scrlView; + UITableView *headerTblView; + EWMultiColumnTableViewContentBackgroundView *tblView; + + // Keep if or not each section is folded. YES for folded, NO for expanded. + NSMutableArray *sectionFoldingStatus; + NSMutableArray *indexPathTable; + + UIView *tblViewHeader; + + CALayer *highlightColumnLayer; +} + +@property (nonatomic, assign) id dataSource; + +@property (nonatomic, assign) CGFloat cellHeight; +@property (nonatomic, assign) CGFloat cellWidth; +@property (nonatomic, assign) CGFloat topHeaderHeight; +@property (nonatomic, assign) CGFloat leftHeaderWidth; +@property (nonatomic, assign) CGFloat sectionHeaderHeight; +@property (nonatomic, assign) CGFloat boldSeperatorLineWidth; +@property (nonatomic, assign) CGFloat normalSeperatorLineWidth; + +@property (nonatomic, retain) UIColor *boldSeperatorLineColor; +@property (nonatomic, retain) UIColor *normalSeperatorLineColor; + +@property (nonatomic, retain) UIColor *leftHeaderBackgroundColor; +@property (nonatomic, retain) UIColor *sectionHeaderBackgroundColor; + +@property (nonatomic, retain) UIColor *topHeaderBackgroundColor; + +@property (nonatomic, assign) BOOL sectionFoldedByDefault; +@property (nonatomic, assign) BOOL sectionHeaderEnabled; + +- (void)reloadData; +- (BOOL)sectionIsFolded:(NSInteger)section; + +@end + + + +@protocol EWMultiColumnTableViewDataSource + +- (UIView *)tableView:(EWMultiColumnTableView *)tableView cellForIndexPath:(NSIndexPath *)indexPath column:(NSInteger)col; +- (void)tableView:(EWMultiColumnTableView *)tableView setContentForCell:(UIView *)cell indexPath:(NSIndexPath *)indexPath column:(NSInteger)col; +- (NSInteger)tableView:(EWMultiColumnTableView *)tableView numberOfRowsInSection:(NSInteger)section; +- (NSInteger)numberOfColumnsInTableView:(EWMultiColumnTableView *)tableView; + + +@optional + +- (CGFloat)tableView:(EWMultiColumnTableView *)tableView heightForCellAtIndexPath:(NSIndexPath *)indexPath column:(NSInteger)column; + +- (CGFloat)tableView:(EWMultiColumnTableView *)tableView widthForColumn:(NSInteger)column; + +// If not implemented, a default cell id will be given. +- (NSString *)tableView:(EWMultiColumnTableView *)tableView reuseIdForIndexPath:(NSIndexPath *)multiColIndexPath; + +#pragma mark - Header Cell +#pragma mark height and width +- (CGFloat)tableView:(EWMultiColumnTableView *)tableView heightForHeaderCellAtIndexPath:(NSIndexPath *)indexPath; +// Top header row +- (CGFloat)heightForHeaderCellOfTableView:(EWMultiColumnTableView *)tableView; +// Left header column +- (CGFloat)widthForHeaderCellOfTableView:(EWMultiColumnTableView *)tableView; + +#pragma mark cell and content +// Create a new header cell in left +- (UIView *)tableView:(EWMultiColumnTableView *)tableView headerCellForIndexPath:(NSIndexPath *)indexPath; +// set content for a resuable header cell +- (void)tableView:(EWMultiColumnTableView *)tableView setContentForHeaderCell:(UIView *)cell atIndexPath:(NSIndexPath *)multiColIndexPath; + +- (UIView *)tableView:(EWMultiColumnTableView *)tableView headerCellForColumn:(NSInteger)col; +- (void)tableView:(EWMultiColumnTableView *)tableView setContentForHeaderCell:(UIView *)cell atColumn:(NSInteger)col; +- (UIView *)topleftHeaderCellOfTableView:(EWMultiColumnTableView *)tableView; + + + + +#pragma mark - Action callback +- (void)tableView:(EWMultiColumnTableView *)tableView swapDataOfColumn:(NSInteger)col1 andColumn:(NSInteger)col2; + + + + +#pragma mark - Section and section header + +- (NSInteger)numberOfSectionsInTableView:(EWMultiColumnTableView *)tableView; + +#pragma mark section header normal cell +// new cell +- (UIView *)tableView:(EWMultiColumnTableView *)tableView sectionHeaderCellForSection:(NSInteger)section column:(NSInteger)col; +// set content +- (void)tableView:(EWMultiColumnTableView *)tableView setContentForSectionHeaderCell:(UIView *)cell section:(NSInteger)section column:(NSInteger)col; +// height +- (CGFloat)tableView:(EWMultiColumnTableView *)tableView heightForSectionHeaderCellAtSection:(NSInteger)section column:(NSInteger)col; + +#pragma mark table header in section header +// new cell +- (UIView *)tableView:(EWMultiColumnTableView *)tableView headerCellInSectionHeaderForSection:(NSInteger)section; +- (void)tableView:(EWMultiColumnTableView *)tableView setContentForHeaderCellInSectionHeader:(UIView *)cell AtSection:(NSInteger)section; +// height +- (CGFloat)tableView:(EWMultiColumnTableView *)tableView heightForHeaderCellInSectionHeaderAtSection:(NSInteger)section; + +@end diff --git a/MultiColumnTableView/EWMultiColumnTableView.m b/MultiColumnTableView/EWMultiColumnTableView.m new file mode 100644 index 0000000..04be254 --- /dev/null +++ b/MultiColumnTableView/EWMultiColumnTableView.m @@ -0,0 +1,847 @@ +/* + * Copyright (c) 2011 Eli Wang + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + + +#import "EWMultiColumnTableView.h" +#import +#import "EWHeaderHighlightLayer.h" +#import "EWMultiColumnTableViewCell.h" +#import "UIView+AddLine.h" + + +#define HeaderCellTag -1 +#define AddHeightTo(v, h) { CGRect f = v.frame; f.size.height += h; v.frame = f; } + +@interface EWMultiColumnTableView() + +- (void)adjustWidth; +- (void)setupHeaderTblView; +- (void)rebuildIndexPathTable; +- (void)orientationChanged:(NSNotification *)notification; +- (void)highlightColumn:(NSInteger)col; +- (void)clearHighlightColumn; +- (void)reset; + +- (void)toggleFoldOfSection:(NSInteger)section withRowNumber:(NSInteger)row rowAnimation:(UITableViewRowAnimation)animation; + +- (UITableViewCell *)tblView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath; +- (UITableViewCell *)tblView:(UITableView *)tableView regularCellForRowAtIndexPath:(NSIndexPath *)multiColIndexPath; +- (UITableViewCell *)tblView:(UITableView *)tableView sectionHeaderCellForRowAtIndexPath:(NSIndexPath *)multiColIndexPath; +- (UITableViewCell *)headerTblView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)multiColIndexPath; + +- (NSInteger)numberOfSections; +- (CGFloat)heightForCellAtIndexPath:(NSIndexPath *)indexPath column:(NSInteger)column; +- (CGFloat)widthForColumn:(NSInteger)column; +- (CGFloat)heightForHeaderCellAtIndexPath:(NSIndexPath *)indexPath; +- (CGFloat)heightForTopHeaderCell; +- (CGFloat)widthForLeftHeaderCell; +- (CGFloat)heightForSectionHeaderCellAtSection:(NSInteger)section column:(NSInteger)col; +- (CGFloat)heightForHeaderCellInSectionHeaderAtSection:(NSInteger)section; + + +- (CGRect)highlightRectForColumn:(NSInteger)col; + + +- (void)columnLongPressed:(UILongPressGestureRecognizer *)recognizer; + +- (NSInteger)columnOfPointInTblView:(CGPoint)point; +- (NSMutableArray *)indexPathsOfSection:(NSInteger)section headerRow:(NSInteger)row; +- (void)swapColumn:(NSInteger)col1 andColumn:(NSInteger)col2; + +@end + + + + + + +@implementation EWMultiColumnTableView + +@synthesize dataSource; +@synthesize cellHeight, cellWidth, topHeaderHeight, leftHeaderWidth, sectionHeaderHeight; +@synthesize leftHeaderBackgroundColor, sectionHeaderBackgroundColor, sectionFoldedByDefault; +@synthesize sectionHeaderEnabled; + +@synthesize normalSeperatorLineColor, normalSeperatorLineWidth, boldSeperatorLineColor, boldSeperatorLineWidth; +@synthesize topHeaderBackgroundColor; + + +#pragma constructors and dealloc + +- (id)initWithFrame:(CGRect)frame +{ + if ((self = [super initWithFrame:frame])) { + + self.layer.borderColor = [[UIColor colorWithWhite:EWMultiColumnTable_BorderColorGray alpha:1.0f] CGColor]; + self.layer.cornerRadius = EWMultiColumnTable_CornerRadius; + self.layer.borderWidth = EWMultiColumnTable_BorderWidth; + self.clipsToBounds = YES; + self.backgroundColor = [UIColor clearColor]; + + cellHeight = EWMultiColumnTable_DefaultCellHeight; + cellWidth = EWMultiColumnTable_DefaultCellWidth; + topHeaderHeight = EWMultiColumnTable_DefaultTopHeaderHeight; + leftHeaderWidth = EWMultiColumnTable_DefaultLeftHeaderWidth; + sectionHeaderHeight = EWMultiColumnTable_DefaultSectionHeaderHeight; + + boldSeperatorLineWidth = EWMultiColumnTable_BoldLineWidth; + normalSeperatorLineWidth = EWMultiColumnTable_NormalLineWidth; + self.boldSeperatorLineColor = [UIColor colorWithWhite:EWMultiColumnTable_LineGray alpha:1.0f]; + self.normalSeperatorLineColor = [UIColor colorWithWhite:EWMultiColumnTable_LineGray alpha:1.0f]; + + self.leftHeaderBackgroundColor = [UIColor colorWithWhite:249.0f/255.0f alpha:1.0f]; + self.sectionHeaderBackgroundColor = [UIColor colorWithWhite:241.0f/255.0f alpha:1.0f]; + self.topHeaderBackgroundColor = [UIColor whiteColor]; + sectionFoldedByDefault = NO; + + + selectedColumn = -1; + sectionFoldingStatus = [[NSMutableArray alloc] initWithCapacity:10]; + + scrlView = [[EWMultiColumnTableViewBGScrollView alloc] initWithFrame:self.bounds]; + scrlView.parent = self; +// scrlView.backgroundColor = [UIColor whiteColor]; + scrlView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; + [self addSubview:scrlView]; + + tblView = [[EWMultiColumnTableViewContentBackgroundView alloc] initWithFrame:scrlView.bounds]; + tblView.dataSource = self; + tblView.delegate = self; + tblView.autoresizingMask = UIViewAutoresizingFlexibleHeight; + tblView.separatorStyle = UITableViewCellSeparatorStyleNone; + tblView.backgroundColor = [UIColor clearColor]; + [scrlView addSubview:tblView]; + + UILongPressGestureRecognizer *recognizer = [[[UILongPressGestureRecognizer alloc] + initWithTarget:self action:@selector(columnLongPressed:)] autorelease]; + recognizer.minimumPressDuration = 1.0; + [tblView addGestureRecognizer:recognizer]; + + NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; + [center addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil]; + } + + return self; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [tblView release]; + [headerTblView release]; + [scrlView release]; + [sectionFoldingStatus release]; + [indexPathTable release]; + [highlightColumnLayer release]; + [tblViewHeader release]; + + [leftHeaderBackgroundColor release]; + [sectionHeaderBackgroundColor release]; + [normalSeperatorLineColor release]; + [boldSeperatorLineColor release]; + [topHeaderBackgroundColor release]; + [super dealloc]; +} + +- (void)drawRect:(CGRect)rect +{ + [super drawRect:rect]; + CGContextRef context = UIGraphicsGetCurrentContext(); + + CGContextSetLineWidth(context, boldSeperatorLineWidth); + CGContextSetAllowsAntialiasing(context, 0); + + CGContextSetStrokeColorWithColor(context, [boldSeperatorLineColor CGColor]); + + if (respondsToLeftHeaderCell) { + CGFloat x = [self widthForLeftHeaderCell] + boldSeperatorLineWidth / 2.0f; + CGContextMoveToPoint(context, x, 0.0f); + CGContextAddLineToPoint(context, x, self.frame.size.height); + } + CGContextStrokePath(context); + + +} + +- (void)reloadData +{ + [self reset]; + + + [headerTblView reloadData]; + [tblView reloadData]; + [self adjustWidth]; +} + +- (BOOL)sectionIsFolded:(NSInteger)section +{ + return [[sectionFoldingStatus objectAtIndex:section] boolValue]; +} + +#pragma mark - Properties + +- (void)setDataSource:(id)dataSource_ +{ + if (dataSource != dataSource_) { + dataSource = dataSource_; + + respondsToReuseIdAtIndexPath = [dataSource_ respondsToSelector:@selector(tableView:reuseIdForIndexPath:)]; + respondsToNumberOfSections = [dataSource_ respondsToSelector:@selector(numberOfSectionsInTableView:)]; + + respondsToHeightForCell = [dataSource_ respondsToSelector:@selector(tableView:heightForCellAtIndexPath:column:)]; + respondsToLeftHeaderCell = [dataSource_ respondsToSelector:@selector(tableView:headerCellForIndexPath:)]; + respondsToHeightForHeaderCell = [dataSource_ respondsToSelector:@selector(tableView:heightForHeaderCellAtIndexPath:)]; + respondsToWidthForHeaderCell = [dataSource_ respondsToSelector:@selector(widthForHeaderCellOfTableView:)]; + respondsToSetContentForHeaderCellAtRow = [dataSource_ respondsToSelector:@selector(tableView:setContentForHeaderCell:atRow:)]; + respondsToHeaderCellForColumn = [dataSource_ respondsToSelector:@selector(tableView:headerCellForColumn:)]; + respondsToSetContentForHeaderCellAtColumn = [dataSource_ respondsToSelector:@selector(tableView:setContentForHeaderCell:atColumn:)]; + respondsToWidthForColumn = [dataSource_ respondsToSelector:@selector(tableView:widthForColumn:)]; + respondsToHeightForTopHeaderCell = [dataSource_ respondsToSelector:@selector(heightForHeaderCellOfTableView:)]; + respondsToHeightForSectionHeaderCell = [dataSource_ respondsToSelector:@selector(tableView:heightForSectionHeaderCellAtSection:column:)]; + respondsToHeightForHeaderCellInSectionHeader = [dataSource_ respondsToSelector:@selector(tableView:heightForHeaderCellInSectionHeaderAtSection:)]; + + // set contentSize of the scrollView and the width of the tableView + [self adjustWidth]; + + // Initialize sectionFoldingStatus + [sectionFoldingStatus release]; + sectionFoldingStatus = [[NSMutableArray alloc] initWithCapacity:[self numberOfSections]]; + for (int i = 0; i < [self numberOfSections]; i++) { + [sectionFoldingStatus addObject:[NSNumber numberWithBool:sectionFoldedByDefault]]; + } + + [self reset]; + + if (respondsToLeftHeaderCell) + [self setupHeaderTblView]; + + } +} + +#pragma mark - UITableViewDataSource & UITableViewDelegate + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + NSInteger numOfRows = 0; + NSInteger numOfSec = [self numberOfSections]; + + + for (int i = 0; i < numOfSec; i++) { + if (sectionHeaderEnabled) + numOfRows++; + + if (!sectionHeaderEnabled || ![[sectionFoldingStatus objectAtIndex:i] boolValue]) + numOfRows += [dataSource tableView:self numberOfRowsInSection:i]; + } + + return numOfRows; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + if (tableView == tblView) { + return [self tblView:tableView cellForRowAtIndexPath:indexPath]; + } else { + return [self headerTblView:tableView cellForRowAtIndexPath:indexPath]; + } +} + +- (UITableViewCell *)tblView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + NSIndexPath *multiColIndexPath = [indexPathTable objectAtIndex:indexPath.row]; + + if (sectionHeaderEnabled && [multiColIndexPath length] == 1) + return [self tblView:tableView sectionHeaderCellForRowAtIndexPath:multiColIndexPath]; + else + return [self tblView:tableView regularCellForRowAtIndexPath:multiColIndexPath]; +} + +- (UITableViewCell *)tblView:(UITableView *)tableView regularCellForRowAtIndexPath:(NSIndexPath *)multiColIndexPath +{ + NSInteger numOfCols = [dataSource numberOfColumnsInTableView:self]; + + static NSString *CellID; + + if (respondsToReuseIdAtIndexPath) + CellID = [dataSource tableView:self reuseIdForIndexPath:multiColIndexPath] ?: @"MultiColumnCell"; + else + CellID = @"MultiColumnCell"; + + EWMultiColumnTableViewCell *cell = (EWMultiColumnTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellID]; + + if (cell == nil) { + cell = [[[EWMultiColumnTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellID] autorelease]; + cell.selectionStyle = UITableViewCellEditingStyleNone; + [cell addBottomLineWithWidth:normalSeperatorLineWidth color:normalSeperatorLineColor]; + } + + NSInteger columnsDiff = numOfCols - [[cell columnCells] count]; + + if (columnsDiff > 0) { + // Add the grid cells - call the delegate method to init the grid cells + CGFloat x = 0.0f; + UIView *lastCol = [[cell columnCells] lastObject]; + if (lastCol) x = lastCol.frame.origin.x + lastCol.frame.size.width; + + for (int i = 0; i < columnsDiff; i++) { + UIView *gridCell = [dataSource tableView:self cellForIndexPath:multiColIndexPath column:i]; + CGRect f = gridCell.frame; + f.origin.x += x; + gridCell.frame = f; + [cell.contentView addSubview:gridCell]; + + CGFloat colWidth = [self widthForColumn:i]; + + x += colWidth + normalSeperatorLineWidth; + [[cell columnCells] addObject:gridCell]; + } + } else if (columnsDiff < 0) { + columnsDiff = -columnsDiff; + for (int i = 0; i < columnsDiff; i++) { + [[[cell columnCells] lastObject] removeFromSuperview]; + [[cell columnCells] removeLastObject]; + } + } + + + // call delegate method to set the cells of the other columns + + for (int i = 0; i < numOfCols; i++) { + [dataSource tableView:self setContentForCell:[[cell columnCells] objectAtIndex:i] + indexPath:multiColIndexPath column:i]; + } + + AddHeightTo(cell, normalSeperatorLineWidth); + + return cell; +} + +- (UITableViewCell *)tblView:(UITableView *)tableView sectionHeaderCellForRowAtIndexPath:(NSIndexPath *)multiColIndexPath +{ + NSInteger numOfCols = [dataSource numberOfColumnsInTableView:self]; + NSInteger section = [multiColIndexPath indexAtPosition:0]; + + static NSString *CellID = @"SectionHeaderCell"; + + EWMultiColumnTableViewCell *cell = (EWMultiColumnTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellID]; + + if (cell == nil) { + cell = [[[EWMultiColumnTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellID] autorelease]; + cell.selectionStyle = UITableViewCellEditingStyleNone; + cell.contentView.backgroundColor = sectionHeaderBackgroundColor; + [cell addBottomLineWithWidth:normalSeperatorLineWidth color:normalSeperatorLineColor]; + } + + NSInteger columnsDiff = numOfCols - [[cell columnCells] count]; + + if (columnsDiff > 0) { + // Add the grid cells - call the delegate method to init the grid cells + CGFloat x = 0.0f; + UIView *lastCol = [[cell columnCells] lastObject]; + if (lastCol) x = lastCol.frame.origin.x + lastCol.frame.size.width; + + for (int i = 0; i < columnsDiff; i++) { + UIView *gridCell = [dataSource tableView:self sectionHeaderCellForSection:section column:i]; + + CGRect f = gridCell.frame; + f.origin.x += x; + gridCell.frame = f; + [cell.contentView addSubview:gridCell]; + + CGFloat colWidth = [self widthForColumn:i]; + + x += colWidth + normalSeperatorLineWidth; + [[cell columnCells] addObject:gridCell]; + } + } else if (columnsDiff < 0) { + columnsDiff = -columnsDiff; + for (int i = 0; i < columnsDiff; i++) { + [[[cell columnCells] lastObject] removeFromSuperview]; + [[cell columnCells] removeLastObject]; + } + } + + + // call delegate method to set the cells of the other columns + + for (int i = 0; i < numOfCols; i++) { + [dataSource tableView:self setContentForSectionHeaderCell:[[cell columnCells] objectAtIndex:i] + section:section column:i]; + } + + AddHeightTo(cell, normalSeperatorLineWidth); + + return cell; +} + +- (UITableViewCell *)headerTblView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + NSIndexPath *multiColIndexPath = [indexPathTable objectAtIndex:indexPath.row]; + static NSString *CellID; + if (sectionHeaderEnabled && [multiColIndexPath length] == 1) + CellID = @"HeaderCellInSectionHeader"; + else + CellID = @"HeaderCell"; + + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellID]; + + if (cell == nil) { + cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellID] autorelease]; + cell.selectionStyle = UITableViewCellEditingStyleNone; + + UIView *headerCellView; + + if (sectionHeaderEnabled && [multiColIndexPath length] == 1) { + headerCellView = [dataSource tableView:self headerCellInSectionHeaderForSection:[multiColIndexPath indexAtPosition:0]]; + cell.contentView.backgroundColor = sectionHeaderBackgroundColor; + } else { + headerCellView = [dataSource tableView:self headerCellForIndexPath:indexPath]; + } + + headerCellView.tag = HeaderCellTag; + [cell.contentView addSubview:headerCellView]; + [cell addBottomLineWithWidth:normalSeperatorLineWidth color:normalSeperatorLineColor]; + } + + if (sectionHeaderEnabled && [multiColIndexPath length] == 1) + [dataSource tableView:self setContentForHeaderCellInSectionHeader:[cell viewWithTag:HeaderCellTag] + AtSection:[multiColIndexPath indexAtPosition:0]]; + else + [dataSource tableView:self setContentForHeaderCell:[cell viewWithTag:HeaderCellTag] + atIndexPath:multiColIndexPath]; + + AddHeightTo(cell, normalSeperatorLineWidth); + + return cell; +} + +- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath +{ + NSIndexPath *multiColIndexPath = [indexPathTable objectAtIndex:indexPath.row]; + + if (sectionHeaderEnabled && [multiColIndexPath length] == 1) { + // Calculate section header + + NSInteger section = [multiColIndexPath indexAtPosition:0]; + CGFloat height = [self heightForHeaderCellInSectionHeaderAtSection:section]; + + // calculate the height of the cells in this row + NSInteger numOfCols = [dataSource numberOfColumnsInTableView:self]; + for (int i = 0; i < numOfCols; i++) { + // call delegate method to calculate the individual cell + CGFloat h = [self heightForSectionHeaderCellAtSection:section column:i]; + + if (h > height) height = h; + } + + // return the Maximum of them. + return height + normalSeperatorLineWidth; + + } else { + // Calculate normal row + + CGFloat height = [self heightForHeaderCellAtIndexPath:multiColIndexPath]; + + // calculate the height of the cells in this row + NSInteger numOfCols = [dataSource numberOfColumnsInTableView:self]; + for (int i = 0; i < numOfCols; i++) { + // call delegate method to calculate the individual cell + CGFloat h = [self heightForCellAtIndexPath:multiColIndexPath column:i]; + + if (h > height) height = h; + } + + // return the Maximum of them. + return height + normalSeperatorLineWidth; + } +} + +- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section +{ + if (tableView == tblView) { + [tblViewHeader release]; + tblViewHeader = [[UIView alloc] initWithFrame:CGRectZero]; + tblViewHeader.clipsToBounds = YES; + tblViewHeader.backgroundColor = [UIColor clearColor]; + + NSInteger cols = [dataSource numberOfColumnsInTableView:self]; + CGFloat x = 0.0f, height = 0.0f; + + for (int i = 0; i < cols; i++) { + UIView *headerCell = [dataSource tableView:self headerCellForColumn:i]; + CGRect f = headerCell.frame; + f.origin.x = x; + headerCell.frame = f; + [tblViewHeader addSubview:headerCell]; + height = MAX(height, f.size.height); + + x += [self widthForColumn:i] + normalSeperatorLineWidth; + } + + CGRect f = tblViewHeader.frame; + CGFloat width = MAX(x - normalSeperatorLineWidth, tblView.frame.size.width); + f.size = CGSizeMake(width, height); + tblViewHeader.frame = f; + tblViewHeader.backgroundColor = self.topHeaderBackgroundColor; + + [tblViewHeader addBottomLineWithWidth:boldSeperatorLineWidth color:boldSeperatorLineColor]; + + return tblViewHeader; + } else { + if ([dataSource respondsToSelector:@selector(topleftHeaderCellOfTableView:)]) { + UIView *header = [dataSource topleftHeaderCellOfTableView:self]; + + UIView *container = [[[UIView alloc] initWithFrame:header.frame] autorelease]; + CGRect f = container.frame; + f.size.height = [self heightForTopHeaderCell]; + container.frame = f; + + [container addSubview:header]; + [container addBottomLineWithWidth:boldSeperatorLineWidth color:boldSeperatorLineColor]; + + return container; + } else { + return [[[UIView alloc] initWithFrame:CGRectZero] autorelease]; + } + } +} + +- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section +{ + return [self heightForTopHeaderCell] + boldSeperatorLineWidth; +} + +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ + if (tableView == headerTblView) { + NSIndexPath *multiColIndexPath = [indexPathTable objectAtIndex:indexPath.row]; + if (sectionHeaderEnabled && [multiColIndexPath length] == 1) { + [self toggleFoldOfSection:[multiColIndexPath indexAtPosition:0] + withRowNumber:indexPath.row rowAnimation:UITableViewRowAnimationTop]; + } + + } +} + +#pragma mark - UIScrollViewDelegate + +- (void)scrollViewDidScroll:(UIScrollView *)scrollView +{ + UIScrollView *target; + if (scrollView == tblView) + target = headerTblView; + else + target = tblView; + + target.contentOffset = scrollView.contentOffset; +} + + + +#pragma mark - Private Methods + +#pragma mark Procedures + +- (void)reset +{ + NSInteger numOfSec = [self numberOfSections]; + if (sectionHeaderEnabled && [sectionFoldingStatus count] == 0) { + for (int i = 0; i < numOfSec; i++) { + [sectionFoldingStatus addObject:[NSNumber numberWithBool:sectionFoldedByDefault]]; + } + } + + [indexPathTable release]; + indexPathTable = [[NSMutableArray alloc] initWithCapacity:numOfSec * 5]; + [self rebuildIndexPathTable]; + [scrlView redraw]; + +} + +- (void)adjustWidth +{ + CGFloat width = 0.0f; + NSInteger cols = [dataSource numberOfColumnsInTableView:self]; + for (int i = 0; i < cols; i++) { + width += [self widthForColumn:i] + normalSeperatorLineWidth; + } + + width -= normalSeperatorLineWidth; + scrlView.contentSize = CGSizeMake(width, 0.0f); + + CGRect f = tblView.frame; + f.size.width = MAX(self.frame.size.width - [self widthForLeftHeaderCell], width); + tblView.frame = f; +} + +- (void)setupHeaderTblView +{ + CGFloat headerCellWidth = [self widthForLeftHeaderCell]; + + [headerTblView removeFromSuperview]; + [headerTblView release]; + headerTblView = [[UITableView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, headerCellWidth, self.frame.size.height)]; + headerTblView.autoresizingMask = UIViewAutoresizingFlexibleHeight; + headerTblView.delegate = self; + headerTblView.dataSource = self; + headerTblView.separatorStyle = UITableViewCellSeparatorStyleNone; + headerTblView.showsVerticalScrollIndicator = NO; + headerTblView.backgroundColor = leftHeaderBackgroundColor; + [self addSubview:headerTblView]; + + scrlView.frame = CGRectMake(headerCellWidth + boldSeperatorLineWidth, 0.0f, + self.frame.size.width - headerCellWidth - boldSeperatorLineWidth, self.frame.size.height); +} + +- (void)rebuildIndexPathTable +{ + [indexPathTable removeAllObjects]; + + NSInteger numOfSec = [self numberOfSections]; + for (int i = 0; i < numOfSec; i++) { + if (sectionHeaderEnabled) + [indexPathTable addObject:[NSIndexPath indexPathWithIndex:i]]; + + if (!sectionHeaderEnabled || ![[sectionFoldingStatus objectAtIndex:i] boolValue]) { + NSInteger numOfRows = [dataSource tableView:self numberOfRowsInSection:i]; + for (int j = 0; j < numOfRows; j++) { + [indexPathTable addObject:[NSIndexPath indexPathForRow:j inSection:i]]; + } + } + } + +} + +- (void)swapColumn:(NSInteger)col1 andColumn:(NSInteger)col2 +{ + [dataSource tableView:self swapDataOfColumn:col1 andColumn:col2]; + [tblView reloadData]; + [scrlView redraw]; +} + +- (void)toggleFoldOfSection:(NSInteger)section withRowNumber:(NSInteger)row rowAnimation:(UITableViewRowAnimation)animation +{ + @synchronized(self) { + BOOL folded = [[sectionFoldingStatus objectAtIndex:section] boolValue]; + [sectionFoldingStatus replaceObjectAtIndex:section withObject:[NSNumber numberWithBool:!folded]]; + + NSMutableArray *indexPaths = [self indexPathsOfSection: section headerRow:row]; + [self rebuildIndexPathTable]; + + [tblView beginUpdates]; + [headerTblView beginUpdates]; + if (folded) { + [tblView insertRowsAtIndexPaths:indexPaths withRowAnimation:animation]; + [headerTblView insertRowsAtIndexPaths:indexPaths withRowAnimation:animation]; + } else { + [tblView deleteRowsAtIndexPaths:indexPaths withRowAnimation:animation]; + [headerTblView deleteRowsAtIndexPaths:indexPaths withRowAnimation:animation]; + } + [tblView endUpdates]; + [headerTblView endUpdates]; + } + +} + +- (void)highlightColumn:(NSInteger)col +{ + if (highlightColumnLayer == nil) { + highlightColumnLayer = [[CALayer alloc] init]; + highlightColumnLayer.borderColor = [[UIColor colorWithRed:232.0f/255.0f green:142.0f/255.0f blue:20.0f/255.0f alpha:1.0f] CGColor]; + highlightColumnLayer.borderWidth = ColumnHighlightWidth; + highlightColumnLayer.shadowRadius = 5.0f; + highlightColumnLayer.shadowOpacity = 0.5f; + [self.layer addSublayer:highlightColumnLayer]; + } + + + [CATransaction begin]; + [CATransaction setValue: (id) kCFBooleanTrue forKey: kCATransactionDisableActions]; + highlightColumnLayer.frame = [self highlightRectForColumn:selectedColumn]; + [CATransaction commit]; + + +} + +- (void)clearHighlightColumn +{ + [highlightColumnLayer removeFromSuperlayer]; + [highlightColumnLayer release]; + highlightColumnLayer = nil; +} + +#pragma mark Computations + + +- (CGFloat)heightForCellAtIndexPath:(NSIndexPath *)indexPath column:(NSInteger)column +{ + if (respondsToHeightForCell) + return [dataSource tableView:self heightForCellAtIndexPath:indexPath column:column]; + else + return cellHeight; +} + +- (CGFloat)widthForColumn:(NSInteger)column +{ + if (respondsToWidthForColumn) + return [dataSource tableView:self widthForColumn:column]; + else + return cellWidth; +} + +- (CGFloat)heightForHeaderCellAtIndexPath:(NSIndexPath *)indexPath; +{ + if (respondsToHeightForHeaderCell) + return [dataSource tableView:self heightForHeaderCellAtIndexPath:indexPath]; + else + return sectionHeaderHeight; +} + +- (CGFloat)heightForTopHeaderCell +{ + if (respondsToHeightForTopHeaderCell) + return [dataSource heightForHeaderCellOfTableView:self]; + else + return topHeaderHeight; +} + +- (CGFloat)widthForLeftHeaderCell +{ + if (respondsToLeftHeaderCell) { + if (respondsToWidthForHeaderCell) + return [dataSource widthForHeaderCellOfTableView:self]; + else + return leftHeaderWidth; + } else { + return 0.0f; + } +} + +- (CGFloat)heightForSectionHeaderCellAtSection:(NSInteger)section column:(NSInteger)col +{ + if (respondsToHeightForSectionHeaderCell) + return [dataSource tableView:self heightForSectionHeaderCellAtSection:section column:col]; + else + return sectionHeaderHeight; +} + +- (CGFloat)heightForHeaderCellInSectionHeaderAtSection:(NSInteger)section +{ + if (respondsToHeightForHeaderCellInSectionHeader) + return [dataSource tableView:self heightForHeaderCellInSectionHeaderAtSection:section]; + else + return cellHeight; +} + + +- (NSInteger)numberOfSections +{ + if (respondsToNumberOfSections) + return [dataSource numberOfSectionsInTableView:self]; + else + return 1; +} + +- (NSInteger)columnOfPointInTblView:(CGPoint)point +{ + CGFloat x = point.x, w = 0.0f; + NSInteger cols = [dataSource numberOfColumnsInTableView:self]; + + for (int i = 0; i < cols; i++) { + w += [self widthForColumn:i]; + if (x < w) + return i; + } + + return -1; +} + +- (NSMutableArray *)indexPathsOfSection:(NSInteger)section headerRow:(NSInteger)row +{ + NSInteger numberOfRows = [dataSource tableView:self numberOfRowsInSection:section]; + NSMutableArray *indexPaths = [NSMutableArray arrayWithCapacity:10]; + for (int i = 1; i <= numberOfRows; i++) { + [indexPaths addObject:[NSIndexPath indexPathForRow:row + i inSection:0]]; + } + return indexPaths; +} + +- (CGRect)highlightRectForColumn:(NSInteger)col +{ + CGFloat x = headerTblView.frame.size.width - scrlView.contentOffset.x + boldSeperatorLineWidth; + for (int i = 0; i < col; i++) { + x += [self widthForColumn:i] + normalSeperatorLineWidth; + } + + CGFloat w = [self widthForColumn:col]; + + return CGRectMake(x, EWMultiColumnTable_BorderWidth, w, self.frame.size.height - EWMultiColumnTable_BorderWidth * 2); +} + +#pragma mark Event Handelers + +- (void)orientationChanged:(NSNotification *)notification +{ + [self adjustWidth]; +} + +- (void)columnLongPressed:(UILongPressGestureRecognizer *)recognizer +{ + if ([dataSource respondsToSelector:@selector(tableView:swapDataOfColumn:andColumn:)]) { + switch (recognizer.state) { + case UIGestureRecognizerStateBegan: { + // create the drag overlay layer + CGPoint point = [recognizer locationInView:scrlView]; + selectedColumn = [self columnOfPointInTblView:point]; + + // Highlight the column + [self highlightColumn:selectedColumn]; + break; + } case UIGestureRecognizerStateChanged: { + // move the dragging layer to the destination. + CGPoint point = [recognizer locationInView:scrlView]; + NSInteger currentCol = [self columnOfPointInTblView:point]; + + if (currentCol >= 0 && currentCol != selectedColumn) { + [self swapColumn:selectedColumn andColumn:currentCol]; + selectedColumn = currentCol; + [self highlightColumn:selectedColumn]; + } + + break; + } + case UIGestureRecognizerStateEnded: + case UIGestureRecognizerStateCancelled: { + [self clearHighlightColumn]; + selectedColumn = -1; + // swap the column + break; + } + default: + NSLog(@"recognizer.state: %d", recognizer.state); + break; + } + } + +} + +@end diff --git a/MultiColumnTableView/EWMultiColumnTableViewBGScrollView.h b/MultiColumnTableView/EWMultiColumnTableViewBGScrollView.h new file mode 100644 index 0000000..6c631a8 --- /dev/null +++ b/MultiColumnTableView/EWMultiColumnTableViewBGScrollView.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2011 Eli Wang + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + + +#import + +@class EWMultiColumnTableView; + + +@interface EWMultiColumnTableViewBGScrollView : UIScrollView { + NSMutableArray *lines; +} + +@property (nonatomic, assign) EWMultiColumnTableView *parent; + +// This method will draw the vertical lines. It adds UIViews as lines ABOVE all views. call it after the table reloads +// to make sure the lines visible +- (void)redraw; + +@end diff --git a/MultiColumnTableView/EWMultiColumnTableViewBGScrollView.m b/MultiColumnTableView/EWMultiColumnTableViewBGScrollView.m new file mode 100644 index 0000000..1bbe251 --- /dev/null +++ b/MultiColumnTableView/EWMultiColumnTableViewBGScrollView.m @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2011 Eli Wang + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + + +#import "EWMultiColumnTableViewBGScrollView.h" +#import "EWMultiColumnTableView.h" +#import +#import "UIView+AddLine.h" + + +@implementation EWMultiColumnTableViewBGScrollView + +@synthesize parent; + +- (void)dealloc +{ + [lines release]; + [super dealloc]; +} + +- (void)redraw +{ + if (lines == nil) lines = [[NSMutableArray alloc] initWithCapacity:10]; + + for (UIView *v in lines) { + [v removeFromSuperview]; + } + + [lines removeAllObjects]; + + UIView *v = [[[UIView alloc] initWithFrame:CGRectMake(0.0f - parent.normalSeperatorLineWidth, 0.0f, + parent.normalSeperatorLineWidth, self.frame.size.height)] autorelease]; + v.backgroundColor = parent.normalSeperatorLineColor; + [self addSubview:v]; + [lines addObject:v]; + + CGFloat x = 0.0f; + for (int i = 0; i < [parent.dataSource numberOfColumnsInTableView:parent]; i++) { + CGFloat width; + if ([parent.dataSource respondsToSelector:@selector(tableView:widthForColumn:)]) + width = [parent.dataSource tableView:parent widthForColumn:i]; + else + width = parent.cellWidth; + + x += width + parent.normalSeperatorLineWidth; + v = [self addVerticalLineWithWidth:parent.normalSeperatorLineWidth color:parent.normalSeperatorLineColor atX:x]; + [lines addObject:v]; + } + +} + +@end diff --git a/MultiColumnTableView/EWMultiColumnTableViewCell.h b/MultiColumnTableView/EWMultiColumnTableViewCell.h new file mode 100644 index 0000000..78d3fba --- /dev/null +++ b/MultiColumnTableView/EWMultiColumnTableViewCell.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2011 Eli Wang + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + + +#import + + +@interface EWMultiColumnTableViewCell : UITableViewCell { + +} + +@property (nonatomic, readonly) NSMutableArray *columnCells; + +@end diff --git a/MultiColumnTableView/EWMultiColumnTableViewCell.m b/MultiColumnTableView/EWMultiColumnTableViewCell.m new file mode 100644 index 0000000..d61332f --- /dev/null +++ b/MultiColumnTableView/EWMultiColumnTableViewCell.m @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2011 Eli Wang + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + + +#import "EWMultiColumnTableViewCell.h" + + +@implementation EWMultiColumnTableViewCell + +@synthesize columnCells; + +- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier +{ + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + if (self) { + columnCells = [[NSMutableArray alloc] initWithCapacity:5]; + } + return self; +} + +- (void)dealloc +{ + [columnCells release]; + [super dealloc]; +} + +@end diff --git a/MultiColumnTableView/EWMultiColumnTableViewContentBackgroundView.h b/MultiColumnTableView/EWMultiColumnTableViewContentBackgroundView.h new file mode 100644 index 0000000..d7f0670 --- /dev/null +++ b/MultiColumnTableView/EWMultiColumnTableViewContentBackgroundView.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2011 Eli Wang + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + + +#import + +#define ColumnHighlightWidth 4.0f + + +@interface EWMultiColumnTableViewContentBackgroundView : UITableView { + +} + +@property (nonatomic, assign) CGRect highlightedRect; + +@end diff --git a/MultiColumnTableView/EWMultiColumnTableViewContentBackgroundView.m b/MultiColumnTableView/EWMultiColumnTableViewContentBackgroundView.m new file mode 100644 index 0000000..78de556 --- /dev/null +++ b/MultiColumnTableView/EWMultiColumnTableViewContentBackgroundView.m @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2011 Eli Wang + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + + +#import "EWMultiColumnTableViewContentBackgroundView.h" + + +@implementation EWMultiColumnTableViewContentBackgroundView + +@synthesize highlightedRect; + + +@end diff --git a/MultiColumnTableView/EWMultiColumnTableViewDefaults.h b/MultiColumnTableView/EWMultiColumnTableViewDefaults.h new file mode 100644 index 0000000..d779203 --- /dev/null +++ b/MultiColumnTableView/EWMultiColumnTableViewDefaults.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2011 Eli Wang + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + + +#define EWMultiColumnTable_CornerRadius 3.0f +#define EWMultiColumnTable_BorderWidth 1.0f +#define EWMultiColumnTable_BorderColorGray 212.0f/255.0f + +#define EWMultiColumnTable_DefaultCellHeight 31.0f +#define EWMultiColumnTable_DefaultCellWidth 252.0f +#define EWMultiColumnTable_DefaultTopHeaderHeight 298.0f +#define EWMultiColumnTable_DefaultLeftHeaderWidth 111.0f +#define EWMultiColumnTable_DefaultSectionHeaderHeight 31.0f +#define EWMultiColumnTable_DefaultHeaderCellWidth 80.0f +#define EWMultiColumnTable_BoldLineWidth 3.0f +#define EWMultiColumnTable_NormalLineWidth 1.0f +#define EWMultiColumnTable_LineGray 223.0f/255.0f diff --git a/MultiColumnTableView/MultiColumnTableView-Info.plist b/MultiColumnTableView/MultiColumnTableView-Info.plist new file mode 100644 index 0000000..3b7bf94 --- /dev/null +++ b/MultiColumnTableView/MultiColumnTableView-Info.plist @@ -0,0 +1,39 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + ${PRODUCT_NAME} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + + CFBundleIdentifier + com.yourcompany.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + NSMainNibFile + MainWindow + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/MultiColumnTableView/MultiColumnTableView-Prefix.pch b/MultiColumnTableView/MultiColumnTableView-Prefix.pch new file mode 100644 index 0000000..aa8ef49 --- /dev/null +++ b/MultiColumnTableView/MultiColumnTableView-Prefix.pch @@ -0,0 +1,14 @@ +// +// Prefix header for all source files of the 'MultiColumnTableView' target in the 'MultiColumnTableView' project +// + +#import + +#ifndef __IPHONE_3_0 +#warning "This project uses features only available in iPhone SDK 3.0 and later." +#endif + +#ifdef __OBJC__ + #import + #import +#endif diff --git a/MultiColumnTableView/MultiColumnTableViewAppDelegate.h b/MultiColumnTableView/MultiColumnTableViewAppDelegate.h new file mode 100644 index 0000000..0307464 --- /dev/null +++ b/MultiColumnTableView/MultiColumnTableViewAppDelegate.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2011 Eli Wang + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + + +#import + +@class MultiColumnTableViewViewController; + +@interface MultiColumnTableViewAppDelegate : NSObject { + +} + +@property (nonatomic, retain) IBOutlet UIWindow *window; + +@property (nonatomic, retain) IBOutlet MultiColumnTableViewViewController *viewController; + +@end diff --git a/MultiColumnTableView/MultiColumnTableViewAppDelegate.m b/MultiColumnTableView/MultiColumnTableViewAppDelegate.m new file mode 100644 index 0000000..2cb9d05 --- /dev/null +++ b/MultiColumnTableView/MultiColumnTableViewAppDelegate.m @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2011 Eli Wang + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + + +#import "MultiColumnTableViewAppDelegate.h" + +#import "MultiColumnTableViewViewController.h" + +@implementation MultiColumnTableViewAppDelegate + + +@synthesize window=_window; + +@synthesize viewController=_viewController; + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + // Override point for customization after application launch. + + 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:. + */ +} + +- (void)dealloc +{ + [_window release]; + [_viewController release]; + [super dealloc]; +} + +@end diff --git a/MultiColumnTableView/MultiColumnTableViewViewController.h b/MultiColumnTableView/MultiColumnTableViewViewController.h new file mode 100644 index 0000000..7030969 --- /dev/null +++ b/MultiColumnTableView/MultiColumnTableViewViewController.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2011 Eli Wang + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + + +#import +#import "EWMultiColumnTableView.h" + +@interface MultiColumnTableViewViewController : UIViewController { + NSMutableArray *data; + NSMutableArray *sectionHeaderData; + + CGFloat colWidth; + NSInteger numberOfSections; + NSInteger numberOfColumns; + + EWMultiColumnTableView *tblView; +} + + +@end diff --git a/MultiColumnTableView/MultiColumnTableViewViewController.m b/MultiColumnTableView/MultiColumnTableViewViewController.m new file mode 100644 index 0000000..d12ef7b --- /dev/null +++ b/MultiColumnTableView/MultiColumnTableViewViewController.m @@ -0,0 +1,336 @@ +/* + * Copyright (c) 2011 Eli Wang + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + + +#import "MultiColumnTableViewViewController.h" +#define ROWS 100 + +@interface MultiColumnTableViewViewController() + +- (void)handleDoubleTap:(UITapGestureRecognizer *)recognizer; + +@end + + + + + +@implementation MultiColumnTableViewViewController + +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) { + srand(time(0)); + } + + return self; +} + + +- (void)dealloc +{ + [data release]; + [tblView release]; + [sectionHeaderData release]; + [super dealloc]; +} + +- (void)didReceiveMemoryWarning +{ + // Releases the view if it doesn't have a superview. + [super didReceiveMemoryWarning]; + + // Release any cached data, images, etc that aren't in use. +} + +#pragma mark - View lifecycle + + +// Implement viewDidLoad to do additional setup after loading the view, typically from a nib. +- (void)viewDidLoad +{ + [super viewDidLoad]; + numberOfColumns = 5; + numberOfSections = 5; + + int sectionDistro[] = {5, 7, 4, 9, 2}; + colWidth = 240.0f; + + data = [[NSMutableArray alloc] initWithCapacity:numberOfSections * 5]; + sectionHeaderData = [[NSMutableArray alloc] initWithCapacity:numberOfSections]; + + for (int i = 0; i < numberOfSections; i++) { + + int rows = sectionDistro[i]; + NSMutableArray *a = [NSMutableArray arrayWithCapacity:numberOfColumns]; + for (int j = 0; j < numberOfColumns; j++) { + + int d = rand() % 100; + + NSMutableString *text = [NSMutableString stringWithFormat:@"S %d C %d", i, j]; + if (d < 66) { + [text appendFormat:@"\nsecond line"]; + } + + if (d < 33) { + [text appendFormat:@"\nthird line"]; + } + + + [a addObject:text]; + } + [sectionHeaderData addObject:a]; + + NSMutableArray *sectionArray = [NSMutableArray arrayWithCapacity:10]; + for (int k = 0; k < rows; k++) { + + NSMutableArray *rowArray = [NSMutableArray arrayWithCapacity:numberOfColumns]; + for (int j = 0; j < numberOfColumns; j++) { + int d = rand() % 100; + + NSMutableString *text = [NSMutableString stringWithFormat:@"(%d, %d, %d)", i, k, j]; + if (d < 66) { + [text appendFormat:@"\nsecond line"]; + } + + if (d < 33) { + [text appendFormat:@"\nthird line"]; + } + + [rowArray addObject:text]; + } + + [sectionArray addObject:rowArray]; + } + + [data addObject:sectionArray]; + } + + + tblView = [[EWMultiColumnTableView alloc] initWithFrame:CGRectInset(self.view.bounds, 5.0f, 5.0f)]; + tblView.sectionHeaderEnabled = YES; +// tblView.cellWidth = 100.0f; +// tblView.boldSeperatorLineColor = [UIColor blueColor]; +// tblView.normalSeperatorLineColor = [UIColor blueColor]; +// tblView.boldSeperatorLineWidth = 10.0f; +// tblView.normalSeperatorLineWidth = 10.0f; + tblView.dataSource = self; + tblView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; + [self.view addSubview:tblView]; + + +} + + +- (void)viewDidUnload +{ + [super viewDidUnload]; + // Release any retained subviews of the main view. + // e.g. self.myOutlet = nil; + [tblView release]; + tblView = nil; +} + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation +{ + // Return YES for supported orientations + return YES; +} + +#pragma mark - EWMultiColumnTableViewDataSource + +- (NSInteger)numberOfSectionsInTableView:(EWMultiColumnTableView *)tableView +{ + return numberOfSections; +} + +- (UIView *)tableView:(EWMultiColumnTableView *)tableView cellForIndexPath:(NSIndexPath *)indexPath column:(NSInteger)col +{ + UILabel *l = [[[UILabel alloc] initWithFrame:CGRectMake(0.0f, 0.0f, colWidth, 40.0f)] autorelease]; + l.numberOfLines = 0; + l.lineBreakMode = UILineBreakModeWordWrap; + + return l; +} + + +- (void)tableView:(EWMultiColumnTableView *)tableView setContentForCell:(UIView *)cell indexPath:(NSIndexPath *)indexPath column:(NSInteger)col{ + UILabel *l = (UILabel *)cell; + l.text = [[[data objectAtIndex:indexPath.section] objectAtIndex:indexPath.row] objectAtIndex:col]; + + CGRect f = l.frame; + f.size.width = [self tableView:tableView widthForColumn:col]; + l.frame = f; + + [l sizeToFit]; +} + +- (CGFloat)tableView:(EWMultiColumnTableView *)tableView heightForCellAtIndexPath:(NSIndexPath *)indexPath column:(NSInteger)col +{ + NSString *str = [[[data objectAtIndex:indexPath.section] objectAtIndex:indexPath.row] objectAtIndex:col]; + CGSize s = [str sizeWithFont:[UIFont systemFontOfSize:[UIFont systemFontSize]] + constrainedToSize:CGSizeMake([self tableView:tableView widthForColumn:col], MAXFLOAT) lineBreakMode:UILineBreakModeWordWrap]; + + return s.height + 20.0f; +} + +- (CGFloat)tableView:(EWMultiColumnTableView *)tableView widthForColumn:(NSInteger)column +{ + return colWidth; +} + +- (NSInteger)tableView:(EWMultiColumnTableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + return [[data objectAtIndex:section] count]; +} + +- (UIView *)tableView:(EWMultiColumnTableView *)tableView sectionHeaderCellForSection:(NSInteger)section column:(NSInteger)col +{ + UILabel *l = [[[UILabel alloc] initWithFrame:CGRectMake(0.0f, 0.0f, [self tableView:tableView widthForColumn:col], 40.0f)] autorelease]; + l.backgroundColor = [UIColor yellowColor]; + return l; +} + +- (void)tableView:(EWMultiColumnTableView *)tableView setContentForSectionHeaderCell:(UIView *)cell section:(NSInteger)section column:(NSInteger)col +{ + UILabel *l = (UILabel *)cell; + l.text = [NSString stringWithFormat:@"S %d C %d", section, col]; + + CGRect f = l.frame; + f.size.width = [self tableView:tableView widthForColumn:col]; + l.frame = f; + + [l sizeToFit]; +} + +- (NSInteger)numberOfColumnsInTableView:(EWMultiColumnTableView *)tableView +{ + return numberOfColumns; +} + +#pragma mark Header Cell + +- (UIView *)tableView:(EWMultiColumnTableView *)tableView headerCellForIndexPath:(NSIndexPath *)indexPath +{ + return [[[UILabel alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 100.0f, 40.0f)] autorelease]; +} + +- (void)tableView:(EWMultiColumnTableView *)tableView setContentForHeaderCell:(UIView *)cell atIndexPath:(NSIndexPath *)indexPath +{ + UILabel *l = (UILabel *)cell; + l.text = [NSString stringWithFormat:@"Line: (%d, %d)", indexPath.section, indexPath.row]; +} + +- (CGFloat)tableView:(EWMultiColumnTableView *)tableView heightForHeaderCellAtIndexPath:(NSIndexPath *)indexPath +{ + return 40.0f; +} + +- (CGFloat)tableView:(EWMultiColumnTableView *)tableView heightForSectionHeaderCellAtSection:(NSInteger)section column:(NSInteger)col +{ + return 50.0f; +} + +- (UIView *)tableView:(EWMultiColumnTableView *)tableView headerCellInSectionHeaderForSection:(NSInteger)section +{ + UILabel *l = [[[UILabel alloc] initWithFrame:CGRectMake(0.0f, 0.0f, [self widthForHeaderCellOfTableView:tableView], 30.0f)] autorelease]; + l.backgroundColor = [UIColor orangeColor]; + return l; + +} + +- (void)tableView:(EWMultiColumnTableView *)tableView setContentForHeaderCellInSectionHeader:(UIView *)cell AtSection:(NSInteger)section +{ + UILabel *l = (UILabel *)cell; + l.text = [NSString stringWithFormat:@"Section %d", section]; +} + +- (CGFloat)widthForHeaderCellOfTableView:(EWMultiColumnTableView *)tableView +{ + return 200.0f; +} + + +- (UIView *)tableView:(EWMultiColumnTableView *)tableView headerCellForColumn:(NSInteger)col +{ + UILabel *l = [[[UILabel alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 250.0f, 300.0f)] autorelease]; + l.text = [NSString stringWithFormat:@"Column: %d", col]; + l.userInteractionEnabled = YES; + + l.tag = col; + UITapGestureRecognizer *recognizer = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTap:)] autorelease]; + recognizer.numberOfTapsRequired = 2; + [l addGestureRecognizer:recognizer]; + + return l; +} + +- (UIView *)topleftHeaderCellOfTableView:(EWMultiColumnTableView *)tableView +{ + UILabel *l = [[[UILabel alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 250.0f, [self heightForHeaderCellOfTableView:tableView])] autorelease]; + l.text = @"Products"; + + return l; +} + +- (CGFloat)heightForHeaderCellOfTableView:(EWMultiColumnTableView *)tableView +{ + return 300.0f; +} + +- (void)tableView:(EWMultiColumnTableView *)tableView swapDataOfColumn:(NSInteger)col1 andColumn:(NSInteger)col2 +{ + for (int i = 0; i < [self numberOfSectionsInTableView:tableView]; i++) { + NSMutableArray *section = [data objectAtIndex:i]; + for (int j = 0; j < [self tableView:tableView numberOfRowsInSection:i]; j++) { + NSMutableArray *a = [section objectAtIndex:j]; + id tmp = [[a objectAtIndex:col2] retain]; + + [a replaceObjectAtIndex:col2 withObject:[a objectAtIndex:col1]]; + [a replaceObjectAtIndex:col1 withObject:tmp]; + [tmp release]; + } + } +} + +- (void)handleDoubleTap:(UITapGestureRecognizer *)recognizer +{ + int col = [recognizer.view tag]; + for (NSMutableArray *array in sectionHeaderData) { + [array removeObjectAtIndex:col]; +// [array addObject:@""]; + } + + for (NSMutableArray *section in data) { + for (NSMutableArray *row in section) { + [row removeObjectAtIndex:col]; +// [row addObject:@""]; + } + } + + numberOfColumns--; + + [tblView reloadData]; + +} + +@end diff --git a/MultiColumnTableView/UIView+AddLine.h b/MultiColumnTableView/UIView+AddLine.h new file mode 100644 index 0000000..c23b68c --- /dev/null +++ b/MultiColumnTableView/UIView+AddLine.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2011 Eli Wang + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + + +#import + + +@interface UIView(AddLine) + +- (void)addBottomLineWithWidth:(CGFloat)width color:(UIColor *)color; + +- (UIView *)addVerticalLineWithWidth:(CGFloat)width color:(UIColor *)color atX:(CGFloat)x; + +@end diff --git a/MultiColumnTableView/UIView+AddLine.m b/MultiColumnTableView/UIView+AddLine.m new file mode 100644 index 0000000..a367010 --- /dev/null +++ b/MultiColumnTableView/UIView+AddLine.m @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2011 Eli Wang + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + + +#import "UIView+AddLine.h" + + +@implementation UIView(AddLine) + +- (void)addBottomLineWithWidth:(CGFloat)width color:(UIColor *)color +{ + CGRect f = self.frame; + f.size.height += width; + self.frame = f; + + UIView *bottomLine = [[[UIView alloc] initWithFrame:CGRectMake(0.0, self.frame.size.height - width, + self.frame.size.width, width)] autorelease]; + bottomLine.backgroundColor = color; + bottomLine.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin; + + [self addSubview:bottomLine]; +} + +- (UIView *)addVerticalLineWithWidth:(CGFloat)width color:(UIColor *)color atX:(CGFloat)x +{ + UIView *vLine = [[[UIView alloc] initWithFrame:CGRectMake(x, 0.0f, width, self.frame.size.height)] autorelease]; + vLine.backgroundColor = color; + vLine.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleRightMargin; + + [self addSubview:vLine]; + + return vLine; +} + +@end diff --git a/MultiColumnTableView/en.lproj/InfoPlist.strings b/MultiColumnTableView/en.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/MultiColumnTableView/en.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/MultiColumnTableView/en.lproj/MainWindow.xib b/MultiColumnTableView/en.lproj/MainWindow.xib new file mode 100644 index 0000000..3dd96dd --- /dev/null +++ b/MultiColumnTableView/en.lproj/MainWindow.xib @@ -0,0 +1,436 @@ + + + + 800 + 10D540 + 760 + 1038.29 + 460.00 + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + 81 + + + YES + + + + YES + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + YES + + YES + + + YES + + + + YES + + IBFilesOwner + IBCocoaTouchFramework + + + IBFirstResponder + IBCocoaTouchFramework + + + + 292 + {768, 1024} + + + 1 + MSAxIDEAA + + NO + NO + + 2 + + IBIPadFramework + YES + + + IBIPadFramework + + + MultiColumnTableViewViewController + + IBIPadFramework + + + + + YES + + + viewController + + + + 8 + + + + delegate + + + + 9 + + + + window + + + + 10 + + + + + YES + + 0 + + + + + + -1 + + + File's Owner + + + -2 + + + + + 2 + + + + + 6 + + + MultiColumnTableView App Delegate + + + 7 + + + + + + + YES + + YES + -1.CustomClassName + -2.CustomClassName + 2.IBEditorWindowLastContentRect + 2.IBPluginDependency + 6.CustomClassName + 6.IBPluginDependency + 7.CustomClassName + 7.IBEditorWindowLastContentRect + 7.IBPluginDependency + + + YES + UIApplication + UIResponder + {{200, 57}, {783, 799}} + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + MultiColumnTableViewAppDelegate + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + MultiColumnTableViewViewController + {{512, 351}, {320, 480}} + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + YES + + + YES + + + + + YES + + + YES + + + + 10 + + + + YES + + MultiColumnTableViewAppDelegate + NSObject + + YES + + YES + viewController + window + + + YES + MultiColumnTableViewViewController + UIWindow + + + + IBProjectSource + MultiColumnTableViewAppDelegate.h + + + + MultiColumnTableViewViewController + UIViewController + + IBProjectSource + MultiColumnTableViewViewController.h + + + + + YES + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSError.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSFileManager.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSKeyValueCoding.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSKeyValueObserving.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSKeyedArchiver.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSNetServices.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSObject.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSPort.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSRunLoop.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSStream.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSThread.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSURL.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSURLConnection.h + + + + NSObject + + IBFrameworkSource + Foundation.framework/Headers/NSXMLParser.h + + + + NSObject + + IBFrameworkSource + UIKit.framework/Headers/UIAccessibility.h + + + + NSObject + + IBFrameworkSource + UIKit.framework/Headers/UINibLoading.h + + + + NSObject + + IBFrameworkSource + UIKit.framework/Headers/UIResponder.h + + + + UIApplication + UIResponder + + IBFrameworkSource + UIKit.framework/Headers/UIApplication.h + + + + UIResponder + NSObject + + + + UIResponder + + IBFrameworkSource + UIKit.framework/Headers/UITextInput.h + + + + UISearchBar + UIView + + IBFrameworkSource + UIKit.framework/Headers/UISearchBar.h + + + + UISearchDisplayController + NSObject + + IBFrameworkSource + UIKit.framework/Headers/UISearchDisplayController.h + + + + UIView + + IBFrameworkSource + UIKit.framework/Headers/UITextField.h + + + + UIView + UIResponder + + IBFrameworkSource + UIKit.framework/Headers/UIView.h + + + + UIViewController + + IBFrameworkSource + UIKit.framework/Headers/UINavigationController.h + + + + UIViewController + + IBFrameworkSource + UIKit.framework/Headers/UISplitViewController.h + + + + UIViewController + + IBFrameworkSource + UIKit.framework/Headers/UITabBarController.h + + + + UIViewController + UIResponder + + IBFrameworkSource + UIKit.framework/Headers/UIViewController.h + + + + UIWindow + UIView + + IBFrameworkSource + UIKit.framework/Headers/UIWindow.h + + + + + 0 + IBIPadFramework + + com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS + + + + com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 + + + YES + MultiColumnTableView.xcodeproj + 3 + 81 + + diff --git a/MultiColumnTableView/en.lproj/MultiColumnTableViewViewController.xib b/MultiColumnTableView/en.lproj/MultiColumnTableViewViewController.xib new file mode 100644 index 0000000..69c8d2b --- /dev/null +++ b/MultiColumnTableView/en.lproj/MultiColumnTableViewViewController.xib @@ -0,0 +1,150 @@ + + + + 800 + 10J869 + 1306 + 1038.35 + 461.00 + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + 301 + + + YES + IBProxyObject + IBUIView + + + YES + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + YES + + YES + + + + + YES + + IBFilesOwner + IBIPadFramework + + + IBFirstResponder + IBIPadFramework + + + + 292 + {768, 1004} + + + + 3 + MQA + + 2 + + + IBIPadFramework + + + + + YES + + + view + + + + 22 + + + + + YES + + 0 + + + + + + -1 + + + File's Owner + + + -2 + + + + + 21 + + + + + + + YES + + YES + -1.CustomClassName + -2.CustomClassName + 21.IBPluginDependency + + + YES + MultiColumnTableViewViewController + UIResponder + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + YES + + + + + + YES + + + + + 22 + + + + YES + + MultiColumnTableViewViewController + UIViewController + + IBProjectSource + ./Classes/MultiColumnTableViewViewController.h + + + + + 0 + IBIPadFramework + + com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS + + + + com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 + + + YES + 3 + 301 + + diff --git a/MultiColumnTableView/main.m b/MultiColumnTableView/main.m new file mode 100644 index 0000000..169ef0d --- /dev/null +++ b/MultiColumnTableView/main.m @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2011 Eli Wang + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + + +#import + +int main(int argc, char *argv[]) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + int retVal = UIApplicationMain(argc, argv, nil, nil); + [pool release]; + return retVal; +} diff --git a/README b/README new file mode 100644 index 0000000..94d7c63 --- /dev/null +++ b/README @@ -0,0 +1 @@ +Base on the UITableView containing only one column, this project implements a multi-column table view for iOS. It has a horizontal scrollable table body, a fixed left and top table header. It also supports foldable sections, and draggable columns.