├── .gitignore ├── MoveGrid ├── MoveGrid.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata ├── MoveGrid │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── CustomGrid.h │ ├── CustomGrid.m │ ├── Images.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── LaunchImage.launchimage │ │ │ └── Contents.json │ ├── MainViewController.h │ ├── MainViewController.m │ ├── MoreViewController.h │ ├── MoreViewController.m │ ├── MoveGrid-Info.plist │ ├── MoveGrid-Prefix.pch │ ├── MoveGrid.xcdatamodeld │ │ ├── .xccurrentversion │ │ └── MoveGrid.xcdatamodel │ │ │ └── contents │ ├── en.lproj │ │ └── InfoPlist.strings │ ├── images │ │ ├── app_item_add.png │ │ ├── app_item_bg.png │ │ ├── app_item_plus.png │ │ └── app_item_pressed_bg.png │ └── main.m └── MoveGridTests │ ├── MoveGridTests-Info.plist │ ├── MoveGridTests.m │ └── en.lproj │ └── InfoPlist.strings └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | # Pods/ 27 | -------------------------------------------------------------------------------- /MoveGrid/MoveGrid.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | D6882F141A0C67A800AB4C0B /* MoreViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D6882F131A0C67A800AB4C0B /* MoreViewController.m */; }; 11 | D6B472FD1A0B57C400CF8091 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D6B472FC1A0B57C400CF8091 /* Foundation.framework */; }; 12 | D6B472FF1A0B57C400CF8091 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D6B472FE1A0B57C400CF8091 /* CoreGraphics.framework */; }; 13 | D6B473011A0B57C400CF8091 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D6B473001A0B57C400CF8091 /* UIKit.framework */; }; 14 | D6B473031A0B57C400CF8091 /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D6B473021A0B57C400CF8091 /* CoreData.framework */; }; 15 | D6B473091A0B57C400CF8091 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D6B473071A0B57C400CF8091 /* InfoPlist.strings */; }; 16 | D6B4730B1A0B57C400CF8091 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = D6B4730A1A0B57C400CF8091 /* main.m */; }; 17 | D6B4730F1A0B57C400CF8091 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = D6B4730E1A0B57C400CF8091 /* AppDelegate.m */; }; 18 | D6B473121A0B57C400CF8091 /* MoveGrid.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = D6B473101A0B57C400CF8091 /* MoveGrid.xcdatamodeld */; }; 19 | D6B473141A0B57C400CF8091 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D6B473131A0B57C400CF8091 /* Images.xcassets */; }; 20 | D6B4731B1A0B57C400CF8091 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D6B4731A1A0B57C400CF8091 /* XCTest.framework */; }; 21 | D6B4731C1A0B57C400CF8091 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D6B472FC1A0B57C400CF8091 /* Foundation.framework */; }; 22 | D6B4731D1A0B57C400CF8091 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D6B473001A0B57C400CF8091 /* UIKit.framework */; }; 23 | D6B4731E1A0B57C400CF8091 /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D6B473021A0B57C400CF8091 /* CoreData.framework */; }; 24 | D6B473261A0B57C500CF8091 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D6B473241A0B57C500CF8091 /* InfoPlist.strings */; }; 25 | D6B473281A0B57C500CF8091 /* MoveGridTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D6B473271A0B57C500CF8091 /* MoveGridTests.m */; }; 26 | D6B473331A0B57EC00CF8091 /* MainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D6B473321A0B57EC00CF8091 /* MainViewController.m */; }; 27 | D6B473361A0B581200CF8091 /* CustomGrid.m in Sources */ = {isa = PBXBuildFile; fileRef = D6B473351A0B581200CF8091 /* CustomGrid.m */; }; 28 | D6B4733C1A0B625B00CF8091 /* app_item_add.png in Resources */ = {isa = PBXBuildFile; fileRef = D6B473381A0B625B00CF8091 /* app_item_add.png */; }; 29 | D6B4733D1A0B625B00CF8091 /* app_item_bg.png in Resources */ = {isa = PBXBuildFile; fileRef = D6B473391A0B625B00CF8091 /* app_item_bg.png */; }; 30 | D6B4733E1A0B625B00CF8091 /* app_item_plus.png in Resources */ = {isa = PBXBuildFile; fileRef = D6B4733A1A0B625B00CF8091 /* app_item_plus.png */; }; 31 | D6B4733F1A0B625B00CF8091 /* app_item_pressed_bg.png in Resources */ = {isa = PBXBuildFile; fileRef = D6B4733B1A0B625B00CF8091 /* app_item_pressed_bg.png */; }; 32 | /* End PBXBuildFile section */ 33 | 34 | /* Begin PBXContainerItemProxy section */ 35 | D6B4731F1A0B57C400CF8091 /* PBXContainerItemProxy */ = { 36 | isa = PBXContainerItemProxy; 37 | containerPortal = D6B472F11A0B57C400CF8091 /* Project object */; 38 | proxyType = 1; 39 | remoteGlobalIDString = D6B472F81A0B57C400CF8091; 40 | remoteInfo = MoveGrid; 41 | }; 42 | /* End PBXContainerItemProxy section */ 43 | 44 | /* Begin PBXFileReference section */ 45 | D6882F121A0C67A800AB4C0B /* MoreViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MoreViewController.h; sourceTree = ""; }; 46 | D6882F131A0C67A800AB4C0B /* MoreViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MoreViewController.m; sourceTree = ""; }; 47 | D6B472F91A0B57C400CF8091 /* MoveGrid.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MoveGrid.app; sourceTree = BUILT_PRODUCTS_DIR; }; 48 | D6B472FC1A0B57C400CF8091 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 49 | D6B472FE1A0B57C400CF8091 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 50 | D6B473001A0B57C400CF8091 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 51 | D6B473021A0B57C400CF8091 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; 52 | D6B473061A0B57C400CF8091 /* MoveGrid-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "MoveGrid-Info.plist"; sourceTree = ""; }; 53 | D6B473081A0B57C400CF8091 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 54 | D6B4730A1A0B57C400CF8091 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 55 | D6B4730C1A0B57C400CF8091 /* MoveGrid-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MoveGrid-Prefix.pch"; sourceTree = ""; }; 56 | D6B4730D1A0B57C400CF8091 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 57 | D6B4730E1A0B57C400CF8091 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 58 | D6B473111A0B57C400CF8091 /* MoveGrid.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MoveGrid.xcdatamodel; sourceTree = ""; }; 59 | D6B473131A0B57C400CF8091 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 60 | D6B473191A0B57C400CF8091 /* MoveGridTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MoveGridTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 61 | D6B4731A1A0B57C400CF8091 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 62 | D6B473231A0B57C400CF8091 /* MoveGridTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "MoveGridTests-Info.plist"; sourceTree = ""; }; 63 | D6B473251A0B57C500CF8091 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 64 | D6B473271A0B57C500CF8091 /* MoveGridTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MoveGridTests.m; sourceTree = ""; }; 65 | D6B473311A0B57EC00CF8091 /* MainViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MainViewController.h; sourceTree = ""; }; 66 | D6B473321A0B57EC00CF8091 /* MainViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MainViewController.m; sourceTree = ""; }; 67 | D6B473341A0B581200CF8091 /* CustomGrid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CustomGrid.h; sourceTree = ""; }; 68 | D6B473351A0B581200CF8091 /* CustomGrid.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CustomGrid.m; sourceTree = ""; }; 69 | D6B473381A0B625B00CF8091 /* app_item_add.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = app_item_add.png; sourceTree = ""; }; 70 | D6B473391A0B625B00CF8091 /* app_item_bg.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = app_item_bg.png; sourceTree = ""; }; 71 | D6B4733A1A0B625B00CF8091 /* app_item_plus.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = app_item_plus.png; sourceTree = ""; }; 72 | D6B4733B1A0B625B00CF8091 /* app_item_pressed_bg.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = app_item_pressed_bg.png; sourceTree = ""; }; 73 | /* End PBXFileReference section */ 74 | 75 | /* Begin PBXFrameworksBuildPhase section */ 76 | D6B472F61A0B57C400CF8091 /* Frameworks */ = { 77 | isa = PBXFrameworksBuildPhase; 78 | buildActionMask = 2147483647; 79 | files = ( 80 | D6B472FF1A0B57C400CF8091 /* CoreGraphics.framework in Frameworks */, 81 | D6B473031A0B57C400CF8091 /* CoreData.framework in Frameworks */, 82 | D6B473011A0B57C400CF8091 /* UIKit.framework in Frameworks */, 83 | D6B472FD1A0B57C400CF8091 /* Foundation.framework in Frameworks */, 84 | ); 85 | runOnlyForDeploymentPostprocessing = 0; 86 | }; 87 | D6B473161A0B57C400CF8091 /* Frameworks */ = { 88 | isa = PBXFrameworksBuildPhase; 89 | buildActionMask = 2147483647; 90 | files = ( 91 | D6B4731B1A0B57C400CF8091 /* XCTest.framework in Frameworks */, 92 | D6B4731E1A0B57C400CF8091 /* CoreData.framework in Frameworks */, 93 | D6B4731D1A0B57C400CF8091 /* UIKit.framework in Frameworks */, 94 | D6B4731C1A0B57C400CF8091 /* Foundation.framework in Frameworks */, 95 | ); 96 | runOnlyForDeploymentPostprocessing = 0; 97 | }; 98 | /* End PBXFrameworksBuildPhase section */ 99 | 100 | /* Begin PBXGroup section */ 101 | D6B472F01A0B57C400CF8091 = { 102 | isa = PBXGroup; 103 | children = ( 104 | D6B473041A0B57C400CF8091 /* MoveGrid */, 105 | D6B473211A0B57C400CF8091 /* MoveGridTests */, 106 | D6B472FB1A0B57C400CF8091 /* Frameworks */, 107 | D6B472FA1A0B57C400CF8091 /* Products */, 108 | ); 109 | sourceTree = ""; 110 | }; 111 | D6B472FA1A0B57C400CF8091 /* Products */ = { 112 | isa = PBXGroup; 113 | children = ( 114 | D6B472F91A0B57C400CF8091 /* MoveGrid.app */, 115 | D6B473191A0B57C400CF8091 /* MoveGridTests.xctest */, 116 | ); 117 | name = Products; 118 | sourceTree = ""; 119 | }; 120 | D6B472FB1A0B57C400CF8091 /* Frameworks */ = { 121 | isa = PBXGroup; 122 | children = ( 123 | D6B472FC1A0B57C400CF8091 /* Foundation.framework */, 124 | D6B472FE1A0B57C400CF8091 /* CoreGraphics.framework */, 125 | D6B473001A0B57C400CF8091 /* UIKit.framework */, 126 | D6B473021A0B57C400CF8091 /* CoreData.framework */, 127 | D6B4731A1A0B57C400CF8091 /* XCTest.framework */, 128 | ); 129 | name = Frameworks; 130 | sourceTree = ""; 131 | }; 132 | D6B473041A0B57C400CF8091 /* MoveGrid */ = { 133 | isa = PBXGroup; 134 | children = ( 135 | D6B473371A0B625B00CF8091 /* images */, 136 | D6B4730D1A0B57C400CF8091 /* AppDelegate.h */, 137 | D6B4730E1A0B57C400CF8091 /* AppDelegate.m */, 138 | D6B473311A0B57EC00CF8091 /* MainViewController.h */, 139 | D6B473321A0B57EC00CF8091 /* MainViewController.m */, 140 | D6882F121A0C67A800AB4C0B /* MoreViewController.h */, 141 | D6882F131A0C67A800AB4C0B /* MoreViewController.m */, 142 | D6B473341A0B581200CF8091 /* CustomGrid.h */, 143 | D6B473351A0B581200CF8091 /* CustomGrid.m */, 144 | D6B473131A0B57C400CF8091 /* Images.xcassets */, 145 | D6B473101A0B57C400CF8091 /* MoveGrid.xcdatamodeld */, 146 | D6B473051A0B57C400CF8091 /* Supporting Files */, 147 | ); 148 | path = MoveGrid; 149 | sourceTree = ""; 150 | }; 151 | D6B473051A0B57C400CF8091 /* Supporting Files */ = { 152 | isa = PBXGroup; 153 | children = ( 154 | D6B473061A0B57C400CF8091 /* MoveGrid-Info.plist */, 155 | D6B473071A0B57C400CF8091 /* InfoPlist.strings */, 156 | D6B4730A1A0B57C400CF8091 /* main.m */, 157 | D6B4730C1A0B57C400CF8091 /* MoveGrid-Prefix.pch */, 158 | ); 159 | name = "Supporting Files"; 160 | sourceTree = ""; 161 | }; 162 | D6B473211A0B57C400CF8091 /* MoveGridTests */ = { 163 | isa = PBXGroup; 164 | children = ( 165 | D6B473271A0B57C500CF8091 /* MoveGridTests.m */, 166 | D6B473221A0B57C400CF8091 /* Supporting Files */, 167 | ); 168 | path = MoveGridTests; 169 | sourceTree = ""; 170 | }; 171 | D6B473221A0B57C400CF8091 /* Supporting Files */ = { 172 | isa = PBXGroup; 173 | children = ( 174 | D6B473231A0B57C400CF8091 /* MoveGridTests-Info.plist */, 175 | D6B473241A0B57C500CF8091 /* InfoPlist.strings */, 176 | ); 177 | name = "Supporting Files"; 178 | sourceTree = ""; 179 | }; 180 | D6B473371A0B625B00CF8091 /* images */ = { 181 | isa = PBXGroup; 182 | children = ( 183 | D6B473381A0B625B00CF8091 /* app_item_add.png */, 184 | D6B473391A0B625B00CF8091 /* app_item_bg.png */, 185 | D6B4733A1A0B625B00CF8091 /* app_item_plus.png */, 186 | D6B4733B1A0B625B00CF8091 /* app_item_pressed_bg.png */, 187 | ); 188 | path = images; 189 | sourceTree = ""; 190 | }; 191 | /* End PBXGroup section */ 192 | 193 | /* Begin PBXNativeTarget section */ 194 | D6B472F81A0B57C400CF8091 /* MoveGrid */ = { 195 | isa = PBXNativeTarget; 196 | buildConfigurationList = D6B4732B1A0B57C500CF8091 /* Build configuration list for PBXNativeTarget "MoveGrid" */; 197 | buildPhases = ( 198 | D6B472F51A0B57C400CF8091 /* Sources */, 199 | D6B472F61A0B57C400CF8091 /* Frameworks */, 200 | D6B472F71A0B57C400CF8091 /* Resources */, 201 | ); 202 | buildRules = ( 203 | ); 204 | dependencies = ( 205 | ); 206 | name = MoveGrid; 207 | productName = MoveGrid; 208 | productReference = D6B472F91A0B57C400CF8091 /* MoveGrid.app */; 209 | productType = "com.apple.product-type.application"; 210 | }; 211 | D6B473181A0B57C400CF8091 /* MoveGridTests */ = { 212 | isa = PBXNativeTarget; 213 | buildConfigurationList = D6B4732E1A0B57C500CF8091 /* Build configuration list for PBXNativeTarget "MoveGridTests" */; 214 | buildPhases = ( 215 | D6B473151A0B57C400CF8091 /* Sources */, 216 | D6B473161A0B57C400CF8091 /* Frameworks */, 217 | D6B473171A0B57C400CF8091 /* Resources */, 218 | ); 219 | buildRules = ( 220 | ); 221 | dependencies = ( 222 | D6B473201A0B57C400CF8091 /* PBXTargetDependency */, 223 | ); 224 | name = MoveGridTests; 225 | productName = MoveGridTests; 226 | productReference = D6B473191A0B57C400CF8091 /* MoveGridTests.xctest */; 227 | productType = "com.apple.product-type.bundle.unit-test"; 228 | }; 229 | /* End PBXNativeTarget section */ 230 | 231 | /* Begin PBXProject section */ 232 | D6B472F11A0B57C400CF8091 /* Project object */ = { 233 | isa = PBXProject; 234 | attributes = { 235 | LastUpgradeCheck = 0510; 236 | ORGANIZATIONNAME = 51app; 237 | TargetAttributes = { 238 | D6B473181A0B57C400CF8091 = { 239 | TestTargetID = D6B472F81A0B57C400CF8091; 240 | }; 241 | }; 242 | }; 243 | buildConfigurationList = D6B472F41A0B57C400CF8091 /* Build configuration list for PBXProject "MoveGrid" */; 244 | compatibilityVersion = "Xcode 3.2"; 245 | developmentRegion = English; 246 | hasScannedForEncodings = 0; 247 | knownRegions = ( 248 | en, 249 | ); 250 | mainGroup = D6B472F01A0B57C400CF8091; 251 | productRefGroup = D6B472FA1A0B57C400CF8091 /* Products */; 252 | projectDirPath = ""; 253 | projectRoot = ""; 254 | targets = ( 255 | D6B472F81A0B57C400CF8091 /* MoveGrid */, 256 | D6B473181A0B57C400CF8091 /* MoveGridTests */, 257 | ); 258 | }; 259 | /* End PBXProject section */ 260 | 261 | /* Begin PBXResourcesBuildPhase section */ 262 | D6B472F71A0B57C400CF8091 /* Resources */ = { 263 | isa = PBXResourcesBuildPhase; 264 | buildActionMask = 2147483647; 265 | files = ( 266 | D6B4733C1A0B625B00CF8091 /* app_item_add.png in Resources */, 267 | D6B4733E1A0B625B00CF8091 /* app_item_plus.png in Resources */, 268 | D6B4733F1A0B625B00CF8091 /* app_item_pressed_bg.png in Resources */, 269 | D6B4733D1A0B625B00CF8091 /* app_item_bg.png in Resources */, 270 | D6B473091A0B57C400CF8091 /* InfoPlist.strings in Resources */, 271 | D6B473141A0B57C400CF8091 /* Images.xcassets in Resources */, 272 | ); 273 | runOnlyForDeploymentPostprocessing = 0; 274 | }; 275 | D6B473171A0B57C400CF8091 /* Resources */ = { 276 | isa = PBXResourcesBuildPhase; 277 | buildActionMask = 2147483647; 278 | files = ( 279 | D6B473261A0B57C500CF8091 /* InfoPlist.strings in Resources */, 280 | ); 281 | runOnlyForDeploymentPostprocessing = 0; 282 | }; 283 | /* End PBXResourcesBuildPhase section */ 284 | 285 | /* Begin PBXSourcesBuildPhase section */ 286 | D6B472F51A0B57C400CF8091 /* Sources */ = { 287 | isa = PBXSourcesBuildPhase; 288 | buildActionMask = 2147483647; 289 | files = ( 290 | D6B4730F1A0B57C400CF8091 /* AppDelegate.m in Sources */, 291 | D6882F141A0C67A800AB4C0B /* MoreViewController.m in Sources */, 292 | D6B473121A0B57C400CF8091 /* MoveGrid.xcdatamodeld in Sources */, 293 | D6B473361A0B581200CF8091 /* CustomGrid.m in Sources */, 294 | D6B4730B1A0B57C400CF8091 /* main.m in Sources */, 295 | D6B473331A0B57EC00CF8091 /* MainViewController.m in Sources */, 296 | ); 297 | runOnlyForDeploymentPostprocessing = 0; 298 | }; 299 | D6B473151A0B57C400CF8091 /* Sources */ = { 300 | isa = PBXSourcesBuildPhase; 301 | buildActionMask = 2147483647; 302 | files = ( 303 | D6B473281A0B57C500CF8091 /* MoveGridTests.m in Sources */, 304 | ); 305 | runOnlyForDeploymentPostprocessing = 0; 306 | }; 307 | /* End PBXSourcesBuildPhase section */ 308 | 309 | /* Begin PBXTargetDependency section */ 310 | D6B473201A0B57C400CF8091 /* PBXTargetDependency */ = { 311 | isa = PBXTargetDependency; 312 | target = D6B472F81A0B57C400CF8091 /* MoveGrid */; 313 | targetProxy = D6B4731F1A0B57C400CF8091 /* PBXContainerItemProxy */; 314 | }; 315 | /* End PBXTargetDependency section */ 316 | 317 | /* Begin PBXVariantGroup section */ 318 | D6B473071A0B57C400CF8091 /* InfoPlist.strings */ = { 319 | isa = PBXVariantGroup; 320 | children = ( 321 | D6B473081A0B57C400CF8091 /* en */, 322 | ); 323 | name = InfoPlist.strings; 324 | sourceTree = ""; 325 | }; 326 | D6B473241A0B57C500CF8091 /* InfoPlist.strings */ = { 327 | isa = PBXVariantGroup; 328 | children = ( 329 | D6B473251A0B57C500CF8091 /* en */, 330 | ); 331 | name = InfoPlist.strings; 332 | sourceTree = ""; 333 | }; 334 | /* End PBXVariantGroup section */ 335 | 336 | /* Begin XCBuildConfiguration section */ 337 | D6B473291A0B57C500CF8091 /* Debug */ = { 338 | isa = XCBuildConfiguration; 339 | buildSettings = { 340 | ALWAYS_SEARCH_USER_PATHS = NO; 341 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 342 | CLANG_CXX_LIBRARY = "libc++"; 343 | CLANG_ENABLE_MODULES = YES; 344 | CLANG_ENABLE_OBJC_ARC = YES; 345 | CLANG_WARN_BOOL_CONVERSION = YES; 346 | CLANG_WARN_CONSTANT_CONVERSION = YES; 347 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 348 | CLANG_WARN_EMPTY_BODY = YES; 349 | CLANG_WARN_ENUM_CONVERSION = YES; 350 | CLANG_WARN_INT_CONVERSION = YES; 351 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 352 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 353 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 354 | COPY_PHASE_STRIP = NO; 355 | GCC_C_LANGUAGE_STANDARD = gnu99; 356 | GCC_DYNAMIC_NO_PIC = NO; 357 | GCC_OPTIMIZATION_LEVEL = 0; 358 | GCC_PREPROCESSOR_DEFINITIONS = ( 359 | "DEBUG=1", 360 | "$(inherited)", 361 | ); 362 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 363 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 364 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 365 | GCC_WARN_UNDECLARED_SELECTOR = YES; 366 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 367 | GCC_WARN_UNUSED_FUNCTION = YES; 368 | GCC_WARN_UNUSED_VARIABLE = YES; 369 | IPHONEOS_DEPLOYMENT_TARGET = 5.0; 370 | ONLY_ACTIVE_ARCH = YES; 371 | SDKROOT = iphoneos; 372 | }; 373 | name = Debug; 374 | }; 375 | D6B4732A1A0B57C500CF8091 /* Release */ = { 376 | isa = XCBuildConfiguration; 377 | buildSettings = { 378 | ALWAYS_SEARCH_USER_PATHS = NO; 379 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 380 | CLANG_CXX_LIBRARY = "libc++"; 381 | CLANG_ENABLE_MODULES = YES; 382 | CLANG_ENABLE_OBJC_ARC = YES; 383 | CLANG_WARN_BOOL_CONVERSION = YES; 384 | CLANG_WARN_CONSTANT_CONVERSION = YES; 385 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 386 | CLANG_WARN_EMPTY_BODY = YES; 387 | CLANG_WARN_ENUM_CONVERSION = YES; 388 | CLANG_WARN_INT_CONVERSION = YES; 389 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 390 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 391 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 392 | COPY_PHASE_STRIP = YES; 393 | ENABLE_NS_ASSERTIONS = NO; 394 | GCC_C_LANGUAGE_STANDARD = gnu99; 395 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 396 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 397 | GCC_WARN_UNDECLARED_SELECTOR = YES; 398 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 399 | GCC_WARN_UNUSED_FUNCTION = YES; 400 | GCC_WARN_UNUSED_VARIABLE = YES; 401 | IPHONEOS_DEPLOYMENT_TARGET = 5.0; 402 | SDKROOT = iphoneos; 403 | VALIDATE_PRODUCT = YES; 404 | }; 405 | name = Release; 406 | }; 407 | D6B4732C1A0B57C500CF8091 /* Debug */ = { 408 | isa = XCBuildConfiguration; 409 | buildSettings = { 410 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 411 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 412 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 413 | GCC_PREFIX_HEADER = "MoveGrid/MoveGrid-Prefix.pch"; 414 | INFOPLIST_FILE = "MoveGrid/MoveGrid-Info.plist"; 415 | PRODUCT_NAME = "$(TARGET_NAME)"; 416 | WRAPPER_EXTENSION = app; 417 | }; 418 | name = Debug; 419 | }; 420 | D6B4732D1A0B57C500CF8091 /* Release */ = { 421 | isa = XCBuildConfiguration; 422 | buildSettings = { 423 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 424 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 425 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 426 | GCC_PREFIX_HEADER = "MoveGrid/MoveGrid-Prefix.pch"; 427 | INFOPLIST_FILE = "MoveGrid/MoveGrid-Info.plist"; 428 | PRODUCT_NAME = "$(TARGET_NAME)"; 429 | WRAPPER_EXTENSION = app; 430 | }; 431 | name = Release; 432 | }; 433 | D6B4732F1A0B57C500CF8091 /* Debug */ = { 434 | isa = XCBuildConfiguration; 435 | buildSettings = { 436 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/MoveGrid.app/MoveGrid"; 437 | FRAMEWORK_SEARCH_PATHS = ( 438 | "$(SDKROOT)/Developer/Library/Frameworks", 439 | "$(inherited)", 440 | "$(DEVELOPER_FRAMEWORKS_DIR)", 441 | ); 442 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 443 | GCC_PREFIX_HEADER = "MoveGrid/MoveGrid-Prefix.pch"; 444 | GCC_PREPROCESSOR_DEFINITIONS = ( 445 | "DEBUG=1", 446 | "$(inherited)", 447 | ); 448 | INFOPLIST_FILE = "MoveGridTests/MoveGridTests-Info.plist"; 449 | PRODUCT_NAME = "$(TARGET_NAME)"; 450 | TEST_HOST = "$(BUNDLE_LOADER)"; 451 | WRAPPER_EXTENSION = xctest; 452 | }; 453 | name = Debug; 454 | }; 455 | D6B473301A0B57C500CF8091 /* Release */ = { 456 | isa = XCBuildConfiguration; 457 | buildSettings = { 458 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/MoveGrid.app/MoveGrid"; 459 | FRAMEWORK_SEARCH_PATHS = ( 460 | "$(SDKROOT)/Developer/Library/Frameworks", 461 | "$(inherited)", 462 | "$(DEVELOPER_FRAMEWORKS_DIR)", 463 | ); 464 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 465 | GCC_PREFIX_HEADER = "MoveGrid/MoveGrid-Prefix.pch"; 466 | INFOPLIST_FILE = "MoveGridTests/MoveGridTests-Info.plist"; 467 | PRODUCT_NAME = "$(TARGET_NAME)"; 468 | TEST_HOST = "$(BUNDLE_LOADER)"; 469 | WRAPPER_EXTENSION = xctest; 470 | }; 471 | name = Release; 472 | }; 473 | /* End XCBuildConfiguration section */ 474 | 475 | /* Begin XCConfigurationList section */ 476 | D6B472F41A0B57C400CF8091 /* Build configuration list for PBXProject "MoveGrid" */ = { 477 | isa = XCConfigurationList; 478 | buildConfigurations = ( 479 | D6B473291A0B57C500CF8091 /* Debug */, 480 | D6B4732A1A0B57C500CF8091 /* Release */, 481 | ); 482 | defaultConfigurationIsVisible = 0; 483 | defaultConfigurationName = Release; 484 | }; 485 | D6B4732B1A0B57C500CF8091 /* Build configuration list for PBXNativeTarget "MoveGrid" */ = { 486 | isa = XCConfigurationList; 487 | buildConfigurations = ( 488 | D6B4732C1A0B57C500CF8091 /* Debug */, 489 | D6B4732D1A0B57C500CF8091 /* Release */, 490 | ); 491 | defaultConfigurationIsVisible = 0; 492 | defaultConfigurationName = Release; 493 | }; 494 | D6B4732E1A0B57C500CF8091 /* Build configuration list for PBXNativeTarget "MoveGridTests" */ = { 495 | isa = XCConfigurationList; 496 | buildConfigurations = ( 497 | D6B4732F1A0B57C500CF8091 /* Debug */, 498 | D6B473301A0B57C500CF8091 /* Release */, 499 | ); 500 | defaultConfigurationIsVisible = 0; 501 | defaultConfigurationName = Release; 502 | }; 503 | /* End XCConfigurationList section */ 504 | 505 | /* Begin XCVersionGroup section */ 506 | D6B473101A0B57C400CF8091 /* MoveGrid.xcdatamodeld */ = { 507 | isa = XCVersionGroup; 508 | children = ( 509 | D6B473111A0B57C400CF8091 /* MoveGrid.xcdatamodel */, 510 | ); 511 | currentVersion = D6B473111A0B57C400CF8091 /* MoveGrid.xcdatamodel */; 512 | path = MoveGrid.xcdatamodeld; 513 | sourceTree = ""; 514 | versionGroupType = wrapper.xcdatamodel; 515 | }; 516 | /* End XCVersionGroup section */ 517 | }; 518 | rootObject = D6B472F11A0B57C400CF8091 /* Project object */; 519 | } 520 | -------------------------------------------------------------------------------- /MoveGrid/MoveGrid.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /MoveGrid/MoveGrid/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // MoveGrid 4 | // 5 | // Created by Jerry.li on 14-11-6. 6 | // Copyright (c) 2014年 51app. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext; 16 | @property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel; 17 | @property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator; 18 | 19 | - (void)saveContext; 20 | - (NSURL *)applicationDocumentsDirectory; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /MoveGrid/MoveGrid/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // MoveGrid 4 | // 5 | // Created by Jerry.li on 14-11-6. 6 | // Copyright (c) 2014年 51app. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "MainViewController.h" 11 | 12 | @implementation AppDelegate 13 | 14 | @synthesize managedObjectContext = _managedObjectContext; 15 | @synthesize managedObjectModel = _managedObjectModel; 16 | @synthesize persistentStoreCoordinator = _persistentStoreCoordinator; 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 19 | { 20 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 21 | UINavigationController *navigation = [[UINavigationController alloc] initWithRootViewController:[[MainViewController alloc] init]]; 22 | 23 | self.window.rootViewController = navigation; 24 | self.window.backgroundColor = [UIColor whiteColor]; 25 | [self.window makeKeyAndVisible]; 26 | return YES; 27 | } 28 | 29 | - (void)applicationWillResignActive:(UIApplication *)application 30 | { 31 | // 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. 32 | // 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. 33 | } 34 | 35 | - (void)applicationDidEnterBackground:(UIApplication *)application 36 | { 37 | // 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. 38 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 39 | } 40 | 41 | - (void)applicationWillEnterForeground:(UIApplication *)application 42 | { 43 | // 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. 44 | } 45 | 46 | - (void)applicationDidBecomeActive:(UIApplication *)application 47 | { 48 | // 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. 49 | } 50 | 51 | - (void)applicationWillTerminate:(UIApplication *)application 52 | { 53 | // Saves changes in the application's managed object context before the application terminates. 54 | [self saveContext]; 55 | } 56 | 57 | - (void)saveContext 58 | { 59 | NSError *error = nil; 60 | NSManagedObjectContext *managedObjectContext = self.managedObjectContext; 61 | if (managedObjectContext != nil) { 62 | if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) { 63 | // Replace this implementation with code to handle the error appropriately. 64 | // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. 65 | NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 66 | abort(); 67 | } 68 | } 69 | } 70 | 71 | #pragma mark - Core Data stack 72 | 73 | // Returns the managed object context for the application. 74 | // If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application. 75 | - (NSManagedObjectContext *)managedObjectContext 76 | { 77 | if (_managedObjectContext != nil) { 78 | return _managedObjectContext; 79 | } 80 | 81 | NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; 82 | if (coordinator != nil) { 83 | _managedObjectContext = [[NSManagedObjectContext alloc] init]; 84 | [_managedObjectContext setPersistentStoreCoordinator:coordinator]; 85 | } 86 | return _managedObjectContext; 87 | } 88 | 89 | // Returns the managed object model for the application. 90 | // If the model doesn't already exist, it is created from the application's model. 91 | - (NSManagedObjectModel *)managedObjectModel 92 | { 93 | if (_managedObjectModel != nil) { 94 | return _managedObjectModel; 95 | } 96 | NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"MoveGrid" withExtension:@"momd"]; 97 | _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; 98 | return _managedObjectModel; 99 | } 100 | 101 | // Returns the persistent store coordinator for the application. 102 | // If the coordinator doesn't already exist, it is created and the application's store added to it. 103 | - (NSPersistentStoreCoordinator *)persistentStoreCoordinator 104 | { 105 | if (_persistentStoreCoordinator != nil) { 106 | return _persistentStoreCoordinator; 107 | } 108 | 109 | NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"MoveGrid.sqlite"]; 110 | 111 | NSError *error = nil; 112 | _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; 113 | if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) { 114 | /* 115 | Replace this implementation with code to handle the error appropriately. 116 | 117 | abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. 118 | 119 | Typical reasons for an error here include: 120 | * The persistent store is not accessible; 121 | * The schema for the persistent store is incompatible with current managed object model. 122 | Check the error message to determine what the actual problem was. 123 | 124 | 125 | If the persistent store is not accessible, there is typically something wrong with the file path. Often, a file URL is pointing into the application's resources directory instead of a writeable directory. 126 | 127 | If you encounter schema incompatibility errors during development, you can reduce their frequency by: 128 | * Simply deleting the existing store: 129 | [[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil] 130 | 131 | * Performing automatic lightweight migration by passing the following dictionary as the options parameter: 132 | @{NSMigratePersistentStoresAutomaticallyOption:@YES, NSInferMappingModelAutomaticallyOption:@YES} 133 | 134 | Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details. 135 | 136 | */ 137 | NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 138 | abort(); 139 | } 140 | 141 | return _persistentStoreCoordinator; 142 | } 143 | 144 | #pragma mark - Application's Documents directory 145 | 146 | // Returns the URL to the application's Documents directory. 147 | - (NSURL *)applicationDocumentsDirectory 148 | { 149 | return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; 150 | } 151 | 152 | @end 153 | -------------------------------------------------------------------------------- /MoveGrid/MoveGrid/CustomGrid.h: -------------------------------------------------------------------------------- 1 | // 2 | // CustomGrid.h 3 | // MoveGrid 4 | // 5 | // Created by Jerry.li on 14-11-6. 6 | // Copyright (c) 2014年 51app. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #define ScreenWidth [UIScreen mainScreen].bounds.size.width 12 | #define ScreenHeight [UIScreen mainScreen].bounds.size.height 13 | 14 | //每个格子的高度 15 | #define GridHeight 95 16 | //每行显示格子的列数 17 | #define PerRowGridCount 4 18 | //每列显示格子的行数 19 | #define PerColumGridCount 3 20 | //每个格子的宽度 21 | #define GridWidth (ScreenWidth/PerRowGridCount) 22 | //每个格子的X轴间隔 23 | #define PaddingX 0 24 | //每个格子的Y轴间隔 25 | #define PaddingY 0 26 | 27 | @protocol CustomGridDelegate; 28 | 29 | @interface CustomGrid : UIButton 30 | //格子的ID 31 | @property(nonatomic, assign)NSInteger gridId; 32 | //格子的选中状态 33 | @property(nonatomic, assign)BOOL isChecked; 34 | //格子的移动状态 35 | @property(nonatomic, assign)BOOL isMove; 36 | //格子的排列索引位置 37 | @property(nonatomic, assign)NSInteger gridIndex; 38 | //格子的位置坐标 39 | @property(nonatomic, assign)CGPoint gridCenterPoint; 40 | //代理方法 41 | @property(nonatomic, weak)id delegate; 42 | 43 | /** 44 | * 创建格子 45 | * @param pointX 格子所在位置的X坐标 46 | * @param pointY 格子所在位置的Y坐标 47 | * @param gridId 格子的ID 48 | * @param index 格子所在位置的索引下标 49 | * @param isDelete 是否增加删除图标 50 | */ 51 | - (id)initWithFrame:(CGRect)frame 52 | title:(NSString *)title 53 | normalImage:(UIImage *)normalImage 54 | highlightedImage:(UIImage *)highlightedImage 55 | gridId:(NSInteger)gridId 56 | atIndex:(NSInteger)index 57 | isAddDelete:(BOOL)isAddDelete 58 | deleteIcon:(UIImage *)deleteIcon; 59 | 60 | //根据格子的坐标计算格子的索引位置 61 | + (NSInteger)indexOfPoint:(CGPoint)point 62 | withButton:(UIButton *)btn 63 | gridArray:(NSMutableArray *)gridListArray; 64 | 65 | @end 66 | 67 | @protocol CustomGridDelegate 68 | 69 | //响应格子的点击事件 70 | - (void)gridItemDidClicked:(CustomGrid *)clickItem; 71 | 72 | //响应格子删除事件 73 | - (void)gridItemDidDeleteClicked:(UIButton *)deleteButton; 74 | 75 | //响应格子的长安手势事件 76 | - (void)pressGestureStateBegan:(UILongPressGestureRecognizer *)longPressGesture withGridItem:(CustomGrid *) grid; 77 | 78 | - (void)pressGestureStateChangedWithPoint:(CGPoint) gridPoint gridItem:(CustomGrid *) gridItem; 79 | 80 | - (void)pressGestureStateEnded:(CustomGrid *) gridItem; 81 | 82 | @end 83 | 84 | 85 | -------------------------------------------------------------------------------- /MoveGrid/MoveGrid/CustomGrid.m: -------------------------------------------------------------------------------- 1 | // 2 | // CustomGrid.m 3 | // MoveGrid 4 | // 5 | // Created by Jerry.li on 14-11-6. 6 | // Copyright (c) 2014年 51app. All rights reserved. 7 | // 8 | 9 | #import "CustomGrid.h" 10 | 11 | @implementation CustomGrid 12 | 13 | @synthesize delegate; 14 | 15 | - (id)initWithFrame:(CGRect)frame 16 | { 17 | self = [super initWithFrame:frame]; 18 | if (self) { 19 | 20 | } 21 | return self; 22 | } 23 | 24 | //创建格子 25 | - (id)initWithFrame:(CGRect)frame 26 | title:(NSString *)title 27 | normalImage:(UIImage *)normalImage 28 | highlightedImage:(UIImage *)highlightedImage 29 | gridId:(NSInteger)gridId 30 | atIndex:(NSInteger)index 31 | isAddDelete:(BOOL)isAddDelete 32 | deleteIcon:(UIImage *)deleteIcon 33 | { 34 | self = [super initWithFrame:frame]; 35 | if (self) { 36 | //计算每个格子的X坐标 37 | CGFloat pointX = (index % PerRowGridCount) * (GridWidth + PaddingX) + PaddingX;; 38 | //计算每个格子的Y坐标 39 | CGFloat pointY = (index / PerRowGridCount) * (GridHeight + PaddingY) + PaddingY; 40 | 41 | [self setFrame:CGRectMake(pointX, pointY, GridWidth, GridHeight)]; 42 | [self setTitle:title forState:UIControlStateNormal]; 43 | [self setTitleColor:[UIColor orangeColor] forState:UIControlStateNormal]; 44 | [self setBackgroundImage:normalImage forState:UIControlStateNormal]; 45 | [self setBackgroundImage:highlightedImage forState:UIControlStateHighlighted]; 46 | self.titleLabel.font = [UIFont boldSystemFontOfSize:14]; 47 | [self addTarget:self action:@selector(gridClick:) forControlEvents:UIControlEventTouchUpInside]; 48 | 49 | ////////// 50 | [self setGridId:gridId]; 51 | [self setGridIndex:index]; 52 | [self setGridCenterPoint:self.center]; 53 | 54 | //判断是否要添加删除图标 55 | if (isAddDelete) { 56 | //当长按时添加删除按钮图标 57 | UIButton *deleteBtn = [UIButton buttonWithType:UIButtonTypeCustom]; 58 | [deleteBtn setFrame:CGRectMake(55, 10, 16, 16)]; 59 | [deleteBtn setBackgroundColor:[UIColor clearColor]]; 60 | [deleteBtn setBackgroundImage:deleteIcon forState:UIControlStateNormal]; 61 | [deleteBtn addTarget:self action:@selector(deleteGrid:) forControlEvents:UIControlEventTouchUpInside]; 62 | [deleteBtn setHidden:YES]; 63 | 64 | ///////////// 65 | [deleteBtn setTag:gridId]; 66 | [self addSubview:deleteBtn]; 67 | 68 | //添加长按手势 69 | UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(gridLongPress:)]; 70 | [self addGestureRecognizer:longPressGesture]; 71 | longPressGesture = nil; 72 | } 73 | } 74 | return self; 75 | } 76 | 77 | 78 | //响应格子点击事件 79 | - (void)gridClick:(CustomGrid *)clickItem 80 | { 81 | [self.delegate gridItemDidClicked:clickItem]; 82 | } 83 | 84 | //响应格子删除事件 85 | - (void)deleteGrid:(UIButton *)deleteButton 86 | { 87 | [self.delegate gridItemDidDeleteClicked:deleteButton]; 88 | } 89 | 90 | //响应格子的长安手势事件 91 | - (void)gridLongPress:(UILongPressGestureRecognizer *)longPressGesture 92 | { 93 | switch (longPressGesture.state) { 94 | case UIGestureRecognizerStateBegan: 95 | { 96 | [self.delegate pressGestureStateBegan:longPressGesture withGridItem:self]; 97 | break; 98 | } 99 | case UIGestureRecognizerStateChanged: 100 | { 101 | //应用移动后的新坐标 102 | CGPoint newPoint = [longPressGesture locationInView:longPressGesture.view]; 103 | [self.delegate pressGestureStateChangedWithPoint:newPoint gridItem:self]; 104 | break; 105 | } 106 | case UIGestureRecognizerStateEnded: 107 | { 108 | [self.delegate pressGestureStateEnded:self]; 109 | break; 110 | } 111 | default: 112 | break; 113 | } 114 | } 115 | 116 | //根据格子的坐标计算格子的索引位置 117 | + (NSInteger)indexOfPoint:(CGPoint)point 118 | withButton:(UIButton *)btn 119 | gridArray:(NSMutableArray *)gridListArray 120 | { 121 | for (NSInteger i = 0;i< gridListArray.count;i++) 122 | { 123 | UIButton *appButton = gridListArray[i]; 124 | if (appButton != btn) 125 | { 126 | if (CGRectContainsPoint(appButton.frame, point)) 127 | { 128 | return i; 129 | } 130 | } 131 | } 132 | return -1; 133 | } 134 | 135 | @end 136 | -------------------------------------------------------------------------------- /MoveGrid/MoveGrid/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "40x40", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "60x60", 16 | "scale" : "2x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /MoveGrid/MoveGrid/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "7.0", 8 | "scale" : "2x" 9 | }, 10 | { 11 | "orientation" : "portrait", 12 | "idiom" : "iphone", 13 | "subtype" : "retina4", 14 | "extent" : "full-screen", 15 | "minimum-system-version" : "7.0", 16 | "scale" : "2x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /MoveGrid/MoveGrid/MainViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // MainViewController.h 3 | // MoveGrid 4 | // 5 | // Created by Jerry.li on 14-11-6. 6 | // Copyright (c) 2014年 51app. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "CustomGrid.h" 11 | 12 | @interface MainViewController : UIViewController 13 | 14 | @property(nonatomic, strong)NSMutableArray *addGridArray; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /MoveGrid/MoveGrid/MainViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // MainViewController.m 3 | // MoveGrid 4 | // 5 | // Created by Jerry.li on 14-11-6. 6 | // Copyright (c) 2014年 51app. All rights reserved. 7 | // 8 | 9 | #import "MainViewController.h" 10 | #import "MoreViewController.h" 11 | 12 | @interface MainViewController () 13 | { 14 | BOOL isSelected; 15 | BOOL contain; 16 | //是否可跳转应用对应的详细页面 17 | BOOL isSkip; 18 | 19 | //选中格子的起始位置 20 | CGPoint startPoint; 21 | //选中格子的起始坐标位置 22 | CGPoint originPoint; 23 | 24 | UIImage *normalImage; 25 | UIImage *highlightedImage; 26 | UIImage *deleteIconImage; 27 | } 28 | 29 | @property(nonatomic, strong)NSMutableArray *gridListArray; 30 | @property(nonatomic, strong)NSMutableArray *showGridArray; 31 | 32 | //更多页面显示应用 33 | @property(nonatomic, strong)NSMutableArray *moreGridIdArray; 34 | @property(nonatomic, strong)UIView *gridListView; 35 | 36 | @end 37 | 38 | @implementation MainViewController 39 | 40 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 41 | { 42 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 43 | if (self) { 44 | self.gridListArray = [[NSMutableArray alloc] initWithCapacity:12]; 45 | self.showGridArray = [[NSMutableArray alloc] initWithCapacity:12]; 46 | self.moreGridIdArray = [[NSMutableArray alloc] initWithCapacity:12]; 47 | self.title = @"吼吼吼~~~"; 48 | } 49 | return self; 50 | } 51 | 52 | - (void)viewDidLoad 53 | { 54 | [super viewDidLoad]; 55 | self.view.backgroundColor = [UIColor orangeColor]; 56 | self.navigationController.navigationBar.translucent = NO; 57 | 58 | normalImage = [UIImage imageNamed:@"app_item_bg"]; 59 | highlightedImage = [UIImage imageNamed:@"app_item_pressed_bg"]; 60 | deleteIconImage = [UIImage imageNamed:@"app_item_plus"]; 61 | 62 | _showGridArray = [NSMutableArray arrayWithObjects:@"101", @"102", @"103", @"104", @"105", @"106", @"107", @"108", @"109", @"200", @"201", @"0", nil]; 63 | 64 | _moreGridIdArray = [NSMutableArray arrayWithObjects:@"202", @"203", @"204", @"205", @"206", @"207", nil]; 65 | 66 | 67 | } 68 | 69 | - (void)viewWillAppear:(BOOL)animated 70 | { 71 | NSLog(@"=====================: %d", self.addGridArray.count); 72 | [self.gridListView removeFromSuperview]; 73 | [self.gridListArray removeAllObjects]; 74 | isSelected = NO; 75 | 76 | // 77 | if (self.addGridArray.count > 0) { 78 | for (NSInteger i = 0; i < self.addGridArray.count; i++) { 79 | NSInteger count = self.showGridArray.count - 1; 80 | [self.showGridArray insertObject:self.addGridArray[i] atIndex:count]; 81 | } 82 | } 83 | 84 | for (NSInteger i = 0; i < self.showGridArray.count; i++) { 85 | NSString *gridId = self.showGridArray[i]; 86 | NSLog(@"new add grid is gridId: %@", gridId); 87 | } 88 | 89 | [self drawGridView]; 90 | } 91 | 92 | - (void)drawGridView 93 | { 94 | _gridListView = [[UIView alloc] init]; 95 | [_gridListView setFrame:CGRectMake(0, 60, ScreenWidth, GridHeight * PerColumGridCount)]; 96 | [_gridListView setBackgroundColor:[UIColor whiteColor]]; 97 | 98 | [self.view addSubview:_gridListView]; 99 | 100 | for (NSInteger index = 0; index < [_showGridArray count]; index++) 101 | { 102 | NSString *gridTitle = _showGridArray[index]; 103 | BOOL isAddDelete = YES; 104 | 105 | if ([gridTitle isEqualToString:@"0"]) { 106 | isAddDelete = NO; 107 | } 108 | CustomGrid *gridItem = [[CustomGrid alloc] initWithFrame:CGRectZero title:gridTitle normalImage:normalImage highlightedImage:highlightedImage gridId:[gridTitle integerValue] atIndex:index isAddDelete:isAddDelete deleteIcon:deleteIconImage]; 109 | gridItem.delegate = self; 110 | 111 | [self.gridListView addSubview:gridItem]; 112 | [self.gridListArray addObject:gridItem]; 113 | } 114 | 115 | //for test print out 116 | for (NSInteger i = 0; i < _gridListArray.count; i++) { 117 | CustomGrid *gridItem = _gridListArray[i]; 118 | gridItem.gridCenterPoint = gridItem.center; 119 | NSLog(@"所有格子的位置信息{gridIndex: %d, gridCenterPoint: %@, gridID: %d}", 120 | gridItem.gridIndex, NSStringFromCGPoint(gridItem.gridCenterPoint), gridItem.gridId); 121 | } 122 | } 123 | 124 | #pragma mark CustomGrid Delegate 125 | 126 | //响应格子的点击事件 127 | - (void)gridItemDidClicked:(CustomGrid *)gridItem 128 | { 129 | NSLog(@"您点击的格子Tag是:%d", gridItem.gridId); 130 | isSkip = YES; 131 | 132 | //查看是否有选中的格子,并且比较点击的格子是否就是选中的格子 133 | for (NSInteger i = 0; i < [_gridListArray count]; i++) { 134 | CustomGrid *item = _gridListArray[i]; 135 | if (item.isChecked && item.gridId != gridItem.gridId) { 136 | item.isChecked = NO; 137 | item.isMove = NO; 138 | isSelected = NO; 139 | isSkip = NO; 140 | 141 | //隐藏删除图标 142 | UIButton *removeBtn = (UIButton *)[self.gridListView viewWithTag:item.gridId]; 143 | removeBtn.hidden = YES; 144 | [item setBackgroundImage:normalImage forState:UIControlStateNormal]; 145 | 146 | if (gridItem.gridId == 0) { 147 | isSkip = YES; 148 | } 149 | break; 150 | } 151 | } 152 | 153 | if (isSkip) { 154 | switch (gridItem.gridId) { 155 | case 0: 156 | { 157 | MoreViewController *otherView = [[MoreViewController alloc] init]; 158 | otherView.showMoreGridIdArray = self.moreGridIdArray; 159 | otherView.currentGridCount = self.gridListArray.count; 160 | [self.navigationController pushViewController:otherView animated:YES]; 161 | break; 162 | } 163 | default: 164 | break; 165 | } 166 | } 167 | } 168 | 169 | //响应点击格子删除事件 170 | - (void)gridItemDidDeleteClicked:(UIButton *)deleteButton 171 | { 172 | NSLog(@"您删除的格子是GridId:%d", deleteButton.tag); 173 | 174 | for (NSInteger i = 0; i < _gridListArray.count; i++) { 175 | CustomGrid *removeGrid = _gridListArray[i]; 176 | if (removeGrid.gridId == deleteButton.tag) { 177 | [removeGrid removeFromSuperview]; 178 | NSInteger count = _gridListArray.count - 1; 179 | for (NSInteger index = removeGrid.gridIndex; index < count; index++) { 180 | CustomGrid *preGrid = _gridListArray[index]; 181 | CustomGrid *nextGrid = _gridListArray[index+1]; 182 | [UIView animateWithDuration:0.5 animations:^{ 183 | nextGrid.center = preGrid.gridCenterPoint; 184 | }]; 185 | nextGrid.gridIndex = index; 186 | } 187 | [_gridListArray removeObjectAtIndex:removeGrid.gridIndex]; 188 | NSString *gridID = [NSString stringWithFormat:@"%d", removeGrid.gridId]; 189 | //删除的应用添加到更多应用数组 190 | [_moreGridIdArray addObject:gridID]; 191 | [_showGridArray removeObject:gridID]; 192 | } 193 | } 194 | } 195 | 196 | - (void)pressGestureStateBegan:(UILongPressGestureRecognizer *)longPressGesture withGridItem:(CustomGrid *) grid 197 | { 198 | NSLog(@"UIGestureRecognizerStateBegan........."); 199 | NSLog(@"isSelected: %d", isSelected); 200 | 201 | //判断格子是否已经被选中并且是否可移动状态,如果选中就加一个放大的特效 202 | if (isSelected && grid.isChecked) { 203 | grid.transform = CGAffineTransformMakeScale(1.2, 1.2); 204 | } 205 | 206 | //没有一个格子选中的时候 207 | if (!isSelected) { 208 | 209 | NSLog(@"没有一个格子选中............"); 210 | grid.isChecked = YES; 211 | grid.isMove = YES; 212 | isSelected = YES; 213 | 214 | //选中格子的时候显示删除图标 215 | UIButton *removeBtn = (UIButton *)[longPressGesture.view viewWithTag:grid.gridId]; 216 | removeBtn.hidden = NO; 217 | 218 | //获取移动格子的起始位置 219 | startPoint = [longPressGesture locationInView:longPressGesture.view]; 220 | //获取移动格子的起始位置中心点 221 | originPoint = grid.center; 222 | 223 | //给选中的格子添加放大的特效 224 | [UIView animateWithDuration:0.5 animations:^{ 225 | grid.transform = CGAffineTransformMakeScale(1.2, 1.2); 226 | grid.alpha = 0.8; 227 | [grid setBackgroundImage:highlightedImage forState:UIControlStateNormal]; 228 | }]; 229 | } 230 | } 231 | 232 | - (void)pressGestureStateChangedWithPoint:(CGPoint) gridPoint gridItem:(CustomGrid *) gridItem 233 | { 234 | if (isSelected && gridItem.isChecked) { 235 | NSLog(@"UIGestureRecognizerStateChanged........."); 236 | 237 | [_gridListView bringSubviewToFront:gridItem]; 238 | //应用移动后的X坐标 239 | CGFloat deltaX = gridPoint.x - startPoint.x; 240 | //应用移动后的Y坐标 241 | CGFloat deltaY = gridPoint.y - startPoint.y; 242 | //拖动的应用跟随手势移动 243 | gridItem.center = CGPointMake(gridItem.center.x + deltaX, gridItem.center.y + deltaY); 244 | 245 | //移动的格子索引下标 246 | NSInteger fromIndex = gridItem.gridIndex; 247 | //移动到目标格子的索引下标 248 | NSInteger toIndex = [CustomGrid indexOfPoint:gridItem.center withButton:gridItem gridArray:_gridListArray]; 249 | 250 | NSInteger borderIndex = [_showGridArray indexOfObject:@"0"]; 251 | NSLog(@"borderIndex: %d", borderIndex); 252 | 253 | if (toIndex < 0 || toIndex >= borderIndex) { 254 | contain = NO; 255 | }else{ 256 | //获取移动到目标格子 257 | CustomGrid *targetGrid = _gridListArray[toIndex]; 258 | gridItem.center = targetGrid.gridCenterPoint; 259 | originPoint = targetGrid.gridCenterPoint; 260 | gridItem.gridIndex = toIndex; 261 | 262 | //判断格子的移动方向,是从后往前还是从前往后拖动 263 | if ((fromIndex - toIndex) > 0) { 264 | NSLog(@"从后往前拖动格子......."); 265 | //从移动格子的位置开始,始终获取最后一个格子的索引位置 266 | NSInteger lastGridIndex = fromIndex; 267 | for (NSInteger i = toIndex; i < fromIndex; i++) { 268 | CustomGrid *lastGrid = _gridListArray[lastGridIndex]; 269 | CustomGrid *preGrid = _gridListArray[lastGridIndex-1]; 270 | [UIView animateWithDuration:0.5 animations:^{ 271 | preGrid.center = lastGrid.gridCenterPoint; 272 | }]; 273 | //实时更新格子的索引下标 274 | preGrid.gridIndex = lastGridIndex; 275 | lastGridIndex--; 276 | } 277 | //排列格子顺序和更新格子坐标信息 278 | [self sortGridList]; 279 | 280 | }else if((fromIndex - toIndex) < 0){ 281 | //从前往后拖动格子 282 | NSLog(@"从前往后拖动格子......."); 283 | //从移动格子到目标格子之间的所有格子向前移动一格 284 | for (NSInteger i = fromIndex; i < toIndex; i++) { 285 | CustomGrid *topOneGrid = _gridListArray[i]; 286 | CustomGrid *nextGrid = _gridListArray[i+1]; 287 | [UIView animateWithDuration:0.5 animations:^{ 288 | nextGrid.center = topOneGrid.gridCenterPoint; 289 | }]; 290 | //实时更新格子的索引下标 291 | nextGrid.gridIndex = i; 292 | } 293 | //排列格子顺序和更新格子坐标信息 294 | [self sortGridList]; 295 | } 296 | } 297 | } 298 | } 299 | 300 | - (void)pressGestureStateEnded:(CustomGrid *) gridItem 301 | { 302 | NSLog(@"UIGestureRecognizerStateEnded........."); 303 | if (isSelected && gridItem.isChecked) { 304 | //撤销格子的放大特效 305 | [UIView animateWithDuration:0.5 animations:^{ 306 | gridItem.transform = CGAffineTransformIdentity; 307 | gridItem.alpha = 1.0; 308 | if (!contain) { 309 | gridItem.center = originPoint; 310 | } 311 | }]; 312 | 313 | //排列格子顺序和更新格子坐标信息 314 | [self sortGridList]; 315 | } 316 | } 317 | 318 | - (void)sortGridList 319 | { 320 | //重新排列数组中存放的格子顺序 321 | [_gridListArray sortUsingComparator:^NSComparisonResult(id obj1, id obj2) { 322 | CustomGrid *tempGrid1 = (CustomGrid *)obj1; 323 | CustomGrid *tempGrid2 = (CustomGrid *)obj2; 324 | return tempGrid1.gridIndex > tempGrid2.gridIndex; 325 | }]; 326 | 327 | //更新所有格子的中心点坐标信息 328 | for (NSInteger i = 0; i < _gridListArray.count; i++) { 329 | CustomGrid *gridItem = _gridListArray[i]; 330 | gridItem.gridCenterPoint = gridItem.center; 331 | 332 | //for test print 333 | //NSLog(@"移动后所有格子的位置信息{gridIndex: %d, gridCenterPoint: %@, gridID: %d}", 334 | //gridItem.gridIndex, NSStringFromCGPoint(gridItem.gridCenterPoint), gridItem.gridId); 335 | } 336 | } 337 | 338 | @end 339 | -------------------------------------------------------------------------------- /MoveGrid/MoveGrid/MoreViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // MoreViewController.h 3 | // MoveGrid 4 | // 5 | // Created by Jerry.li on 14-11-7. 6 | // Copyright (c) 2014年 51app. All rights reserved. 7 | // 8 | 9 | #import 10 | @class MainViewController; 11 | @interface MoreViewController : UIViewController 12 | 13 | //显示格子的GridId 14 | @property(nonatomic, strong)NSMutableArray *showMoreGridIdArray; 15 | //当前首页显示格子的数量 16 | @property(nonatomic, assign)NSInteger currentGridCount; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /MoveGrid/MoveGrid/MoreViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // MoreViewController.m 3 | // MoveGrid 4 | // 5 | // Created by Jerry.li on 14-11-7. 6 | // Copyright (c) 2014年 51app. All rights reserved. 7 | // 8 | 9 | #import "MoreViewController.h" 10 | #import "CustomGrid.h" 11 | #import "MainViewController.h" 12 | 13 | 14 | @interface MoreViewController () 15 | { 16 | //标记是否选中 17 | BOOL isSelected; 18 | //可添加格子的最大数 19 | NSInteger maxAddGridCount; 20 | 21 | UIImage *normalImage; 22 | UIImage *highlightedImage; 23 | 24 | } 25 | 26 | @property(nonatomic, strong)NSMutableArray *addGridArray; 27 | //存放格子按钮 28 | @property(nonatomic, strong)NSMutableArray *gridItemArray; 29 | @property(nonatomic, strong)UIView *showMoreGridView; 30 | 31 | @end 32 | 33 | @implementation MoreViewController 34 | 35 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 36 | { 37 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 38 | if (self) { 39 | self.title = @"更多格子"; 40 | self.gridItemArray = [NSMutableArray arrayWithCapacity:12]; 41 | self.addGridArray = [NSMutableArray arrayWithCapacity:12]; 42 | } 43 | return self; 44 | } 45 | 46 | - (void)viewDidLoad 47 | { 48 | [super viewDidLoad]; 49 | [self.view setBackgroundColor:[UIColor orangeColor]]; 50 | UIBarButtonItem *leftButton = [[UIBarButtonItem alloc] initWithTitle:@"上一页" style:UIBarButtonItemStylePlain target:self action:@selector(backToPreView)]; 51 | [self.navigationItem setLeftBarButtonItem:leftButton animated:YES]; 52 | } 53 | 54 | - (void)backToPreView 55 | { 56 | MainViewController *mainView = [self.navigationController.viewControllers objectAtIndex:0]; 57 | mainView.addGridArray = self.addGridArray; 58 | [self.navigationController popToViewController:mainView animated:YES]; 59 | } 60 | 61 | - (void)viewWillAppear:(BOOL)animated 62 | { 63 | [self drawMoreGridView]; 64 | } 65 | 66 | - (void)drawMoreGridView 67 | { 68 | [_showMoreGridView removeFromSuperview]; 69 | 70 | _showMoreGridView = [[UIView alloc] init]; 71 | [_showMoreGridView setFrame:CGRectMake(0, 5, ScreenWidth, GridHeight * PerColumGridCount)]; 72 | [_showMoreGridView setBackgroundColor:[UIColor whiteColor]]; 73 | 74 | normalImage = [UIImage imageNamed:@"app_item_bg"]; 75 | highlightedImage = [UIImage imageNamed:@"app_item_pressed_bg"]; 76 | UIImage *deleteIconImage = [UIImage imageNamed:@"app_item_add"]; 77 | //获取到可添加格子的最大数 78 | maxAddGridCount = (PerRowGridCount * PerColumGridCount) - self.currentGridCount; 79 | 80 | for (NSInteger index = 0; index < self.showMoreGridIdArray.count; index++) 81 | { 82 | NSString *gridTitle = self.showMoreGridIdArray[index]; 83 | CustomGrid *gridItem = [[CustomGrid alloc] initWithFrame:CGRectZero title:gridTitle normalImage:normalImage highlightedImage:highlightedImage gridId:[gridTitle integerValue] atIndex:index isAddDelete:YES deleteIcon:deleteIconImage]; 84 | gridItem.delegate = self; 85 | 86 | [self.gridItemArray addObject:gridItem]; 87 | [self.showMoreGridView addSubview:gridItem]; 88 | } 89 | 90 | [self.view addSubview:_showMoreGridView]; 91 | } 92 | 93 | #pragma mark CustomGrid Delegate 94 | //响应格子的点击事件 95 | - (void)gridItemDidClicked:(CustomGrid *)clickItem 96 | { 97 | for (NSInteger index = 0; index < self.gridItemArray.count; index++) 98 | { 99 | CustomGrid *gridItem = self.gridItemArray[index]; 100 | if (gridItem.isChecked && gridItem.gridId != clickItem.gridId) 101 | { 102 | //隐藏删图标 103 | UIButton *deleteButton = (UIButton *)[self.showMoreGridView viewWithTag:gridItem.gridId]; 104 | deleteButton.hidden = YES; 105 | 106 | [gridItem setIsChecked: NO]; 107 | [gridItem setBackgroundImage:normalImage forState:UIControlStateNormal]; 108 | isSelected = NO; 109 | } 110 | } 111 | } 112 | 113 | //响应格子删除事件 114 | - (void)gridItemDidDeleteClicked:(UIButton *)deleteButton 115 | { 116 | NSLog(@"您添加的格子GridId:%d", deleteButton.tag); 117 | 118 | //当首页显示的格子数量已经达到最大显示数量时,不能再次添加 119 | if (self.addGridArray.count >= maxAddGridCount) { 120 | UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"" 121 | message:@"首页应用已满,请在移除首页某个应用后添加。" 122 | delegate:self 123 | cancelButtonTitle:@"ok" 124 | otherButtonTitles:nil]; 125 | [alertView show]; 126 | }else{ 127 | for (NSInteger i = 0; i < self.gridItemArray.count; i++) { 128 | CustomGrid *deleteGird = self.gridItemArray[i]; 129 | if (deleteGird.gridId == deleteButton.tag) { 130 | //从视图上移除格子 131 | [deleteGird removeFromSuperview]; 132 | 133 | NSInteger count = self.gridItemArray.count - 1; 134 | //从添加格子的索引开始,后面的格子依次往前移动一格 135 | for (NSInteger index = deleteGird.gridIndex; index < count; index++) { 136 | CustomGrid *preGrid = self.gridItemArray[index]; 137 | CustomGrid *nextGrid = self.gridItemArray[index+1]; 138 | 139 | [UIView animateWithDuration:0.5 animations:^{ 140 | nextGrid.center = preGrid.gridCenterPoint; 141 | }]; 142 | nextGrid.gridIndex = index; 143 | } 144 | //将删除的格子从数组里面移除 145 | [self.gridItemArray removeObjectAtIndex:deleteGird.gridIndex]; 146 | 147 | //删除格子的GirdID 148 | NSString *gridId = [NSString stringWithFormat:@"%d", deleteGird.gridId]; 149 | [self.showMoreGridIdArray removeObject:gridId]; 150 | [self.addGridArray addObject:gridId]; 151 | } 152 | } 153 | } 154 | 155 | //for test print out 156 | for (NSInteger i = 0; i < _gridItemArray.count; i++) 157 | { 158 | CustomGrid *gridItem = _gridItemArray[i]; 159 | gridItem.gridCenterPoint = gridItem.center; 160 | NSLog(@"所有格子的位置信息{gridIndex: %d, gridCenterPoint: %@, gridID: %d}", 161 | gridItem.gridIndex, NSStringFromCGPoint(gridItem.gridCenterPoint), gridItem.gridId); 162 | } 163 | 164 | } 165 | 166 | //响应格子的长安手势事件 167 | - (void)pressGestureStateBegan:(UILongPressGestureRecognizer *)longPressGesture withGridItem:(CustomGrid *) grid 168 | { 169 | //验证当前长按的按钮是否已经是选中的状态,如果是,那么只增加放大效果 170 | if (grid.isChecked) { 171 | grid.transform = CGAffineTransformMakeScale(1.2, 1.2); 172 | }else{ 173 | //验证数组中所有的格子是否有选中状态的格子 174 | for (NSInteger i = 0; i < self.showMoreGridIdArray.count; i++) { 175 | CustomGrid *gridItem = self.gridItemArray[i]; 176 | if (gridItem.isChecked) { 177 | isSelected = YES; 178 | } 179 | } 180 | 181 | //如果数组中有选中状态的格子,则不做任何操作,反则增加格子的选中状态 182 | if (!isSelected) { 183 | //标记该格子为选中状态 184 | grid.isChecked = YES; 185 | 186 | //显示格子右上角的添加图标 187 | UIButton *addButton = (UIButton *)[longPressGesture.view viewWithTag:grid.gridId]; 188 | addButton.hidden = NO; 189 | 190 | //给选中的格子添加放大的特效 191 | [UIView animateWithDuration:0.5 animations:^{ 192 | [grid setTransform:CGAffineTransformMakeScale(1.2, 1.2)]; 193 | [grid setAlpha:0.8]; 194 | [grid setBackgroundImage:highlightedImage forState:UIControlStateNormal]; 195 | }]; 196 | } 197 | } 198 | } 199 | 200 | - (void)pressGestureStateChangedWithPoint:(CGPoint) gridPoint gridItem:(CustomGrid *) gridItem 201 | { 202 | 203 | } 204 | 205 | - (void)pressGestureStateEnded:(CustomGrid *) gridItem 206 | { 207 | //手势结束时,还原格子的放大效果 208 | [UIView animateWithDuration:0.5 animations:^{ 209 | [gridItem setTransform:CGAffineTransformIdentity]; 210 | [gridItem setAlpha:1.0]; 211 | }]; 212 | } 213 | 214 | #pragma mark UIAlertView Delegate 215 | - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex 216 | { 217 | NSLog(@"click button index: %d", buttonIndex); 218 | if (buttonIndex == 0) { 219 | for (NSInteger index = 0; index < self.gridItemArray.count; index++) 220 | { 221 | CustomGrid *gridItem = self.gridItemArray[index]; 222 | if (gridItem.isChecked) 223 | { 224 | //隐藏删图标 225 | UIButton *deleteButton = (UIButton *)[self.showMoreGridView viewWithTag:gridItem.gridId]; 226 | deleteButton.hidden = YES; 227 | 228 | [gridItem setIsChecked: NO]; 229 | [gridItem setBackgroundImage:normalImage forState:UIControlStateNormal]; 230 | isSelected = NO; 231 | } 232 | } 233 | } 234 | } 235 | 236 | @end 237 | -------------------------------------------------------------------------------- /MoveGrid/MoveGrid/MoveGrid-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | com.51app.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /MoveGrid/MoveGrid/MoveGrid-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_3_0 10 | #warning "This project uses features only available in iOS SDK 3.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | #import 15 | #import 16 | #import 17 | #endif 18 | -------------------------------------------------------------------------------- /MoveGrid/MoveGrid/MoveGrid.xcdatamodeld/.xccurrentversion: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | _XCCurrentVersionName 6 | MoveGrid.xcdatamodel 7 | 8 | 9 | -------------------------------------------------------------------------------- /MoveGrid/MoveGrid/MoveGrid.xcdatamodeld/MoveGrid.xcdatamodel/contents: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /MoveGrid/MoveGrid/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /MoveGrid/MoveGrid/images/app_item_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lib5988/moveGrid/a7ef981fb75805750caceb260dd32673c29e1dab/MoveGrid/MoveGrid/images/app_item_add.png -------------------------------------------------------------------------------- /MoveGrid/MoveGrid/images/app_item_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lib5988/moveGrid/a7ef981fb75805750caceb260dd32673c29e1dab/MoveGrid/MoveGrid/images/app_item_bg.png -------------------------------------------------------------------------------- /MoveGrid/MoveGrid/images/app_item_plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lib5988/moveGrid/a7ef981fb75805750caceb260dd32673c29e1dab/MoveGrid/MoveGrid/images/app_item_plus.png -------------------------------------------------------------------------------- /MoveGrid/MoveGrid/images/app_item_pressed_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lib5988/moveGrid/a7ef981fb75805750caceb260dd32673c29e1dab/MoveGrid/MoveGrid/images/app_item_pressed_bg.png -------------------------------------------------------------------------------- /MoveGrid/MoveGrid/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // MoveGrid 4 | // 5 | // Created by Jerry.li on 14-11-6. 6 | // Copyright (c) 2014年 51app. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "AppDelegate.h" 12 | 13 | int main(int argc, char * argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /MoveGrid/MoveGridTests/MoveGridTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | com.51app.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /MoveGrid/MoveGridTests/MoveGridTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // MoveGridTests.m 3 | // MoveGridTests 4 | // 5 | // Created by Jerry.li on 14-11-6. 6 | // Copyright (c) 2014年 51app. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface MoveGridTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation MoveGridTests 16 | 17 | - (void)setUp 18 | { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown 24 | { 25 | // Put teardown code here. This method is called after the invocation of each test method in the class. 26 | [super tearDown]; 27 | } 28 | 29 | - (void)testExample 30 | { 31 | XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__); 32 | } 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /MoveGrid/MoveGridTests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 小乙我也是刚刚从java转过来的码农,刚好公司要重构APP应用,其中有一个功能就是实现多个格子的随意拖动和删除并有序排序,百度,谷歌了很久都没有找到我想要的demo,只能自己动手写了,终于花了一个礼拜实现了该功能,所以上传到这里,说不定以后还能用到,大家也可看看,多提建议。在此先谢过了 4 | --------------------------------------------------------------------------------