├── .gitignore ├── LICENSE.md ├── README.md ├── UICollectionView拖动排序.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata └── UICollectionView拖动排序 ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets ├── AppIcon.appiconset │ └── Contents.json ├── Contents.json ├── icon1.imageset │ ├── Contents.json │ ├── Icon-60@2x.png │ └── Icon-60@3x.png ├── icon2.imageset │ ├── Contents.json │ ├── 多云@2x.png │ └── 多云@3x.png └── proper_logo.imageset │ ├── Contents.json │ └── proper_logo.png ├── Base.lproj ├── LaunchScreen.storyboard └── Main.storyboard ├── Controller ├── 1拖动排序 │ ├── SortViewController.h │ └── SortViewController.m ├── 2拖动排序+合并 │ ├── MergeViewController.h │ └── MergeViewController.m ├── 5YYModel测试 │ └── AppModel.m └── Support │ ├── Cell │ ├── MergeCollectionViewCell.h │ ├── MergeCollectionViewCell.m │ └── MergeCollectionViewCell.xib │ ├── Config.h │ └── View │ ├── MergeCollectionView.h │ ├── MergeCollectionView.m │ ├── MergeDetailView.h │ ├── MergeDetailView.m │ └── MergeDetailView.xib ├── Info.plist ├── ViewController.h ├── ViewController.m └── main.m /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata 19 | 20 | ## Other 21 | *.xccheckout 22 | *.moved-aside 23 | *.xcuserstate 24 | *.xcscmblueprint 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | *.ipa 29 | 30 | # CocoaPods 31 | # 32 | # We recommend against adding the Pods directory to your .gitignore. However 33 | # you should judge for yourself, the pros and cons are mentioned at: 34 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 35 | # 36 | #Pods/ 37 | 38 | # Carthage 39 | # 40 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 41 | # Carthage/Checkouts 42 | 43 | Carthage/Build 44 | 45 | \.DS_Store 46 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2018 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 仿 iOS 系统的 SpringBoard 2 | --- 3 | 4 | 该项目有以下几大功能。 5 | 6 | - 拖动排序 7 | - 拖动合并文件夹 8 | - 自动合并图标 9 | - 文件夹改名 10 | - 文件夹内排序 11 | - 拖动从文件夹移除 12 | - 文件夹内超过9个可以翻页查看 13 | 14 | `下面的 gif 加载的比较慢。对你有帮助的话请给个 star,谢谢啦` 15 | 16 | ![拖动排序合并](http://upload-images.jianshu.io/upload_images/2024647-0e56b4d288b10123.gif?imageMogr2/auto-orient/strip) -------------------------------------------------------------------------------- /UICollectionView拖动排序.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 38AB7DFB1E8DFA5B004C0A46 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 38AB7DFA1E8DFA5B004C0A46 /* main.m */; }; 11 | 38AB7DFE1E8DFA5B004C0A46 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 38AB7DFD1E8DFA5B004C0A46 /* AppDelegate.m */; }; 12 | 38AB7E011E8DFA5B004C0A46 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 38AB7E001E8DFA5B004C0A46 /* ViewController.m */; }; 13 | 38AB7E041E8DFA5B004C0A46 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 38AB7E021E8DFA5B004C0A46 /* Main.storyboard */; }; 14 | 38AB7E061E8DFA5B004C0A46 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 38AB7E051E8DFA5B004C0A46 /* Assets.xcassets */; }; 15 | 38AB7E091E8DFA5B004C0A46 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 38AB7E071E8DFA5B004C0A46 /* LaunchScreen.storyboard */; }; 16 | 38BEF53D1E9DB96E00798528 /* MergeCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 38BEF5361E9DB96E00798528 /* MergeCollectionViewCell.m */; }; 17 | 38BEF53E1E9DB96E00798528 /* MergeCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 38BEF5371E9DB96E00798528 /* MergeCollectionViewCell.xib */; }; 18 | 38BEF53F1E9DB96E00798528 /* MergeDetailView.m in Sources */ = {isa = PBXBuildFile; fileRef = 38BEF53B1E9DB96E00798528 /* MergeDetailView.m */; }; 19 | 38BEF5401E9DB96E00798528 /* MergeDetailView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 38BEF53C1E9DB96E00798528 /* MergeDetailView.xib */; }; 20 | 38BEF5461E9DBDCB00798528 /* MergeCollectionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 38BEF5451E9DBDCB00798528 /* MergeCollectionView.m */; }; 21 | 38E963F11E9C69FF002B99C2 /* SortViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 38E963EC1E9C69FF002B99C2 /* SortViewController.m */; }; 22 | 38E963F21E9C69FF002B99C2 /* MergeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 38E963EF1E9C69FF002B99C2 /* MergeViewController.m */; }; 23 | /* End PBXBuildFile section */ 24 | 25 | /* Begin PBXFileReference section */ 26 | 38AB7DF61E8DFA5B004C0A46 /* UICollectionView拖动排序.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "UICollectionView拖动排序.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 27 | 38AB7DFA1E8DFA5B004C0A46 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 28 | 38AB7DFC1E8DFA5B004C0A46 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 29 | 38AB7DFD1E8DFA5B004C0A46 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 30 | 38AB7DFF1E8DFA5B004C0A46 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 31 | 38AB7E001E8DFA5B004C0A46 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 32 | 38AB7E031E8DFA5B004C0A46 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 33 | 38AB7E051E8DFA5B004C0A46 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 34 | 38AB7E081E8DFA5B004C0A46 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 35 | 38AB7E0A1E8DFA5B004C0A46 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 36 | 38BEF5351E9DB96E00798528 /* MergeCollectionViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MergeCollectionViewCell.h; sourceTree = ""; }; 37 | 38BEF5361E9DB96E00798528 /* MergeCollectionViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MergeCollectionViewCell.m; sourceTree = ""; }; 38 | 38BEF5371E9DB96E00798528 /* MergeCollectionViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MergeCollectionViewCell.xib; sourceTree = ""; }; 39 | 38BEF53A1E9DB96E00798528 /* MergeDetailView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MergeDetailView.h; sourceTree = ""; }; 40 | 38BEF53B1E9DB96E00798528 /* MergeDetailView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MergeDetailView.m; sourceTree = ""; }; 41 | 38BEF53C1E9DB96E00798528 /* MergeDetailView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MergeDetailView.xib; sourceTree = ""; }; 42 | 38BEF5431E9DBAB400798528 /* Config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Config.h; sourceTree = ""; }; 43 | 38BEF5441E9DBDCB00798528 /* MergeCollectionView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MergeCollectionView.h; sourceTree = ""; }; 44 | 38BEF5451E9DBDCB00798528 /* MergeCollectionView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MergeCollectionView.m; sourceTree = ""; }; 45 | 38E963EB1E9C69FF002B99C2 /* SortViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SortViewController.h; sourceTree = ""; }; 46 | 38E963EC1E9C69FF002B99C2 /* SortViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SortViewController.m; sourceTree = ""; }; 47 | 38E963EE1E9C69FF002B99C2 /* MergeViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MergeViewController.h; sourceTree = ""; }; 48 | 38E963EF1E9C69FF002B99C2 /* MergeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MergeViewController.m; sourceTree = ""; }; 49 | /* End PBXFileReference section */ 50 | 51 | /* Begin PBXFrameworksBuildPhase section */ 52 | 38AB7DF31E8DFA5B004C0A46 /* Frameworks */ = { 53 | isa = PBXFrameworksBuildPhase; 54 | buildActionMask = 2147483647; 55 | files = ( 56 | ); 57 | runOnlyForDeploymentPostprocessing = 0; 58 | }; 59 | /* End PBXFrameworksBuildPhase section */ 60 | 61 | /* Begin PBXGroup section */ 62 | 386B75571E94C83E00081D09 /* Controller */ = { 63 | isa = PBXGroup; 64 | children = ( 65 | 38BEF5331E9DB96E00798528 /* Support */, 66 | 38E963EA1E9C69FF002B99C2 /* 1拖动排序 */, 67 | 38E963ED1E9C69FF002B99C2 /* 2拖动排序+合并 */, 68 | ); 69 | path = Controller; 70 | sourceTree = ""; 71 | }; 72 | 38AB7DED1E8DFA5B004C0A46 = { 73 | isa = PBXGroup; 74 | children = ( 75 | 38AB7DF81E8DFA5B004C0A46 /* UICollectionView拖动排序 */, 76 | 38AB7DF71E8DFA5B004C0A46 /* Products */, 77 | ); 78 | sourceTree = ""; 79 | }; 80 | 38AB7DF71E8DFA5B004C0A46 /* Products */ = { 81 | isa = PBXGroup; 82 | children = ( 83 | 38AB7DF61E8DFA5B004C0A46 /* UICollectionView拖动排序.app */, 84 | ); 85 | name = Products; 86 | sourceTree = ""; 87 | }; 88 | 38AB7DF81E8DFA5B004C0A46 /* UICollectionView拖动排序 */ = { 89 | isa = PBXGroup; 90 | children = ( 91 | 386B75571E94C83E00081D09 /* Controller */, 92 | 38AB7DFC1E8DFA5B004C0A46 /* AppDelegate.h */, 93 | 38AB7DFD1E8DFA5B004C0A46 /* AppDelegate.m */, 94 | 38AB7DFF1E8DFA5B004C0A46 /* ViewController.h */, 95 | 38AB7E001E8DFA5B004C0A46 /* ViewController.m */, 96 | 38AB7E021E8DFA5B004C0A46 /* Main.storyboard */, 97 | 38AB7E051E8DFA5B004C0A46 /* Assets.xcassets */, 98 | 38AB7E071E8DFA5B004C0A46 /* LaunchScreen.storyboard */, 99 | 38AB7E0A1E8DFA5B004C0A46 /* Info.plist */, 100 | 38AB7DF91E8DFA5B004C0A46 /* Supporting Files */, 101 | ); 102 | path = "UICollectionView拖动排序"; 103 | sourceTree = ""; 104 | }; 105 | 38AB7DF91E8DFA5B004C0A46 /* Supporting Files */ = { 106 | isa = PBXGroup; 107 | children = ( 108 | 38AB7DFA1E8DFA5B004C0A46 /* main.m */, 109 | ); 110 | name = "Supporting Files"; 111 | sourceTree = ""; 112 | }; 113 | 38BEF5331E9DB96E00798528 /* Support */ = { 114 | isa = PBXGroup; 115 | children = ( 116 | 38BEF5431E9DBAB400798528 /* Config.h */, 117 | 38BEF5341E9DB96E00798528 /* Cell */, 118 | 38BEF5391E9DB96E00798528 /* View */, 119 | ); 120 | path = Support; 121 | sourceTree = ""; 122 | }; 123 | 38BEF5341E9DB96E00798528 /* Cell */ = { 124 | isa = PBXGroup; 125 | children = ( 126 | 38BEF5351E9DB96E00798528 /* MergeCollectionViewCell.h */, 127 | 38BEF5361E9DB96E00798528 /* MergeCollectionViewCell.m */, 128 | 38BEF5371E9DB96E00798528 /* MergeCollectionViewCell.xib */, 129 | ); 130 | path = Cell; 131 | sourceTree = ""; 132 | }; 133 | 38BEF5391E9DB96E00798528 /* View */ = { 134 | isa = PBXGroup; 135 | children = ( 136 | 38BEF5441E9DBDCB00798528 /* MergeCollectionView.h */, 137 | 38BEF5451E9DBDCB00798528 /* MergeCollectionView.m */, 138 | 38BEF53A1E9DB96E00798528 /* MergeDetailView.h */, 139 | 38BEF53B1E9DB96E00798528 /* MergeDetailView.m */, 140 | 38BEF53C1E9DB96E00798528 /* MergeDetailView.xib */, 141 | ); 142 | path = View; 143 | sourceTree = ""; 144 | }; 145 | 38E963EA1E9C69FF002B99C2 /* 1拖动排序 */ = { 146 | isa = PBXGroup; 147 | children = ( 148 | 38E963EB1E9C69FF002B99C2 /* SortViewController.h */, 149 | 38E963EC1E9C69FF002B99C2 /* SortViewController.m */, 150 | ); 151 | path = "1拖动排序"; 152 | sourceTree = ""; 153 | }; 154 | 38E963ED1E9C69FF002B99C2 /* 2拖动排序+合并 */ = { 155 | isa = PBXGroup; 156 | children = ( 157 | 38E963EE1E9C69FF002B99C2 /* MergeViewController.h */, 158 | 38E963EF1E9C69FF002B99C2 /* MergeViewController.m */, 159 | ); 160 | path = "2拖动排序+合并"; 161 | sourceTree = ""; 162 | }; 163 | /* End PBXGroup section */ 164 | 165 | /* Begin PBXNativeTarget section */ 166 | 38AB7DF51E8DFA5B004C0A46 /* UICollectionView拖动排序 */ = { 167 | isa = PBXNativeTarget; 168 | buildConfigurationList = 38AB7E0D1E8DFA5B004C0A46 /* Build configuration list for PBXNativeTarget "UICollectionView拖动排序" */; 169 | buildPhases = ( 170 | 38AB7DF21E8DFA5B004C0A46 /* Sources */, 171 | 38AB7DF31E8DFA5B004C0A46 /* Frameworks */, 172 | 38AB7DF41E8DFA5B004C0A46 /* Resources */, 173 | ); 174 | buildRules = ( 175 | ); 176 | dependencies = ( 177 | ); 178 | name = "UICollectionView拖动排序"; 179 | productName = "UICollectionView拖动排序"; 180 | productReference = 38AB7DF61E8DFA5B004C0A46 /* UICollectionView拖动排序.app */; 181 | productType = "com.apple.product-type.application"; 182 | }; 183 | /* End PBXNativeTarget section */ 184 | 185 | /* Begin PBXProject section */ 186 | 38AB7DEE1E8DFA5B004C0A46 /* Project object */ = { 187 | isa = PBXProject; 188 | attributes = { 189 | LastUpgradeCheck = 0920; 190 | ORGANIZATIONNAME = Lym; 191 | TargetAttributes = { 192 | 38AB7DF51E8DFA5B004C0A46 = { 193 | CreatedOnToolsVersion = 8.3; 194 | DevelopmentTeam = PT38H38E4T; 195 | ProvisioningStyle = Automatic; 196 | }; 197 | }; 198 | }; 199 | buildConfigurationList = 38AB7DF11E8DFA5B004C0A46 /* Build configuration list for PBXProject "UICollectionView拖动排序" */; 200 | compatibilityVersion = "Xcode 3.2"; 201 | developmentRegion = English; 202 | hasScannedForEncodings = 0; 203 | knownRegions = ( 204 | en, 205 | Base, 206 | ); 207 | mainGroup = 38AB7DED1E8DFA5B004C0A46; 208 | productRefGroup = 38AB7DF71E8DFA5B004C0A46 /* Products */; 209 | projectDirPath = ""; 210 | projectRoot = ""; 211 | targets = ( 212 | 38AB7DF51E8DFA5B004C0A46 /* UICollectionView拖动排序 */, 213 | ); 214 | }; 215 | /* End PBXProject section */ 216 | 217 | /* Begin PBXResourcesBuildPhase section */ 218 | 38AB7DF41E8DFA5B004C0A46 /* Resources */ = { 219 | isa = PBXResourcesBuildPhase; 220 | buildActionMask = 2147483647; 221 | files = ( 222 | 38AB7E091E8DFA5B004C0A46 /* LaunchScreen.storyboard in Resources */, 223 | 38BEF5401E9DB96E00798528 /* MergeDetailView.xib in Resources */, 224 | 38AB7E061E8DFA5B004C0A46 /* Assets.xcassets in Resources */, 225 | 38BEF53E1E9DB96E00798528 /* MergeCollectionViewCell.xib in Resources */, 226 | 38AB7E041E8DFA5B004C0A46 /* Main.storyboard in Resources */, 227 | ); 228 | runOnlyForDeploymentPostprocessing = 0; 229 | }; 230 | /* End PBXResourcesBuildPhase section */ 231 | 232 | /* Begin PBXSourcesBuildPhase section */ 233 | 38AB7DF21E8DFA5B004C0A46 /* Sources */ = { 234 | isa = PBXSourcesBuildPhase; 235 | buildActionMask = 2147483647; 236 | files = ( 237 | 38BEF53F1E9DB96E00798528 /* MergeDetailView.m in Sources */, 238 | 38AB7E011E8DFA5B004C0A46 /* ViewController.m in Sources */, 239 | 38BEF5461E9DBDCB00798528 /* MergeCollectionView.m in Sources */, 240 | 38AB7DFE1E8DFA5B004C0A46 /* AppDelegate.m in Sources */, 241 | 38E963F11E9C69FF002B99C2 /* SortViewController.m in Sources */, 242 | 38AB7DFB1E8DFA5B004C0A46 /* main.m in Sources */, 243 | 38BEF53D1E9DB96E00798528 /* MergeCollectionViewCell.m in Sources */, 244 | 38E963F21E9C69FF002B99C2 /* MergeViewController.m in Sources */, 245 | ); 246 | runOnlyForDeploymentPostprocessing = 0; 247 | }; 248 | /* End PBXSourcesBuildPhase section */ 249 | 250 | /* Begin PBXVariantGroup section */ 251 | 38AB7E021E8DFA5B004C0A46 /* Main.storyboard */ = { 252 | isa = PBXVariantGroup; 253 | children = ( 254 | 38AB7E031E8DFA5B004C0A46 /* Base */, 255 | ); 256 | name = Main.storyboard; 257 | sourceTree = ""; 258 | }; 259 | 38AB7E071E8DFA5B004C0A46 /* LaunchScreen.storyboard */ = { 260 | isa = PBXVariantGroup; 261 | children = ( 262 | 38AB7E081E8DFA5B004C0A46 /* Base */, 263 | ); 264 | name = LaunchScreen.storyboard; 265 | sourceTree = ""; 266 | }; 267 | /* End PBXVariantGroup section */ 268 | 269 | /* Begin XCBuildConfiguration section */ 270 | 38AB7E0B1E8DFA5B004C0A46 /* Debug */ = { 271 | isa = XCBuildConfiguration; 272 | buildSettings = { 273 | ALWAYS_SEARCH_USER_PATHS = NO; 274 | CLANG_ANALYZER_NONNULL = YES; 275 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 276 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 277 | CLANG_CXX_LIBRARY = "libc++"; 278 | CLANG_ENABLE_MODULES = YES; 279 | CLANG_ENABLE_OBJC_ARC = YES; 280 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 281 | CLANG_WARN_BOOL_CONVERSION = YES; 282 | CLANG_WARN_COMMA = YES; 283 | CLANG_WARN_CONSTANT_CONVERSION = YES; 284 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 285 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 286 | CLANG_WARN_EMPTY_BODY = YES; 287 | CLANG_WARN_ENUM_CONVERSION = YES; 288 | CLANG_WARN_INFINITE_RECURSION = YES; 289 | CLANG_WARN_INT_CONVERSION = YES; 290 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 291 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 292 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 293 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 294 | CLANG_WARN_STRICT_PROTOTYPES = YES; 295 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 296 | CLANG_WARN_UNREACHABLE_CODE = YES; 297 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 298 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 299 | COPY_PHASE_STRIP = NO; 300 | DEBUG_INFORMATION_FORMAT = dwarf; 301 | ENABLE_STRICT_OBJC_MSGSEND = YES; 302 | ENABLE_TESTABILITY = YES; 303 | GCC_C_LANGUAGE_STANDARD = gnu99; 304 | GCC_DYNAMIC_NO_PIC = NO; 305 | GCC_NO_COMMON_BLOCKS = YES; 306 | GCC_OPTIMIZATION_LEVEL = 0; 307 | GCC_PREPROCESSOR_DEFINITIONS = ( 308 | "DEBUG=1", 309 | "$(inherited)", 310 | ); 311 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 312 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 313 | GCC_WARN_UNDECLARED_SELECTOR = YES; 314 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 315 | GCC_WARN_UNUSED_FUNCTION = YES; 316 | GCC_WARN_UNUSED_VARIABLE = YES; 317 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 318 | MTL_ENABLE_DEBUG_INFO = YES; 319 | ONLY_ACTIVE_ARCH = YES; 320 | SDKROOT = iphoneos; 321 | }; 322 | name = Debug; 323 | }; 324 | 38AB7E0C1E8DFA5B004C0A46 /* Release */ = { 325 | isa = XCBuildConfiguration; 326 | buildSettings = { 327 | ALWAYS_SEARCH_USER_PATHS = NO; 328 | CLANG_ANALYZER_NONNULL = YES; 329 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 330 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 331 | CLANG_CXX_LIBRARY = "libc++"; 332 | CLANG_ENABLE_MODULES = YES; 333 | CLANG_ENABLE_OBJC_ARC = YES; 334 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 335 | CLANG_WARN_BOOL_CONVERSION = YES; 336 | CLANG_WARN_COMMA = YES; 337 | CLANG_WARN_CONSTANT_CONVERSION = YES; 338 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 339 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 340 | CLANG_WARN_EMPTY_BODY = YES; 341 | CLANG_WARN_ENUM_CONVERSION = YES; 342 | CLANG_WARN_INFINITE_RECURSION = YES; 343 | CLANG_WARN_INT_CONVERSION = YES; 344 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 345 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 346 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 347 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 348 | CLANG_WARN_STRICT_PROTOTYPES = YES; 349 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 350 | CLANG_WARN_UNREACHABLE_CODE = YES; 351 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 352 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 353 | COPY_PHASE_STRIP = NO; 354 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 355 | ENABLE_NS_ASSERTIONS = NO; 356 | ENABLE_STRICT_OBJC_MSGSEND = YES; 357 | GCC_C_LANGUAGE_STANDARD = gnu99; 358 | GCC_NO_COMMON_BLOCKS = YES; 359 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 360 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 361 | GCC_WARN_UNDECLARED_SELECTOR = YES; 362 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 363 | GCC_WARN_UNUSED_FUNCTION = YES; 364 | GCC_WARN_UNUSED_VARIABLE = YES; 365 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 366 | MTL_ENABLE_DEBUG_INFO = NO; 367 | SDKROOT = iphoneos; 368 | VALIDATE_PRODUCT = YES; 369 | }; 370 | name = Release; 371 | }; 372 | 38AB7E0E1E8DFA5B004C0A46 /* Debug */ = { 373 | isa = XCBuildConfiguration; 374 | buildSettings = { 375 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 376 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 377 | DEVELOPMENT_TEAM = PT38H38E4T; 378 | INFOPLIST_FILE = "UICollectionView拖动排序/Info.plist"; 379 | IPHONEOS_DEPLOYMENT_TARGET = 10.2; 380 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 381 | PRODUCT_BUNDLE_IDENTIFIER = "com.Lym.UICollectionView----"; 382 | PRODUCT_NAME = "$(TARGET_NAME)"; 383 | }; 384 | name = Debug; 385 | }; 386 | 38AB7E0F1E8DFA5B004C0A46 /* Release */ = { 387 | isa = XCBuildConfiguration; 388 | buildSettings = { 389 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 390 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 391 | DEVELOPMENT_TEAM = PT38H38E4T; 392 | INFOPLIST_FILE = "UICollectionView拖动排序/Info.plist"; 393 | IPHONEOS_DEPLOYMENT_TARGET = 10.2; 394 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 395 | PRODUCT_BUNDLE_IDENTIFIER = "com.Lym.UICollectionView----"; 396 | PRODUCT_NAME = "$(TARGET_NAME)"; 397 | }; 398 | name = Release; 399 | }; 400 | /* End XCBuildConfiguration section */ 401 | 402 | /* Begin XCConfigurationList section */ 403 | 38AB7DF11E8DFA5B004C0A46 /* Build configuration list for PBXProject "UICollectionView拖动排序" */ = { 404 | isa = XCConfigurationList; 405 | buildConfigurations = ( 406 | 38AB7E0B1E8DFA5B004C0A46 /* Debug */, 407 | 38AB7E0C1E8DFA5B004C0A46 /* Release */, 408 | ); 409 | defaultConfigurationIsVisible = 0; 410 | defaultConfigurationName = Release; 411 | }; 412 | 38AB7E0D1E8DFA5B004C0A46 /* Build configuration list for PBXNativeTarget "UICollectionView拖动排序" */ = { 413 | isa = XCConfigurationList; 414 | buildConfigurations = ( 415 | 38AB7E0E1E8DFA5B004C0A46 /* Debug */, 416 | 38AB7E0F1E8DFA5B004C0A46 /* Release */, 417 | ); 418 | defaultConfigurationIsVisible = 0; 419 | defaultConfigurationName = Release; 420 | }; 421 | /* End XCConfigurationList section */ 422 | }; 423 | rootObject = 38AB7DEE1E8DFA5B004C0A46 /* Project object */; 424 | } 425 | -------------------------------------------------------------------------------- /UICollectionView拖动排序.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /UICollectionView拖动排序/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // UICollectionView拖动排序 4 | // 5 | // Created by Lym on 2017/3/31. 6 | // Copyright © 2017年 Lym. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /UICollectionView拖动排序/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // UICollectionView拖动排序 4 | // 5 | // Created by Lym on 2017/3/31. 6 | // Copyright © 2017年 Lym. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "ViewController.h" 11 | 12 | @interface AppDelegate () 13 | 14 | @end 15 | 16 | @implementation AppDelegate 17 | 18 | 19 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 20 | UINavigationController *nvc = [[UINavigationController alloc] initWithRootViewController:[[ViewController alloc] init]]; 21 | self.window.rootViewController = nvc; 22 | [self.window makeKeyAndVisible]; 23 | return YES; 24 | } 25 | 26 | 27 | - (void)applicationWillResignActive:(UIApplication *)application { 28 | // 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. 29 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 30 | } 31 | 32 | 33 | - (void)applicationDidEnterBackground:(UIApplication *)application { 34 | // 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. 35 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 36 | } 37 | 38 | 39 | - (void)applicationWillEnterForeground:(UIApplication *)application { 40 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 41 | } 42 | 43 | 44 | - (void)applicationDidBecomeActive:(UIApplication *)application { 45 | // 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. 46 | } 47 | 48 | 49 | - (void)applicationWillTerminate:(UIApplication *)application { 50 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 51 | } 52 | 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /UICollectionView拖动排序/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | } 43 | ], 44 | "info" : { 45 | "version" : 1, 46 | "author" : "xcode" 47 | } 48 | } -------------------------------------------------------------------------------- /UICollectionView拖动排序/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /UICollectionView拖动排序/Assets.xcassets/icon1.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "Icon-60@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "Icon-60@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /UICollectionView拖动排序/Assets.xcassets/icon1.imageset/Icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2015lym/MergeCollectionView/291b74c7f20c8b5bb93b9bf4a75ca8c8f2c7e882/UICollectionView拖动排序/Assets.xcassets/icon1.imageset/Icon-60@2x.png -------------------------------------------------------------------------------- /UICollectionView拖动排序/Assets.xcassets/icon1.imageset/Icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2015lym/MergeCollectionView/291b74c7f20c8b5bb93b9bf4a75ca8c8f2c7e882/UICollectionView拖动排序/Assets.xcassets/icon1.imageset/Icon-60@3x.png -------------------------------------------------------------------------------- /UICollectionView拖动排序/Assets.xcassets/icon2.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "多云@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "多云@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /UICollectionView拖动排序/Assets.xcassets/icon2.imageset/多云@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2015lym/MergeCollectionView/291b74c7f20c8b5bb93b9bf4a75ca8c8f2c7e882/UICollectionView拖动排序/Assets.xcassets/icon2.imageset/多云@2x.png -------------------------------------------------------------------------------- /UICollectionView拖动排序/Assets.xcassets/icon2.imageset/多云@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2015lym/MergeCollectionView/291b74c7f20c8b5bb93b9bf4a75ca8c8f2c7e882/UICollectionView拖动排序/Assets.xcassets/icon2.imageset/多云@3x.png -------------------------------------------------------------------------------- /UICollectionView拖动排序/Assets.xcassets/proper_logo.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "proper_logo.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /UICollectionView拖动排序/Assets.xcassets/proper_logo.imageset/proper_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2015lym/MergeCollectionView/291b74c7f20c8b5bb93b9bf4a75ca8c8f2c7e882/UICollectionView拖动排序/Assets.xcassets/proper_logo.imageset/proper_logo.png -------------------------------------------------------------------------------- /UICollectionView拖动排序/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /UICollectionView拖动排序/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /UICollectionView拖动排序/Controller/1拖动排序/SortViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // SortViewController.h 3 | // UICollectionView拖动排序 4 | // 5 | // Created by Lym on 2017/4/5. 6 | // Copyright © 2017年 Lym. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SortViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /UICollectionView拖动排序/Controller/1拖动排序/SortViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // SortViewController.m 3 | // UICollectionView拖动排序 4 | // 5 | // Created by Lym on 2017/4/5. 6 | // Copyright © 2017年 Lym. All rights reserved. 7 | // 8 | 9 | #import "SortViewController.h" 10 | #import "MergeCollectionViewCell.h" 11 | #import "MergeCollectionView.h" 12 | #import "Config.h" 13 | 14 | static const int ITEM_NUMBER = 50; //item数量 15 | 16 | @interface SortViewController () 17 | @property (nonatomic, strong) NSMutableArray *dataArray; 18 | @property (nonatomic, strong) MergeCollectionView *collectionView; 19 | @end 20 | 21 | @implementation SortViewController 22 | 23 | #pragma mark - ---------- 生命周期 ---------- 24 | - (void)viewDidLoad { 25 | [super viewDidLoad]; 26 | 27 | [self createCollectionView]; 28 | 29 | _dataArray = [NSMutableArray array]; 30 | 31 | //产生随机颜色的方块 32 | for (int i = 1; i <= ITEM_NUMBER; i++) { 33 | NSString *str = [NSString stringWithFormat:@"%d", i]; 34 | [_dataArray addObject:str]; 35 | } 36 | } 37 | 38 | - (void)didReceiveMemoryWarning { 39 | [super didReceiveMemoryWarning]; 40 | } 41 | 42 | #pragma mark - ---------- 创建collectionView ---------- 43 | - (void)createCollectionView { 44 | 45 | _collectionView = [[MergeCollectionView alloc] initWithFrame:CGRectMake(0, 20, SCREEN_WIDTH, SCREEN_HEIGHT - 20)]; 46 | _collectionView.delegate = self; 47 | _collectionView.dataSource = self; 48 | [self.view addSubview:self.collectionView]; 49 | 50 | /* 51 | * 增加长按手势 52 | * 触发长按事件时间为0.5秒 53 | */ 54 | UILongPressGestureRecognizer *longGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handlelongGesture:)]; 55 | longGesture.minimumPressDuration = 0.5f; 56 | [_collectionView addGestureRecognizer:longGesture]; 57 | } 58 | 59 | #pragma mark - ---------- item数量 ---------- 60 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{ 61 | return _dataArray.count; 62 | } 63 | 64 | #pragma mark - ---------- Cell的内容 ---------- 65 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{ 66 | MergeCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"MergeCollectionViewCell" 67 | forIndexPath:indexPath]; 68 | cell.contentLabel.text = [NSString stringWithFormat:@"请假审批%@", _dataArray[indexPath.row]]; 69 | cell.imageView.image = [UIImage imageNamed:@"proper_logo"]; 70 | return cell; 71 | } 72 | 73 | #pragma mark - ---------- 允许拖动 ---------- 74 | - (BOOL)collectionView:(UICollectionView *)collectionView canMoveItemAtIndexPath:(NSIndexPath *)indexPath{ 75 | return YES; 76 | } 77 | 78 | #pragma mark - ---------- 更新数据源 ---------- 79 | - (void)collectionView:(UICollectionView *)collectionView moveItemAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath*)destinationIndexPath { 80 | //移除数据插入到新的位置 81 | id obj = [_dataArray objectAtIndex:sourceIndexPath.row]; 82 | [_dataArray removeObjectAtIndex:sourceIndexPath.row]; 83 | [_dataArray insertObject:obj 84 | atIndex:destinationIndexPath.row]; 85 | } 86 | 87 | - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { 88 | NSLog(@"%zd", indexPath.row); 89 | } 90 | 91 | 92 | #pragma mark - ---------- 拖动手势 ---------- 93 | - (void)handlelongGesture:(UILongPressGestureRecognizer *)longGesture { 94 | switch (longGesture.state) { 95 | case UIGestureRecognizerStateBegan:{//手势开始 96 | //判断手势落点位置是否在Item上 97 | NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:[longGesture locationInView:self.collectionView]]; 98 | if (indexPath == nil) { 99 | break; 100 | } 101 | UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:indexPath]; 102 | [self.collectionView bringSubviewToFront:cell]; 103 | //在Item上则开始移动该Item的cell 104 | [self.collectionView beginInteractiveMovementForItemAtIndexPath:indexPath]; 105 | } 106 | break; 107 | case UIGestureRecognizerStateChanged:{//手势改变 108 | //移动过程当中随时更新cell位置 109 | [self.collectionView updateInteractiveMovementTargetPosition:[longGesture locationInView:self.collectionView]]; 110 | } 111 | break; 112 | case UIGestureRecognizerStateEnded:{//手势结束 113 | //移动结束后关闭cell移动 114 | [self.collectionView endInteractiveMovement]; 115 | } 116 | break; 117 | default://手势其他状态 118 | [self.collectionView cancelInteractiveMovement]; 119 | break; 120 | } 121 | } 122 | 123 | //以下方法可以全部注释,注释后失去长按放大效果 124 | #pragma mark - ---------- 允许长按 ---------- 125 | - (BOOL)collectionView:(UICollectionView *)collectionView shouldHighlightItemAtIndexPath:(NSIndexPath *)indexPath{ 126 | return YES; 127 | } 128 | 129 | #pragma mark - ---------- didHighlight ---------- 130 | - (void)collectionView:(UICollectionView *)collectionView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath{ 131 | UICollectionViewCell *selectedCell = [collectionView cellForItemAtIndexPath:indexPath]; 132 | [collectionView bringSubviewToFront:selectedCell]; 133 | [UIView animateWithDuration:0.28 animations:^{ 134 | selectedCell.transform = CGAffineTransformMakeScale(1.2f, 1.2f); 135 | }]; 136 | } 137 | 138 | #pragma mark - ---------- didUnhighlight ---------- 139 | - (void)collectionView:(UICollectionView *)collectionView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath{ 140 | UICollectionViewCell *selectedCell = [collectionView cellForItemAtIndexPath:indexPath]; 141 | [UIView animateWithDuration:0.28 animations:^{ 142 | selectedCell.transform = CGAffineTransformMakeScale(1.0f, 1.0f); 143 | }]; 144 | } 145 | 146 | @end 147 | -------------------------------------------------------------------------------- /UICollectionView拖动排序/Controller/2拖动排序+合并/MergeViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // MergeViewController.h 3 | // UICollectionView拖动排序 4 | // 5 | // Created by Lym on 2017/4/5. 6 | // Copyright © 2017年 Lym. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface MergeViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /UICollectionView拖动排序/Controller/2拖动排序+合并/MergeViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // MergeViewController.m 3 | // UICollectionView拖动排序 4 | // 5 | // Created by Lym on 2017/4/5. 6 | // Copyright © 2017年 Lym. All rights reserved. 7 | // 8 | 9 | #import "MergeViewController.h" 10 | #import "MergeCollectionViewCell.h" 11 | #import "MergeCollectionView.h" 12 | #import "MergeDetailView.h" 13 | #import "Config.h" 14 | 15 | static const int ITEM_NUMBER = 10; //item数量 16 | static const NSString *kImage = @"image"; //logo图片 17 | static const NSString *kTitle = @"title"; //图片标题 18 | 19 | typedef NS_ENUM(NSInteger, kMoveType){ 20 | kMoveTypeNone, 21 | kMoveTypeExchange, 22 | kMoveTypeMerge 23 | }; 24 | 25 | @interface MergeViewController () 26 | 27 | @property (nonatomic, strong) MergeCollectionView *collectionView; 28 | @property (nonatomic, strong) UIView *grayView; 29 | 30 | 31 | @property (nonatomic, strong) NSMutableArray *dataArray; //数据源数组 32 | @property (nonatomic, strong) NSMutableArray *containerArray; //记录包含合并的数组 33 | 34 | @property (nonatomic, assign) kMoveType moveType; //移动类型 35 | 36 | @end 37 | 38 | @implementation MergeViewController 39 | - (NSMutableArray *)containerArray{ 40 | if (!_containerArray) { 41 | _containerArray = [[NSMutableArray alloc]init]; 42 | } 43 | return _containerArray; 44 | } 45 | 46 | - (void)viewDidLoad { 47 | [super viewDidLoad]; 48 | [self createCollectionView]; 49 | _moveType = kMoveTypeNone; 50 | 51 | _dataArray = [NSMutableArray array]; 52 | //添加数据源 53 | for (int i = 1; i <= ITEM_NUMBER; i++) { 54 | NSString *str = [NSString stringWithFormat:@"请假审批%d", i]; 55 | UIImage *image = [UIImage imageNamed:@"proper_logo"]; 56 | NSDictionary *dic = @{kImage:image,kTitle:str}; 57 | [_dataArray addObject:dic]; 58 | [self.containerArray addObject:@[dic]]; 59 | } 60 | } 61 | - (void)didReceiveMemoryWarning { 62 | [super didReceiveMemoryWarning]; 63 | } 64 | 65 | #pragma mark - ---------- 创建collectionView ---------- 66 | - (void)createCollectionView { 67 | 68 | _collectionView = [[MergeCollectionView alloc] initWithFrame:CGRectMake(0, 20, SCREEN_WIDTH, SCREEN_HEIGHT - 20)]; 69 | _collectionView.delegate = self; 70 | _collectionView.dataSource = self; 71 | [self.view addSubview:self.collectionView]; 72 | 73 | /* 74 | * 增加长按手势 75 | * 触发长按事件时间为0.5秒 76 | */ 77 | UILongPressGestureRecognizer *longGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handlelongGesture:)]; 78 | longGesture.minimumPressDuration = 0.5f; 79 | [_collectionView addGestureRecognizer:longGesture]; 80 | } 81 | 82 | 83 | #pragma mark - ---------- item数量 ---------- 84 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { 85 | return self.dataArray.count; 86 | } 87 | 88 | #pragma mark - ---------- Cell的内容 ---------- 89 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { 90 | MergeCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"MergeCollectionViewCell" 91 | forIndexPath:indexPath]; 92 | cell.contentLabel.text = self.dataArray[indexPath.item][kTitle]; 93 | cell.imageView.image = self.dataArray[indexPath.item][kImage]; 94 | return cell; 95 | } 96 | 97 | #pragma mark - ---------- Cell的点击事件 ---------- 98 | - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { 99 | if (_containerArray[indexPath.item].count != 1) { 100 | [self setGrayView]; 101 | UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:indexPath]; 102 | __block MergeDetailView *detailView = [[NSBundle mainBundle] loadNibNamed:@"MergeDetailView" owner:self options:nil].lastObject; 103 | __weak MergeDetailView *weakDetailView = detailView; 104 | detailView.frame = CGRectMake(SCREEN_WIDTH/8, 105 | (SCREEN_HEIGHT - 3 * SCREEN_WIDTH/4)/2 - 50, 106 | 3 * SCREEN_WIDTH/4 + 1, 107 | 3 * SCREEN_WIDTH/4 + 100); 108 | detailView.backgroundColor = [UIColor clearColor]; 109 | detailView.folderTitleTextField.text = _dataArray[indexPath.item][kTitle]; 110 | detailView.dataArray = [NSMutableArray arrayWithArray:self.containerArray[indexPath.item]]; 111 | detailView.folderTitle = ^(NSString *title) { 112 | [_dataArray replaceObjectAtIndex:indexPath.item withObject:@{kTitle:title,kImage:_dataArray[indexPath.item][kImage]}]; 113 | }; 114 | detailView.removeItem = ^(NSDictionary *item){ 115 | NSMutableArray *mutableArr = [[NSMutableArray alloc]init]; 116 | [mutableArr addObjectsFromArray:self.containerArray[indexPath.item]]; 117 | [mutableArr removeObject:item]; 118 | [self.containerArray replaceObjectAtIndex:indexPath.item withObject:mutableArr]; 119 | [self.containerArray addObject:@[item]]; 120 | 121 | [_dataArray addObject:item]; 122 | if (self.containerArray[indexPath.item].count == 1) { 123 | [_dataArray replaceObjectAtIndex:indexPath.item withObject:@{kTitle:self.containerArray[indexPath.item][0][kTitle],kImage:self.containerArray[indexPath.item][0][kImage]}]; 124 | [weakDetailView dismissContactView]; 125 | }else{ 126 | [_dataArray replaceObjectAtIndex:indexPath.item withObject:@{kTitle:_dataArray[indexPath.item][kTitle],kImage:[self setMergeImageWithImageArray:self.containerArray[indexPath.item]]}]; 127 | NSIndexPath *insertPath = [NSIndexPath indexPathForRow:_dataArray.count-1 inSection:0]; 128 | [self.collectionView insertItemsAtIndexPaths:@[insertPath]]; 129 | } 130 | }; 131 | [_grayView addSubview:detailView]; 132 | [detailView openCell: [self.view convertRect:cell.frame toView:detailView]]; 133 | // cell.hidden = YES; 134 | detailView.close = ^(void){ 135 | // cell.hidden = NO; 136 | [self.collectionView reloadData]; 137 | }; 138 | } else { 139 | NSLog(@"%zd", indexPath.row); 140 | } 141 | } 142 | 143 | #pragma mark - ---------- 灰色背景 ---------- 144 | - (void)setGrayView { 145 | _grayView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)]; 146 | _grayView.backgroundColor = GRAYVIEW_COLOR; 147 | [[UIApplication sharedApplication].keyWindow addSubview:_grayView]; 148 | } 149 | 150 | #pragma mark - ---------- 拖动手势 ---------- 151 | static UIView *snapedView; //截图快照 152 | static NSIndexPath *currentIndexPath; //当前路径 153 | static NSIndexPath *oldIndexPath; //旧路径 154 | static NSIndexPath *startIndexPath; //起始路径 155 | - (void)handlelongGesture:(UILongPressGestureRecognizer *)longGesture{ 156 | _moveType = kMoveTypeNone; 157 | switch (longGesture.state) { 158 | case UIGestureRecognizerStateBegan:{//手势开始 159 | //判断手势落点位置是否在Item上 160 | oldIndexPath = [self.collectionView indexPathForItemAtPoint:[longGesture locationInView:self.collectionView]]; 161 | startIndexPath = oldIndexPath; 162 | if (oldIndexPath == nil) { 163 | break; 164 | } 165 | UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:oldIndexPath]; 166 | //使用系统截图功能,得到cell的截图视图 167 | 168 | snapedView = [cell snapshotViewAfterScreenUpdates:NO]; 169 | snapedView.frame = cell.frame; 170 | [self.collectionView addSubview:snapedView]; 171 | //截图后隐藏当前cell 172 | cell.hidden = YES; 173 | CGPoint currentPoint = [longGesture locationInView:self.collectionView]; 174 | [UIView animateWithDuration:0.25 animations:^{ 175 | snapedView.transform = CGAffineTransformMakeScale(1.2f, 1.2f); 176 | snapedView.center = CGPointMake(currentPoint.x, currentPoint.y); 177 | }]; 178 | } 179 | break; 180 | case UIGestureRecognizerStateChanged:{//手势改变 181 | //当前手指位置 - 截图视图位置移动 182 | CGPoint currentPoint = [longGesture locationInView:self.collectionView]; 183 | snapedView.center = CGPointMake(currentPoint.x, currentPoint.y); 184 | } 185 | break; 186 | default:{//手势结束和其他状态 187 | CGPoint currentPoint = [longGesture locationInView:self.collectionView]; 188 | snapedView.center = CGPointMake(currentPoint.x, currentPoint.y); 189 | 190 | //计算截图视图和哪个cell相交 191 | for (UICollectionViewCell *cell in [self.collectionView visibleCells]) { 192 | //当前隐藏的cell就不需要交换了,直接continue 193 | if ([self.collectionView indexPathForCell:cell] == oldIndexPath) { 194 | continue; 195 | } 196 | //计算中心距 197 | CGFloat space = sqrtf(pow(snapedView.center.x - cell.center.x, 2) + powf(snapedView.center.y - cell.center.y, 2)); 198 | NSLog(@"%f",space); 199 | //如果相交一半就移动 200 | if(space <= snapedView.bounds.size.width*3 / 4){ 201 | currentIndexPath = [self.collectionView indexPathForCell:cell]; 202 | //移动 会调用willMoveToIndexPath方法更新数据源 203 | _moveType = kMoveTypeExchange; 204 | //更改移动后的起始indexPath,用于后面获取隐藏的cell,是移动后的位置 205 | oldIndexPath = currentIndexPath; 206 | } 207 | //如果中心距离小于10就合并 208 | if (space <= 20.0) { 209 | //如果拖动的是一个合并过的cell,则不执行二次合并 210 | if (self.containerArray[startIndexPath.item].count==1) { 211 | currentIndexPath = [self.collectionView indexPathForCell:cell]; 212 | _moveType = kMoveTypeMerge; 213 | //更改移动后的起始indexPath,用于后面获取隐藏的cell,是移动前的位置 214 | oldIndexPath = startIndexPath; 215 | }else{ 216 | 217 | } 218 | } 219 | } 220 | if (_moveType == kMoveTypeExchange) { 221 | //移除数据插入到新的位置 222 | [self.collectionView moveItemAtIndexPath:startIndexPath toIndexPath:currentIndexPath]; 223 | id obj = [_dataArray objectAtIndex:startIndexPath.item]; 224 | [_dataArray removeObjectAtIndex:startIndexPath.item]; 225 | [_dataArray insertObject:obj 226 | atIndex:currentIndexPath.item]; 227 | id containerObj = [self.containerArray objectAtIndex:startIndexPath.item]; 228 | [self.containerArray removeObjectAtIndex:startIndexPath.item]; 229 | [self.containerArray insertObject:containerObj 230 | atIndex:currentIndexPath.item]; 231 | 232 | }else if (_moveType == kMoveTypeMerge){ 233 | //设置合并后的新数组 234 | NSMutableArray *mergeArray = [[NSMutableArray alloc]init]; 235 | [self.containerArray[currentIndexPath.item] enumerateObjectsUsingBlock:^(NSDictionary * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 236 | [mergeArray addObject:obj]; 237 | }]; 238 | [mergeArray addObject:self.containerArray[startIndexPath.item][0]]; 239 | [self.containerArray replaceObjectAtIndex:currentIndexPath.item withObject:mergeArray]; 240 | 241 | if (_containerArray[currentIndexPath.item].count == 2) { 242 | [_dataArray replaceObjectAtIndex:currentIndexPath.item withObject:@{kTitle:@"文件夹",kImage:[self setMergeImageWithImageArray:self.containerArray[currentIndexPath.item]]}]; 243 | } else { 244 | [_dataArray replaceObjectAtIndex:currentIndexPath.item withObject:@{kTitle:_dataArray[currentIndexPath.item][kTitle], kImage:[self setMergeImageWithImageArray:self.containerArray[currentIndexPath.item]]}]; 245 | } 246 | 247 | [_dataArray removeObjectAtIndex:startIndexPath.item]; 248 | [self.containerArray removeObjectAtIndex:startIndexPath.item]; 249 | }else if (_moveType == kMoveTypeNone){ 250 | currentIndexPath = startIndexPath; 251 | } 252 | UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:oldIndexPath];//原来隐藏的cell 253 | UICollectionViewCell *targetCell = [self.collectionView cellForItemAtIndexPath:currentIndexPath];//移动目标cell 254 | //结束动画过程中停止交互,防止出问题 255 | self.collectionView.userInteractionEnabled = NO; 256 | //给截图视图一个动画移动到隐藏cell的新位置 257 | [UIView animateWithDuration:0.25 animations:^{ 258 | snapedView.center = targetCell.center; 259 | snapedView.transform = CGAffineTransformMakeScale(1.0f, 1.0f); 260 | } completion:^(BOOL finished) { 261 | //移除截图视图、显示隐藏的cell并开启交互 262 | [snapedView removeFromSuperview]; 263 | cell.hidden = NO; 264 | self.collectionView.userInteractionEnabled = YES; 265 | [self.collectionView reloadData]; 266 | }]; 267 | } 268 | break; 269 | } 270 | } 271 | 272 | #pragma mark - ---------- 合成新图标 ---------- 273 | - (UIImage *)setMergeImageWithImageArray:(NSArray *)imageArray{ 274 | if (imageArray.count == 1) { 275 | return imageArray[0][kImage]; 276 | } 277 | //新图标大小 278 | CGSize size = CGSizeMake(SCREEN_WIDTH/4-40, SCREEN_WIDTH/4-40); 279 | UIGraphicsBeginImageContext(size); 280 | //从数组中取图片进行拼接 281 | [imageArray enumerateObjectsUsingBlock:^(NSDictionary* obj, NSUInteger idx, BOOL * _Nonnull stop) { 282 | UIImage *image = obj[kImage]; 283 | [image drawInRect:CGRectMake(15/WIDTH_5S_SCALE*(idx%3), 284 | 15/WIDTH_5S_SCALE*(idx/3), 285 | 10/WIDTH_5S_SCALE, 286 | 10/WIDTH_5S_SCALE)]; 287 | if (idx>=8) { 288 | *stop = YES; 289 | } 290 | }]; 291 | UIImage *resultImage = UIGraphicsGetImageFromCurrentImageContext(); 292 | UIGraphicsEndImageContext(); 293 | return resultImage; 294 | } 295 | @end 296 | -------------------------------------------------------------------------------- /UICollectionView拖动排序/Controller/5YYModel测试/AppModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppModel.m 3 | // UICollectionView拖动排序 4 | // 5 | // Created by Lym on 2017/4/13. 6 | // Copyright © 2017年 Lym. All rights reserved. 7 | // 8 | 9 | #import "AppModel.h" 10 | @implementation AppFolderListData 11 | 12 | @implementation AppFolderListData 13 | 14 | @end 15 | 16 | 17 | @implementation AppFolderList 18 | 19 | @end 20 | 21 | 22 | @implementation AppList 23 | 24 | @end 25 | 26 | 27 | @implementation AppModel 28 | 29 | 30 | @end 31 | //- (instancetype)initWithModel:(NSDictionary *)model{ 32 | // if (self = [super init]) { 33 | // [self setValuesForKeysWithDictionary:model]; 34 | // } 35 | // return self; 36 | //} 37 | // 38 | //- (void)setValue:(id)value forUndefinedKey:(NSString *)key{ 39 | // NSLog(@"%@",key); 40 | //} 41 | -------------------------------------------------------------------------------- /UICollectionView拖动排序/Controller/Support/Cell/MergeCollectionViewCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // MergeCollectionViewCell.h 3 | // UICollectionView拖动排序 4 | // 5 | // Created by Lym on 2017/3/31. 6 | // Copyright © 2017年 Lym. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface MergeCollectionViewCell : UICollectionViewCell 12 | 13 | @property (weak, nonatomic) IBOutlet UIImageView *imageView; 14 | @property (weak, nonatomic) IBOutlet UILabel *contentLabel; 15 | 16 | @property (weak, nonatomic) IBOutlet UIButton *badge; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /UICollectionView拖动排序/Controller/Support/Cell/MergeCollectionViewCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // MergeCollectionViewCell.m 3 | // UICollectionView拖动排序 4 | // 5 | // Created by Lym on 2017/3/31. 6 | // Copyright © 2017年 Lym. All rights reserved. 7 | // 8 | 9 | #import "MergeCollectionViewCell.h" 10 | 11 | @implementation MergeCollectionViewCell 12 | 13 | - (void)awakeFromNib { 14 | [super awakeFromNib]; 15 | self.badge.layer.cornerRadius = self.badge.frame.size.width / 2; 16 | } 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /UICollectionView拖动排序/Controller/Support/Cell/MergeCollectionViewCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 41 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 62 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /UICollectionView拖动排序/Controller/Support/Config.h: -------------------------------------------------------------------------------- 1 | // 2 | // Config.h 3 | // UICollectionView拖动排序 4 | // 5 | // Created by Lym on 2017/4/12. 6 | // Copyright © 2017年 Lym. All rights reserved. 7 | // 8 | 9 | #ifndef Config_h 10 | #define Config_h 11 | 12 | #define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width 13 | #define SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height 14 | #define WIDTH_5S_SCALE 320.0 * [UIScreen mainScreen].bounds.size.width 15 | 16 | 17 | #define GRAYVIEW_COLOR [UIColor colorWithRed:0/255.0 green:0/255.0 blue:0/255.0 alpha:0.5] 18 | 19 | #define TEXTFIELD_COLOR [UIColor colorWithRed:0/255.0 green:0/255.0 blue:0/255.0 alpha:0.6] 20 | 21 | #endif /* Config_h */ 22 | -------------------------------------------------------------------------------- /UICollectionView拖动排序/Controller/Support/View/MergeCollectionView.h: -------------------------------------------------------------------------------- 1 | // 2 | // MergeCollectionView.h 3 | // UICollectionView拖动排序 4 | // 5 | // Created by Lym on 2017/4/12. 6 | // Copyright © 2017年 Lym. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface MergeCollectionView : UICollectionView 12 | 13 | - (instancetype)initWithFrame:(CGRect)frame; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /UICollectionView拖动排序/Controller/Support/View/MergeCollectionView.m: -------------------------------------------------------------------------------- 1 | // 2 | // MergeCollectionView.m 3 | // UICollectionView拖动排序 4 | // 5 | // Created by Lym on 2017/4/12. 6 | // Copyright © 2017年 Lym. All rights reserved. 7 | // 8 | 9 | #import "MergeCollectionView.h" 10 | #import "Config.h" 11 | 12 | @implementation MergeCollectionView 13 | 14 | - (instancetype)initWithFrame:(CGRect)frame { 15 | UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; 16 | layout.itemSize = CGSizeMake((SCREEN_WIDTH-15) / 4, (SCREEN_WIDTH-15) / 4); 17 | layout.minimumLineSpacing = 5; 18 | layout.minimumInteritemSpacing = 5; 19 | self = [super initWithFrame:frame collectionViewLayout:layout]; 20 | self.backgroundColor = [UIColor groupTableViewBackgroundColor]; 21 | [self registerNib:[UINib nibWithNibName:@"MergeCollectionViewCell" bundle:nil] forCellWithReuseIdentifier:@"MergeCollectionViewCell"]; 22 | return self; 23 | } 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /UICollectionView拖动排序/Controller/Support/View/MergeDetailView.h: -------------------------------------------------------------------------------- 1 | // 2 | // MergeDetailView.h 3 | // UICollectionView拖动排序 4 | // 5 | // Created by Lym on 2017/4/11. 6 | // Copyright © 2017年 Lym. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface MergeDetailView : UIView 12 | 13 | @property (weak, nonatomic) IBOutlet UITextField *folderTitleTextField; 14 | 15 | @property (nonatomic, strong) NSMutableArray *dataArray; //数据源数组 16 | //修改标题 17 | @property (nonatomic, copy) void(^folderTitle)(NSString *title); 18 | //移除App 19 | @property (nonatomic, copy) void(^removeItem)(NSDictionary *item); 20 | @property (nonatomic, copy) void (^close)(void); 21 | 22 | - (void)openCell:(CGRect )cellFrame; 23 | 24 | - (void)dismissContactView; 25 | @end 26 | -------------------------------------------------------------------------------- /UICollectionView拖动排序/Controller/Support/View/MergeDetailView.m: -------------------------------------------------------------------------------- 1 | // 2 | // MergeDetailView.m 3 | // UICollectionView拖动排序 4 | // 5 | // Created by Lym on 2017/4/11. 6 | // Copyright © 2017年 Lym. All rights reserved. 7 | // 8 | 9 | #import "MergeDetailView.h" 10 | #import "MergeCollectionViewCell.h" 11 | #import "Config.h" 12 | 13 | static NSString * const kImage = @"image"; //logo图片 14 | static NSString * const kTitle = @"title"; //图片标题 15 | 16 | @interface MergeDetailView () 20 | 21 | @property (weak, nonatomic) IBOutlet UICollectionView *collectionView; 22 | @property (nonatomic, strong) UITapGestureRecognizer * tapGesture; 23 | @property (nonatomic, assign) CGRect transformRect; 24 | @end 25 | 26 | @implementation MergeDetailView 27 | 28 | - (void)awakeFromNib { 29 | [super awakeFromNib]; 30 | 31 | _folderTitleTextField.backgroundColor = TEXTFIELD_COLOR; 32 | _folderTitleTextField.delegate = self; 33 | 34 | [self createCollectionView]; 35 | } 36 | 37 | - (void)drawRect:(CGRect)rect { 38 | [super drawRect:rect]; 39 | CGFloat zoomValue = _transformRect.size.width/_collectionView.frame.size.width; 40 | _collectionView.transform = CGAffineTransformMakeScale(zoomValue, zoomValue); 41 | _collectionView.frame = _transformRect; 42 | [UIView animateWithDuration:0.25 animations:^{ 43 | _collectionView.center = CGPointMake(self.frame.size.width/2, self.frame.size.height/2+25); 44 | _collectionView.transform = CGAffineTransformMakeScale(1.0f, 1.0f); 45 | } completion:^(BOOL finished) { 46 | //移除截图视图、显示隐藏的cell并开启交互 47 | }]; 48 | 49 | _tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissContactView)]; 50 | _tapGesture.delegate = self; 51 | [[UIApplication sharedApplication].keyWindow addGestureRecognizer:_tapGesture]; 52 | } 53 | 54 | //防止无法点击didselect 55 | - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { 56 | if (touch.view.frame.size.width == SCREEN_WIDTH) { 57 | return YES; 58 | } else { 59 | return NO; 60 | } 61 | } 62 | 63 | - (void)dismissContactView { 64 | [UIView animateWithDuration:0.25 animations:^{ 65 | _collectionView.center = CGPointMake(_transformRect.origin.x+_transformRect.size.width/2, _transformRect.origin.y+_transformRect.size.height/2); 66 | _collectionView.transform = CGAffineTransformMakeScale(_transformRect.size.width/self.frame.size.width, _transformRect.size.width/self.frame.size.width); 67 | }completion:^(BOOL finished) { 68 | [[UIApplication sharedApplication].keyWindow removeGestureRecognizer:_tapGesture]; 69 | [self.superview removeFromSuperview]; 70 | self.close(); 71 | }]; 72 | 73 | } 74 | 75 | #pragma mark - ---------- 创建collectionView ---------- 76 | - (void)createCollectionView { 77 | 78 | UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; 79 | layout.itemSize = CGSizeMake(SCREEN_WIDTH / 4, SCREEN_WIDTH / 4); 80 | layout.sectionInset = UIEdgeInsetsMake(0, 0, 0, 0); 81 | layout.minimumLineSpacing = 0; 82 | layout.minimumInteritemSpacing = 0; 83 | layout.scrollDirection = UICollectionViewScrollDirectionVertical; 84 | 85 | _collectionView.collectionViewLayout = layout; 86 | _collectionView.delegate = self; 87 | _collectionView.dataSource = self; 88 | _collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 89 | [_collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"Cell"]; 90 | _collectionView.backgroundColor = [UIColor groupTableViewBackgroundColor]; 91 | [_collectionView registerNib:[UINib nibWithNibName:@"MergeCollectionViewCell" bundle:nil] forCellWithReuseIdentifier:@"MergeCollectionViewCell"]; 92 | //此处给其增加长按手势,用此手势触发cell移动效果 93 | UILongPressGestureRecognizer *longGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handlelongGesture:)]; 94 | longGesture.minimumPressDuration = 0.5f;//触发长按事件时间为:秒 95 | [_collectionView addGestureRecognizer:longGesture]; 96 | 97 | } 98 | 99 | #pragma mark - delegate 100 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section 101 | { 102 | return self.dataArray.count; 103 | } 104 | 105 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath 106 | { 107 | MergeCollectionViewCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"MergeCollectionViewCell" forIndexPath:indexPath]; 108 | cell.contentLabel.text = [NSString stringWithFormat:@"%@",self.dataArray[indexPath.item][kTitle]]; 109 | cell.imageView.image = self.dataArray[indexPath.item][kImage]; 110 | return cell; 111 | } 112 | 113 | #pragma mark - ---------- 监听手势 ---------- 114 | - (void)handlelongGesture:(UILongPressGestureRecognizer *)longGesture { 115 | [self action:longGesture]; 116 | } 117 | 118 | #pragma mark - ---------- 拖动手势 ---------- 119 | static UIView *snapedView; //截图快照 120 | static NSIndexPath *currentIndexPath; //当前路径 121 | static NSIndexPath *oldIndexPath; //旧路径 122 | static NSIndexPath *startIndexPath; //起始路径 123 | - (void)action:(UILongPressGestureRecognizer *)longGesture{ 124 | switch (longGesture.state) { 125 | case UIGestureRecognizerStateBegan:{//手势开始 126 | //判断手势落点位置是否在Item上 127 | oldIndexPath = [self.collectionView indexPathForItemAtPoint:[longGesture locationInView:self.collectionView]]; 128 | startIndexPath = oldIndexPath; 129 | if (oldIndexPath == nil) { 130 | break; 131 | } 132 | UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:oldIndexPath]; 133 | //使用系统截图功能,得到cell的截图视图 134 | 135 | snapedView = [cell snapshotViewAfterScreenUpdates:NO]; 136 | snapedView.frame = cell.frame; 137 | [self.collectionView addSubview:snapedView]; 138 | //截图后隐藏当前cell 139 | cell.hidden = YES; 140 | CGPoint currentPoint = [longGesture locationInView:self.collectionView]; 141 | [UIView animateWithDuration:0.25 animations:^{ 142 | snapedView.transform = CGAffineTransformMakeScale(1.2f, 1.2f); 143 | snapedView.center = CGPointMake(currentPoint.x, currentPoint.y); 144 | }]; 145 | } 146 | break; 147 | case UIGestureRecognizerStateChanged:{//手势改变 148 | //当前手指位置 - 截图视图位置移动 149 | CGPoint currentPoint = [longGesture locationInView:self.collectionView]; 150 | snapedView.center = CGPointMake(currentPoint.x, currentPoint.y); 151 | } 152 | break; 153 | default:{//手势结束和其他状态 154 | CGPoint currentPoint = [longGesture locationInView:self.collectionView]; 155 | snapedView.center = CGPointMake(currentPoint.x, currentPoint.y); 156 | 157 | 158 | /* 拖出界删除 */ 159 | CGPoint checkPoint = [longGesture locationInView:self]; 160 | if (checkPoint.x < self.collectionView.frame.origin.x || 161 | checkPoint.x > self.collectionView.frame.origin.x + self.collectionView.frame.size.width || 162 | checkPoint.y < self.collectionView.frame.origin.y || 163 | checkPoint.y > self.collectionView.frame.origin.y + self.collectionView.frame.size.height) { 164 | 165 | //在这里填写拖出去要执行的代码 166 | 167 | NSLog(@"拖出界"); 168 | _removeItem(_dataArray[startIndexPath.item]); 169 | [_dataArray removeObjectAtIndex:startIndexPath.item]; 170 | [snapedView removeFromSuperview]; 171 | [self dismissContactView]; 172 | [self.collectionView reloadData]; 173 | } else { 174 | //计算截图视图和哪个cell相交 175 | for (UICollectionViewCell *cell in [self.collectionView visibleCells]) { 176 | //当前隐藏的cell就不需要交换了,直接continue 177 | if ([self.collectionView indexPathForCell:cell] == oldIndexPath) { 178 | currentIndexPath = oldIndexPath; 179 | continue; 180 | }else{ 181 | //计算中心距 182 | CGFloat space = sqrtf(pow(snapedView.center.x - cell.center.x, 2) + powf(snapedView.center.y - cell.center.y, 2)); 183 | NSLog(@"%f",space); 184 | //如果相交一半就移动 185 | if(space <= snapedView.bounds.size.width*1 / 2){ 186 | currentIndexPath = [self.collectionView indexPathForCell:cell]; 187 | //更改移动后的起始indexPath,用于后面获取隐藏的cell,是移动后的位置 188 | [self.collectionView moveItemAtIndexPath:startIndexPath toIndexPath:currentIndexPath]; 189 | oldIndexPath = currentIndexPath; 190 | 191 | //移除数据插入到新的位置 192 | id obj = [_dataArray objectAtIndex:startIndexPath.item]; 193 | [_dataArray removeObject:[_dataArray objectAtIndex:startIndexPath.item]]; 194 | [_dataArray insertObject:obj 195 | atIndex:currentIndexPath.item]; 196 | } 197 | } 198 | } 199 | 200 | UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:oldIndexPath];//原来隐藏的cell 201 | UICollectionViewCell *targetCell = [self.collectionView cellForItemAtIndexPath:currentIndexPath];//移动目标cell 202 | //结束动画过程中停止交互,防止出问题 203 | self.collectionView.userInteractionEnabled = NO; 204 | //给截图视图一个动画移动到隐藏cell的新位置 205 | [UIView animateWithDuration:0.25 animations:^{ 206 | snapedView.center = targetCell.center; 207 | snapedView.transform = CGAffineTransformMakeScale(1.0f, 1.0f); 208 | } completion:^(BOOL finished) { 209 | //移除截图视图、显示隐藏的cell并开启交互 210 | [snapedView removeFromSuperview]; 211 | cell.hidden = NO; 212 | self.collectionView.userInteractionEnabled = YES; 213 | [self.collectionView reloadData]; 214 | }]; 215 | } 216 | } 217 | break; 218 | } 219 | } 220 | 221 | - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { 222 | NSLog(@"%ld", indexPath.row); 223 | } 224 | 225 | - (void)textFieldDidEndEditing:(UITextField *)textField { 226 | textField.text = [textField.text stringByReplacingOccurrencesOfString:@" " withString:@""]; 227 | self.folderTitle(textField.text); 228 | } 229 | 230 | - (void)openCell:(CGRect )cellFrame{ 231 | _transformRect = CGRectMake(cellFrame.origin.x, cellFrame.origin.y+84, cellFrame.size.width, cellFrame.size.height); 232 | [self setNeedsDisplay]; 233 | } 234 | 235 | @end 236 | -------------------------------------------------------------------------------- /UICollectionView拖动排序/Controller/Support/View/MergeDetailView.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /UICollectionView拖动排序/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /UICollectionView拖动排序/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // UICollectionView拖动排序 4 | // 5 | // Created by Lym on 2017/3/31. 6 | // Copyright © 2017年 Lym. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /UICollectionView拖动排序/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // UICollectionView拖动排序 4 | // 5 | // Created by Lym on 2017/3/31. 6 | // Copyright © 2017年 Lym. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "SortViewController.h" 11 | #import "MergeViewController.h" 12 | 13 | @interface ViewController () 14 | 15 | @end 16 | 17 | @implementation ViewController 18 | 19 | #pragma mark - ---------- 生命周期 ---------- 20 | - (void)viewDidLoad { 21 | [super viewDidLoad]; 22 | 23 | self.navigationItem.title = @"Merge Test"; 24 | self.view.backgroundColor = [UIColor whiteColor]; 25 | 26 | UIButton *btn1 = [[UIButton alloc] initWithFrame:CGRectMake(self.view.frame.size.width/2 - 50, 100, 100, 50)]; 27 | [btn1 setTitle:@"拖动排序" forState:UIControlStateNormal]; 28 | [btn1 setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; 29 | [btn1 addTarget:self action:@selector(sortVC) forControlEvents:UIControlEventTouchUpInside]; 30 | [self.view addSubview:btn1]; 31 | 32 | UIButton *btn2 = [[UIButton alloc] initWithFrame:CGRectMake(self.view.frame.size.width/2 - 75, 200, 150, 50)]; 33 | [btn2 setTitle:@"拖动排序+合并" forState:UIControlStateNormal]; 34 | [btn2 setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; 35 | [btn2 addTarget:self action:@selector(mergeVC) forControlEvents:UIControlEventTouchUpInside]; 36 | [self.view addSubview:btn2]; 37 | 38 | } 39 | 40 | - (void)didReceiveMemoryWarning { 41 | [super didReceiveMemoryWarning]; 42 | } 43 | 44 | //排序 45 | - (void)sortVC { 46 | SortViewController *vc = [[SortViewController alloc] init]; 47 | [self.navigationController pushViewController:vc animated:YES]; 48 | } 49 | 50 | //合并+排序 51 | - (void)mergeVC { 52 | MergeViewController *vc = [[MergeViewController alloc] init]; 53 | [self.navigationController pushViewController:vc animated:YES]; 54 | } 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /UICollectionView拖动排序/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // UICollectionView拖动排序 4 | // 5 | // Created by Lym on 2017/3/31. 6 | // Copyright © 2017年 Lym. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | --------------------------------------------------------------------------------