├── LICENSE
├── README.md
├── ReorderableGridView-Swift.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ ├── xcshareddata
│ │ ├── ReordableGridView-Swift.xccheckout
│ │ └── ReorderableGridView-Swift.xccheckout
│ └── xcuserdata
│ │ └── cem.xcuserdatad
│ │ └── UserInterfaceState.xcuserstate
└── xcuserdata
│ └── cem.xcuserdatad
│ ├── xcdebugger
│ └── Breakpoints_v2.xcbkptlist
│ └── xcschemes
│ ├── ReorderableGridView-Swift.xcscheme
│ └── xcschememanagement.plist
├── ReorderableGridView-Swift
├── AppDelegate.swift
├── Base.lproj
│ ├── LaunchScreen.xib
│ └── Main.storyboard
├── Images.xcassets
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── Info.plist
├── MultipleGridViewController.swift
├── ReorderableGridView.swift
└── ViewController.swift
├── ReorderableGridView-SwiftTests
├── Info.plist
└── ReorderableGridView_SwiftTests.swift
└── demo.gif
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (C) 2014, Cem Olcay
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a
4 | copy of this software and associated documentation files (the "Software"),
5 | to deal in the Software without restriction, including without limitation
6 | the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | and/or sell copies of the Software, and to permit persons to whom the
8 | Software is furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
16 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19 | DEALINGS IN THE SOFTWARE.
20 |
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ReorderableGridView-Swift
2 | =======================
3 |
4 | reorderable grid view solution implemented with swift.
5 | its UIScrollView subclass, its not a collection view layout.
6 | automatically sets horizontal item spacing by item widths. so items must be fixed-width.
7 | also sets automatically its content size.
8 | if you call `gridView?.invalidateLayout()` after orientation changed, it will lays out the grid by new orientation.
9 |
10 |
11 | Demo
12 | ----
13 |
14 | 
15 |
16 | Usage
17 | -----
18 |
19 | copy & paste the `ReorderableGridView.swift` into your project.
20 |
21 | gridView = ReorderableGridView(frame: self.view.frame, itemWidth: 180, verticalPadding: 20)
22 | self.view.addSubview(gridView!)
23 |
24 | Grid view ready !
25 |
26 | now you can add it `ReorderableView` instances
27 |
28 | let itemView = ReorderableView (x: 0, y: 0, w: 180, h: 250)
29 | ...
30 | gridView?.addReorderableView(itemView)
31 |
32 | // or
33 | let pos = GridPosition (x: 0, y: 1)
34 | gridView?addReorderableView (itemView, gridPosition: pos)
35 |
36 |
37 |
38 | or remove them
39 |
40 | gridView?.removeReorderableViewAtGridPosition(GridPosition (x: 0, y: 0))
41 |
42 | // or
43 | gridView?.removeReorderableView (itemView)
44 |
45 |
46 | > **Design Tip**
47 | > View itself don't have any margin padding.
48 | > It uses all frame width to calculate how many `ReorderableView`s can fit and
49 | > what should be their horizontal padding in a row.
50 | > Padding between columns (vertical padding) can be set in init method,
51 | > which is 10 by default.
52 | > You can have a container view and use something like
53 | > `CGRectInset (containerView.frame, marginX, marginY)`
54 | > when init grid with margin
55 |
56 |
57 |
58 | Optional Values
59 | ---------------
60 |
61 | var reorderable : Bool = true
62 | var draggable : Bool = true
63 | var draggableDelegate: Draggable?
64 |
65 | set them if you want your grid editable or not
66 |
67 | **Draggable Protocol**
68 |
69 | func didDragStartedForView (reorderableGridView: ReordableGridView, view: ReordableView)
70 | func didDraggedView (reorderableGridView: ReordableGridView, view: ReordableView)
71 | func didDragEndForView (reorderableGridView: ReordableGridView, view: ReordableView)
72 |
73 |
74 | set `gridView.draggableDelegate = self` and implement `Draggable` protocol functions if you want to access info about dragging actions in grid.
75 | This can be useful for multiple grid layouts.
76 | Example included in second tab of demo.
77 |
--------------------------------------------------------------------------------
/ReorderableGridView-Swift.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | B25078711A1F36E300651D6A /* MultipleGridViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B25078701A1F36E200651D6A /* MultipleGridViewController.swift */; };
11 | B2C47F671A1C9078002FDA24 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2C47F661A1C9078002FDA24 /* AppDelegate.swift */; };
12 | B2C47F691A1C9078002FDA24 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2C47F681A1C9078002FDA24 /* ViewController.swift */; };
13 | B2C47F6C1A1C9078002FDA24 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B2C47F6A1A1C9078002FDA24 /* Main.storyboard */; };
14 | B2C47F6E1A1C9078002FDA24 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B2C47F6D1A1C9078002FDA24 /* Images.xcassets */; };
15 | B2C47F711A1C9078002FDA24 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = B2C47F6F1A1C9078002FDA24 /* LaunchScreen.xib */; };
16 | B2C47F7D1A1C9078002FDA24 /* ReorderableGridView_SwiftTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2C47F7C1A1C9078002FDA24 /* ReorderableGridView_SwiftTests.swift */; };
17 | B2C47F871A1C909B002FDA24 /* ReorderableGridView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2C47F861A1C909B002FDA24 /* ReorderableGridView.swift */; };
18 | /* End PBXBuildFile section */
19 |
20 | /* Begin PBXContainerItemProxy section */
21 | B2C47F771A1C9078002FDA24 /* PBXContainerItemProxy */ = {
22 | isa = PBXContainerItemProxy;
23 | containerPortal = B2C47F591A1C9078002FDA24 /* Project object */;
24 | proxyType = 1;
25 | remoteGlobalIDString = B2C47F601A1C9078002FDA24;
26 | remoteInfo = "ReorderableGridView-Swift";
27 | };
28 | /* End PBXContainerItemProxy section */
29 |
30 | /* Begin PBXFileReference section */
31 | B25078701A1F36E200651D6A /* MultipleGridViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultipleGridViewController.swift; sourceTree = ""; };
32 | B2C47F611A1C9078002FDA24 /* ReorderableGridView-Swift.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "ReorderableGridView-Swift.app"; sourceTree = BUILT_PRODUCTS_DIR; };
33 | B2C47F651A1C9078002FDA24 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
34 | B2C47F661A1C9078002FDA24 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
35 | B2C47F681A1C9078002FDA24 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
36 | B2C47F6B1A1C9078002FDA24 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
37 | B2C47F6D1A1C9078002FDA24 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
38 | B2C47F701A1C9078002FDA24 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; };
39 | B2C47F761A1C9078002FDA24 /* ReorderableGridView-SwiftTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "ReorderableGridView-SwiftTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
40 | B2C47F7B1A1C9078002FDA24 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
41 | B2C47F7C1A1C9078002FDA24 /* ReorderableGridView_SwiftTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReorderableGridView_SwiftTests.swift; sourceTree = ""; };
42 | B2C47F861A1C909B002FDA24 /* ReorderableGridView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReorderableGridView.swift; sourceTree = ""; };
43 | /* End PBXFileReference section */
44 |
45 | /* Begin PBXFrameworksBuildPhase section */
46 | B2C47F5E1A1C9078002FDA24 /* Frameworks */ = {
47 | isa = PBXFrameworksBuildPhase;
48 | buildActionMask = 2147483647;
49 | files = (
50 | );
51 | runOnlyForDeploymentPostprocessing = 0;
52 | };
53 | B2C47F731A1C9078002FDA24 /* Frameworks */ = {
54 | isa = PBXFrameworksBuildPhase;
55 | buildActionMask = 2147483647;
56 | files = (
57 | );
58 | runOnlyForDeploymentPostprocessing = 0;
59 | };
60 | /* End PBXFrameworksBuildPhase section */
61 |
62 | /* Begin PBXGroup section */
63 | B2C47F581A1C9078002FDA24 = {
64 | isa = PBXGroup;
65 | children = (
66 | B2C47F631A1C9078002FDA24 /* ReorderableGridView-Swift */,
67 | B2C47F791A1C9078002FDA24 /* ReorderableGridView-SwiftTests */,
68 | B2C47F621A1C9078002FDA24 /* Products */,
69 | );
70 | sourceTree = "";
71 | };
72 | B2C47F621A1C9078002FDA24 /* Products */ = {
73 | isa = PBXGroup;
74 | children = (
75 | B2C47F611A1C9078002FDA24 /* ReorderableGridView-Swift.app */,
76 | B2C47F761A1C9078002FDA24 /* ReorderableGridView-SwiftTests.xctest */,
77 | );
78 | name = Products;
79 | sourceTree = "";
80 | };
81 | B2C47F631A1C9078002FDA24 /* ReorderableGridView-Swift */ = {
82 | isa = PBXGroup;
83 | children = (
84 | B2C47F661A1C9078002FDA24 /* AppDelegate.swift */,
85 | B2C47F681A1C9078002FDA24 /* ViewController.swift */,
86 | B25078701A1F36E200651D6A /* MultipleGridViewController.swift */,
87 | B2C47F861A1C909B002FDA24 /* ReorderableGridView.swift */,
88 | B2C47F641A1C9078002FDA24 /* Supporting Files */,
89 | );
90 | path = "ReorderableGridView-Swift";
91 | sourceTree = "";
92 | };
93 | B2C47F641A1C9078002FDA24 /* Supporting Files */ = {
94 | isa = PBXGroup;
95 | children = (
96 | B2C47F6A1A1C9078002FDA24 /* Main.storyboard */,
97 | B2C47F6D1A1C9078002FDA24 /* Images.xcassets */,
98 | B2C47F6F1A1C9078002FDA24 /* LaunchScreen.xib */,
99 | B2C47F651A1C9078002FDA24 /* Info.plist */,
100 | );
101 | name = "Supporting Files";
102 | sourceTree = "";
103 | };
104 | B2C47F791A1C9078002FDA24 /* ReorderableGridView-SwiftTests */ = {
105 | isa = PBXGroup;
106 | children = (
107 | B2C47F7C1A1C9078002FDA24 /* ReorderableGridView_SwiftTests.swift */,
108 | B2C47F7A1A1C9078002FDA24 /* Supporting Files */,
109 | );
110 | path = "ReorderableGridView-SwiftTests";
111 | sourceTree = "";
112 | };
113 | B2C47F7A1A1C9078002FDA24 /* Supporting Files */ = {
114 | isa = PBXGroup;
115 | children = (
116 | B2C47F7B1A1C9078002FDA24 /* Info.plist */,
117 | );
118 | name = "Supporting Files";
119 | sourceTree = "";
120 | };
121 | /* End PBXGroup section */
122 |
123 | /* Begin PBXNativeTarget section */
124 | B2C47F601A1C9078002FDA24 /* ReorderableGridView-Swift */ = {
125 | isa = PBXNativeTarget;
126 | buildConfigurationList = B2C47F801A1C9078002FDA24 /* Build configuration list for PBXNativeTarget "ReorderableGridView-Swift" */;
127 | buildPhases = (
128 | B2C47F5D1A1C9078002FDA24 /* Sources */,
129 | B2C47F5E1A1C9078002FDA24 /* Frameworks */,
130 | B2C47F5F1A1C9078002FDA24 /* Resources */,
131 | );
132 | buildRules = (
133 | );
134 | dependencies = (
135 | );
136 | name = "ReorderableGridView-Swift";
137 | productName = "ReorderableGridView-Swift";
138 | productReference = B2C47F611A1C9078002FDA24 /* ReorderableGridView-Swift.app */;
139 | productType = "com.apple.product-type.application";
140 | };
141 | B2C47F751A1C9078002FDA24 /* ReorderableGridView-SwiftTests */ = {
142 | isa = PBXNativeTarget;
143 | buildConfigurationList = B2C47F831A1C9078002FDA24 /* Build configuration list for PBXNativeTarget "ReorderableGridView-SwiftTests" */;
144 | buildPhases = (
145 | B2C47F721A1C9078002FDA24 /* Sources */,
146 | B2C47F731A1C9078002FDA24 /* Frameworks */,
147 | B2C47F741A1C9078002FDA24 /* Resources */,
148 | );
149 | buildRules = (
150 | );
151 | dependencies = (
152 | B2C47F781A1C9078002FDA24 /* PBXTargetDependency */,
153 | );
154 | name = "ReorderableGridView-SwiftTests";
155 | productName = "ReorderableGridView-SwiftTests";
156 | productReference = B2C47F761A1C9078002FDA24 /* ReorderableGridView-SwiftTests.xctest */;
157 | productType = "com.apple.product-type.bundle.unit-test";
158 | };
159 | /* End PBXNativeTarget section */
160 |
161 | /* Begin PBXProject section */
162 | B2C47F591A1C9078002FDA24 /* Project object */ = {
163 | isa = PBXProject;
164 | attributes = {
165 | LastUpgradeCheck = 0610;
166 | ORGANIZATIONNAME = "Cem Olcay";
167 | TargetAttributes = {
168 | B2C47F601A1C9078002FDA24 = {
169 | CreatedOnToolsVersion = 6.1;
170 | };
171 | B2C47F751A1C9078002FDA24 = {
172 | CreatedOnToolsVersion = 6.1;
173 | TestTargetID = B2C47F601A1C9078002FDA24;
174 | };
175 | };
176 | };
177 | buildConfigurationList = B2C47F5C1A1C9078002FDA24 /* Build configuration list for PBXProject "ReorderableGridView-Swift" */;
178 | compatibilityVersion = "Xcode 3.2";
179 | developmentRegion = English;
180 | hasScannedForEncodings = 0;
181 | knownRegions = (
182 | en,
183 | Base,
184 | );
185 | mainGroup = B2C47F581A1C9078002FDA24;
186 | productRefGroup = B2C47F621A1C9078002FDA24 /* Products */;
187 | projectDirPath = "";
188 | projectRoot = "";
189 | targets = (
190 | B2C47F601A1C9078002FDA24 /* ReorderableGridView-Swift */,
191 | B2C47F751A1C9078002FDA24 /* ReorderableGridView-SwiftTests */,
192 | );
193 | };
194 | /* End PBXProject section */
195 |
196 | /* Begin PBXResourcesBuildPhase section */
197 | B2C47F5F1A1C9078002FDA24 /* Resources */ = {
198 | isa = PBXResourcesBuildPhase;
199 | buildActionMask = 2147483647;
200 | files = (
201 | B2C47F6C1A1C9078002FDA24 /* Main.storyboard in Resources */,
202 | B2C47F711A1C9078002FDA24 /* LaunchScreen.xib in Resources */,
203 | B2C47F6E1A1C9078002FDA24 /* Images.xcassets in Resources */,
204 | );
205 | runOnlyForDeploymentPostprocessing = 0;
206 | };
207 | B2C47F741A1C9078002FDA24 /* Resources */ = {
208 | isa = PBXResourcesBuildPhase;
209 | buildActionMask = 2147483647;
210 | files = (
211 | );
212 | runOnlyForDeploymentPostprocessing = 0;
213 | };
214 | /* End PBXResourcesBuildPhase section */
215 |
216 | /* Begin PBXSourcesBuildPhase section */
217 | B2C47F5D1A1C9078002FDA24 /* Sources */ = {
218 | isa = PBXSourcesBuildPhase;
219 | buildActionMask = 2147483647;
220 | files = (
221 | B25078711A1F36E300651D6A /* MultipleGridViewController.swift in Sources */,
222 | B2C47F691A1C9078002FDA24 /* ViewController.swift in Sources */,
223 | B2C47F871A1C909B002FDA24 /* ReorderableGridView.swift in Sources */,
224 | B2C47F671A1C9078002FDA24 /* AppDelegate.swift in Sources */,
225 | );
226 | runOnlyForDeploymentPostprocessing = 0;
227 | };
228 | B2C47F721A1C9078002FDA24 /* Sources */ = {
229 | isa = PBXSourcesBuildPhase;
230 | buildActionMask = 2147483647;
231 | files = (
232 | B2C47F7D1A1C9078002FDA24 /* ReorderableGridView_SwiftTests.swift in Sources */,
233 | );
234 | runOnlyForDeploymentPostprocessing = 0;
235 | };
236 | /* End PBXSourcesBuildPhase section */
237 |
238 | /* Begin PBXTargetDependency section */
239 | B2C47F781A1C9078002FDA24 /* PBXTargetDependency */ = {
240 | isa = PBXTargetDependency;
241 | target = B2C47F601A1C9078002FDA24 /* ReorderableGridView-Swift */;
242 | targetProxy = B2C47F771A1C9078002FDA24 /* PBXContainerItemProxy */;
243 | };
244 | /* End PBXTargetDependency section */
245 |
246 | /* Begin PBXVariantGroup section */
247 | B2C47F6A1A1C9078002FDA24 /* Main.storyboard */ = {
248 | isa = PBXVariantGroup;
249 | children = (
250 | B2C47F6B1A1C9078002FDA24 /* Base */,
251 | );
252 | name = Main.storyboard;
253 | sourceTree = "";
254 | };
255 | B2C47F6F1A1C9078002FDA24 /* LaunchScreen.xib */ = {
256 | isa = PBXVariantGroup;
257 | children = (
258 | B2C47F701A1C9078002FDA24 /* Base */,
259 | );
260 | name = LaunchScreen.xib;
261 | sourceTree = "";
262 | };
263 | /* End PBXVariantGroup section */
264 |
265 | /* Begin XCBuildConfiguration section */
266 | B2C47F7E1A1C9078002FDA24 /* Debug */ = {
267 | isa = XCBuildConfiguration;
268 | buildSettings = {
269 | ALWAYS_SEARCH_USER_PATHS = NO;
270 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
271 | CLANG_CXX_LIBRARY = "libc++";
272 | CLANG_ENABLE_MODULES = YES;
273 | CLANG_ENABLE_OBJC_ARC = YES;
274 | CLANG_WARN_BOOL_CONVERSION = YES;
275 | CLANG_WARN_CONSTANT_CONVERSION = YES;
276 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
277 | CLANG_WARN_EMPTY_BODY = YES;
278 | CLANG_WARN_ENUM_CONVERSION = YES;
279 | CLANG_WARN_INT_CONVERSION = YES;
280 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
281 | CLANG_WARN_UNREACHABLE_CODE = YES;
282 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
283 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
284 | COPY_PHASE_STRIP = NO;
285 | ENABLE_STRICT_OBJC_MSGSEND = YES;
286 | GCC_C_LANGUAGE_STANDARD = gnu99;
287 | GCC_DYNAMIC_NO_PIC = NO;
288 | GCC_OPTIMIZATION_LEVEL = 0;
289 | GCC_PREPROCESSOR_DEFINITIONS = (
290 | "DEBUG=1",
291 | "$(inherited)",
292 | );
293 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
294 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
295 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
296 | GCC_WARN_UNDECLARED_SELECTOR = YES;
297 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
298 | GCC_WARN_UNUSED_FUNCTION = YES;
299 | GCC_WARN_UNUSED_VARIABLE = YES;
300 | IPHONEOS_DEPLOYMENT_TARGET = 8.1;
301 | MTL_ENABLE_DEBUG_INFO = YES;
302 | ONLY_ACTIVE_ARCH = YES;
303 | SDKROOT = iphoneos;
304 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
305 | };
306 | name = Debug;
307 | };
308 | B2C47F7F1A1C9078002FDA24 /* Release */ = {
309 | isa = XCBuildConfiguration;
310 | buildSettings = {
311 | ALWAYS_SEARCH_USER_PATHS = NO;
312 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
313 | CLANG_CXX_LIBRARY = "libc++";
314 | CLANG_ENABLE_MODULES = YES;
315 | CLANG_ENABLE_OBJC_ARC = YES;
316 | CLANG_WARN_BOOL_CONVERSION = YES;
317 | CLANG_WARN_CONSTANT_CONVERSION = YES;
318 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
319 | CLANG_WARN_EMPTY_BODY = YES;
320 | CLANG_WARN_ENUM_CONVERSION = YES;
321 | CLANG_WARN_INT_CONVERSION = YES;
322 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
323 | CLANG_WARN_UNREACHABLE_CODE = YES;
324 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
325 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
326 | COPY_PHASE_STRIP = YES;
327 | ENABLE_NS_ASSERTIONS = NO;
328 | ENABLE_STRICT_OBJC_MSGSEND = YES;
329 | GCC_C_LANGUAGE_STANDARD = gnu99;
330 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
331 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
332 | GCC_WARN_UNDECLARED_SELECTOR = YES;
333 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
334 | GCC_WARN_UNUSED_FUNCTION = YES;
335 | GCC_WARN_UNUSED_VARIABLE = YES;
336 | IPHONEOS_DEPLOYMENT_TARGET = 8.1;
337 | MTL_ENABLE_DEBUG_INFO = NO;
338 | SDKROOT = iphoneos;
339 | VALIDATE_PRODUCT = YES;
340 | };
341 | name = Release;
342 | };
343 | B2C47F811A1C9078002FDA24 /* Debug */ = {
344 | isa = XCBuildConfiguration;
345 | buildSettings = {
346 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
347 | INFOPLIST_FILE = "ReorderableGridView-Swift/Info.plist";
348 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
349 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
350 | PRODUCT_NAME = "ReorderableGridView-Swift";
351 | TARGETED_DEVICE_FAMILY = "1,2";
352 | };
353 | name = Debug;
354 | };
355 | B2C47F821A1C9078002FDA24 /* Release */ = {
356 | isa = XCBuildConfiguration;
357 | buildSettings = {
358 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
359 | INFOPLIST_FILE = "ReorderableGridView-Swift/Info.plist";
360 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
361 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
362 | PRODUCT_NAME = "ReorderableGridView-Swift";
363 | TARGETED_DEVICE_FAMILY = "1,2";
364 | };
365 | name = Release;
366 | };
367 | B2C47F841A1C9078002FDA24 /* Debug */ = {
368 | isa = XCBuildConfiguration;
369 | buildSettings = {
370 | BUNDLE_LOADER = "$(TEST_HOST)";
371 | FRAMEWORK_SEARCH_PATHS = (
372 | "$(SDKROOT)/Developer/Library/Frameworks",
373 | "$(inherited)",
374 | );
375 | GCC_PREPROCESSOR_DEFINITIONS = (
376 | "DEBUG=1",
377 | "$(inherited)",
378 | );
379 | INFOPLIST_FILE = "ReorderableGridView-SwiftTests/Info.plist";
380 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
381 | PRODUCT_NAME = "ReorderableGridView-SwiftTests";
382 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ReorderableGridView-Swift.app/ReorderableGridView-Swift";
383 | };
384 | name = Debug;
385 | };
386 | B2C47F851A1C9078002FDA24 /* Release */ = {
387 | isa = XCBuildConfiguration;
388 | buildSettings = {
389 | BUNDLE_LOADER = "$(TEST_HOST)";
390 | FRAMEWORK_SEARCH_PATHS = (
391 | "$(SDKROOT)/Developer/Library/Frameworks",
392 | "$(inherited)",
393 | );
394 | INFOPLIST_FILE = "ReorderableGridView-SwiftTests/Info.plist";
395 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
396 | PRODUCT_NAME = "ReorderableGridView-SwiftTests";
397 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ReorderableGridView-Swift.app/ReorderableGridView-Swift";
398 | };
399 | name = Release;
400 | };
401 | /* End XCBuildConfiguration section */
402 |
403 | /* Begin XCConfigurationList section */
404 | B2C47F5C1A1C9078002FDA24 /* Build configuration list for PBXProject "ReorderableGridView-Swift" */ = {
405 | isa = XCConfigurationList;
406 | buildConfigurations = (
407 | B2C47F7E1A1C9078002FDA24 /* Debug */,
408 | B2C47F7F1A1C9078002FDA24 /* Release */,
409 | );
410 | defaultConfigurationIsVisible = 0;
411 | defaultConfigurationName = Release;
412 | };
413 | B2C47F801A1C9078002FDA24 /* Build configuration list for PBXNativeTarget "ReorderableGridView-Swift" */ = {
414 | isa = XCConfigurationList;
415 | buildConfigurations = (
416 | B2C47F811A1C9078002FDA24 /* Debug */,
417 | B2C47F821A1C9078002FDA24 /* Release */,
418 | );
419 | defaultConfigurationIsVisible = 0;
420 | defaultConfigurationName = Release;
421 | };
422 | B2C47F831A1C9078002FDA24 /* Build configuration list for PBXNativeTarget "ReorderableGridView-SwiftTests" */ = {
423 | isa = XCConfigurationList;
424 | buildConfigurations = (
425 | B2C47F841A1C9078002FDA24 /* Debug */,
426 | B2C47F851A1C9078002FDA24 /* Release */,
427 | );
428 | defaultConfigurationIsVisible = 0;
429 | defaultConfigurationName = Release;
430 | };
431 | /* End XCConfigurationList section */
432 | };
433 | rootObject = B2C47F591A1C9078002FDA24 /* Project object */;
434 | }
435 |
--------------------------------------------------------------------------------
/ReorderableGridView-Swift.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ReorderableGridView-Swift.xcodeproj/project.xcworkspace/xcshareddata/ReordableGridView-Swift.xccheckout:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDESourceControlProjectFavoriteDictionaryKey
6 |
7 | IDESourceControlProjectIdentifier
8 | 0FC2F698-B9C1-4634-BAFC-F2FA48F24EDE
9 | IDESourceControlProjectName
10 | ReordableGridView-Swift
11 | IDESourceControlProjectOriginsDictionary
12 |
13 | 2A6249D544D1E1349BAC88A3DF3143C5072ED4CE
14 | https://github.com/cemolcay/ReordableGridView-Swift.git
15 |
16 | IDESourceControlProjectPath
17 | ReordableGridView-Swift.xcodeproj
18 | IDESourceControlProjectRelativeInstallPathDictionary
19 |
20 | 2A6249D544D1E1349BAC88A3DF3143C5072ED4CE
21 | ../..
22 |
23 | IDESourceControlProjectURL
24 | https://github.com/cemolcay/ReordableGridView-Swift.git
25 | IDESourceControlProjectVersion
26 | 111
27 | IDESourceControlProjectWCCIdentifier
28 | 2A6249D544D1E1349BAC88A3DF3143C5072ED4CE
29 | IDESourceControlProjectWCConfigurations
30 |
31 |
32 | IDESourceControlRepositoryExtensionIdentifierKey
33 | public.vcs.git
34 | IDESourceControlWCCIdentifierKey
35 | 2A6249D544D1E1349BAC88A3DF3143C5072ED4CE
36 | IDESourceControlWCCName
37 | ReordableGridView-Swift
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/ReorderableGridView-Swift.xcodeproj/project.xcworkspace/xcshareddata/ReorderableGridView-Swift.xccheckout:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDESourceControlProjectFavoriteDictionaryKey
6 |
7 | IDESourceControlProjectIdentifier
8 | 3E32D046-C0A8-4159-983D-E3D279557D00
9 | IDESourceControlProjectName
10 | ReorderableGridView-Swift
11 | IDESourceControlProjectOriginsDictionary
12 |
13 | 2A6249D544D1E1349BAC88A3DF3143C5072ED4CE
14 | https://github.com/cemolcay/ReorderableGridView-Swift.git
15 |
16 | IDESourceControlProjectPath
17 | ReorderableGridView-Swift.xcodeproj
18 | IDESourceControlProjectRelativeInstallPathDictionary
19 |
20 | 2A6249D544D1E1349BAC88A3DF3143C5072ED4CE
21 | ../..
22 |
23 | IDESourceControlProjectURL
24 | https://github.com/cemolcay/ReorderableGridView-Swift.git
25 | IDESourceControlProjectVersion
26 | 111
27 | IDESourceControlProjectWCCIdentifier
28 | 2A6249D544D1E1349BAC88A3DF3143C5072ED4CE
29 | IDESourceControlProjectWCConfigurations
30 |
31 |
32 | IDESourceControlRepositoryExtensionIdentifierKey
33 | public.vcs.git
34 | IDESourceControlWCCIdentifierKey
35 | 2A6249D544D1E1349BAC88A3DF3143C5072ED4CE
36 | IDESourceControlWCCName
37 | ReorderableGridView-Swift
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/ReorderableGridView-Swift.xcodeproj/project.xcworkspace/xcuserdata/cem.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cemolcay/ReorderableGridView-Swift/176ab79d6a4513444758b2591d27c670ca31101b/ReorderableGridView-Swift.xcodeproj/project.xcworkspace/xcuserdata/cem.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/ReorderableGridView-Swift.xcodeproj/xcuserdata/cem.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/ReorderableGridView-Swift.xcodeproj/xcuserdata/cem.xcuserdatad/xcschemes/ReorderableGridView-Swift.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
44 |
45 |
47 |
53 |
54 |
55 |
56 |
57 |
63 |
64 |
65 |
66 |
75 |
76 |
82 |
83 |
84 |
85 |
86 |
87 |
93 |
94 |
100 |
101 |
102 |
103 |
105 |
106 |
109 |
110 |
111 |
--------------------------------------------------------------------------------
/ReorderableGridView-Swift.xcodeproj/xcuserdata/cem.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | ReordableGridView-Swift.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 | ReorderableGridView-Swift.xcscheme
13 |
14 | orderHint
15 | 0
16 |
17 |
18 | SuppressBuildableAutocreation
19 |
20 | B2C47F601A1C9078002FDA24
21 |
22 | primary
23 |
24 |
25 | B2C47F751A1C9078002FDA24
26 |
27 | primary
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/ReorderableGridView-Swift/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // ReorderableGridView-Swift
4 | //
5 | // Created by Cem Olcay on 19/11/14.
6 | // Copyright (c) 2014 Cem Olcay. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
18 | // Override point for customization after application launch.
19 |
20 | UINavigationBar.appearance().titleTextAttributes = [NSFontAttributeName: UIFont.HelveticaNeue(.Thin, size: 20)]
21 |
22 | return true
23 | }
24 |
25 | func applicationWillResignActive(application: UIApplication) {
26 | // 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.
27 | // 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.
28 | }
29 |
30 | func applicationDidEnterBackground(application: UIApplication) {
31 | // 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.
32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
33 | }
34 |
35 | func applicationWillEnterForeground(application: UIApplication) {
36 | // 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.
37 | }
38 |
39 | func applicationDidBecomeActive(application: UIApplication) {
40 | // 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.
41 | }
42 |
43 | func applicationWillTerminate(application: UIApplication) {
44 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
45 | }
46 |
47 |
48 | }
49 |
50 |
--------------------------------------------------------------------------------
/ReorderableGridView-Swift/Base.lproj/LaunchScreen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
20 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/ReorderableGridView-Swift/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 |
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 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
--------------------------------------------------------------------------------
/ReorderableGridView-Swift/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" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | }
33 | ],
34 | "info" : {
35 | "version" : 1,
36 | "author" : "xcode"
37 | }
38 | }
--------------------------------------------------------------------------------
/ReorderableGridView-Swift/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | com.questa.$(PRODUCT_NAME:rfc1034identifier)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 | UIInterfaceOrientationLandscapeLeft
37 | UIInterfaceOrientationLandscapeRight
38 | UIInterfaceOrientationPortraitUpsideDown
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/ReorderableGridView-Swift/MultipleGridViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MultipleGridViewController.swift
3 | // ReorderableGridView-Swift
4 | //
5 | // Created by Cem Olcay on 21/11/14.
6 | // Copyright (c) 2014 Cem Olcay. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class MultipleGridViewController: UIViewController, Draggable {
12 |
13 | // MARK: Properties
14 | @IBOutlet var selectedItemsGridContainerView: UIView!
15 | @IBOutlet var itemsGridContainerView: UIView!
16 |
17 | var selectedItemsGrid: ReorderableGridView?
18 | var itemsGrid: ReorderableGridView?
19 | var itemCount: Int = 0
20 |
21 | var borderColor: UIColor?
22 | var bgColor: UIColor?
23 | var bottomColor: UIColor?
24 |
25 |
26 |
27 | // MARK: Lifecycle
28 |
29 | override func viewDidLoad() {
30 | super.viewDidLoad()
31 |
32 | borderColor = RGBColor(233, g: 233, b: 233)
33 | bgColor = RGBColor(242, g: 242, b: 242)
34 | bottomColor = RGBColor(65, g: 65, b: 65)
35 |
36 | self.title = "Multiple Grid"
37 | self.navigationItem.title = "Multiple Grid View Demo"
38 | self.view.backgroundColor = bgColor
39 |
40 | selectedItemsGrid = ReorderableGridView (frame: selectedItemsGridContainerView.bounds, itemWidth: 180)
41 | selectedItemsGrid?.draggableDelegate = self
42 | selectedItemsGrid?.reorderable = false
43 | selectedItemsGrid?.clipsToBounds = false
44 | selectedItemsGridContainerView.addSubview(selectedItemsGrid!)
45 |
46 | itemsGrid = ReorderableGridView (frame: itemsGridContainerView.bounds, itemWidth: 180)
47 | itemsGrid?.draggableDelegate = self
48 | itemsGrid?.clipsToBounds = false
49 | itemsGrid?.reorderable = false
50 | itemsGridContainerView.addSubview(itemsGrid!)
51 |
52 | for _ in 0..<20 {
53 | itemsGrid?.addReorderableView(itemView())
54 | }
55 | }
56 |
57 | override func viewDidAppear(animated: Bool) {
58 | super.viewDidAppear(animated)
59 |
60 | if let grid = itemsGrid {
61 | grid.frame = itemsGridContainerView.bounds
62 | grid.invalidateLayout()
63 | }
64 |
65 | if let grid = selectedItemsGrid {
66 | grid.frame = selectedItemsGridContainerView.bounds
67 | grid.invalidateLayout()
68 | }
69 | }
70 |
71 | func itemView () -> ReorderableView {
72 | let w : CGFloat = 180
73 | let h : CGFloat = 100 + CGFloat(arc4random()%100)
74 |
75 | let view = ReorderableView (x: 0, y: 0, w: w, h: h)
76 | view.tag = itemCount++
77 | view.layer.borderColor = borderColor?.CGColor
78 | view.layer.backgroundColor = UIColor.whiteColor().CGColor
79 | view.layer.borderWidth = 1
80 | view.layer.cornerRadius = 5
81 | view.layer.masksToBounds = true
82 |
83 | let topView = UIView(x: 0, y: 0, w: view.w, h: 50)
84 | view.addSubview(topView)
85 |
86 | let itemLabel = UILabel (frame: topView.frame)
87 | itemLabel.center = topView.center
88 | itemLabel.font = UIFont.HelveticaNeue(.Thin, size: 20)
89 | itemLabel.textAlignment = NSTextAlignment.Center
90 | itemLabel.textColor = bottomColor?
91 | itemLabel.text = "\(view.tag)"
92 | itemLabel.layer.masksToBounds = true
93 | topView.addSubview(itemLabel)
94 |
95 | let sepLayer = CALayer ()
96 | sepLayer.frame = CGRect (x: 0, y: topView.bottom, width: topView.w, height: 1)
97 | sepLayer.backgroundColor = borderColor?.CGColor
98 | topView.layer.addSublayer(sepLayer)
99 |
100 | let bottomView = UIView(frame: CGRect(x: 0, y: topView.bottom, width: view.w, height: view.h-topView.h))
101 | let bottomLayer = CALayer ()
102 | bottomLayer.frame = CGRect (x: 0, y: bottomView.h-5, width: bottomView.w, height: 5)
103 | bottomLayer.backgroundColor = bottomColor?.CGColor
104 | bottomView.layer.addSublayer(bottomLayer)
105 | bottomView.layer.masksToBounds = true
106 | view.addSubview(bottomView)
107 |
108 | return view
109 | }
110 |
111 |
112 |
113 | // MARK: Draggable
114 |
115 | func didDragStartedForView(reorderableGridView: ReorderableGridView, view: ReorderableView) {
116 |
117 | }
118 |
119 | func didDraggedView(reorderableGridView: ReorderableGridView, view: ReorderableView) {
120 |
121 | }
122 |
123 | func didDragEndForView(reorderableGridView: ReorderableGridView, view: ReorderableView) {
124 |
125 | // items grid to selected items grid
126 |
127 | if (reorderableGridView == itemsGrid!) {
128 | let convertedPos : CGPoint = self.view.convertPoint(view.center, fromView: itemsGridContainerView)
129 | if (CGRectContainsPoint(selectedItemsGridContainerView.frame, convertedPos)) {
130 | itemsGrid?.removeReorderableView(view)
131 | selectedItemsGrid?.addReorderableView(view)
132 | } else {
133 | reorderableGridView.invalidateLayout()
134 | }
135 | }
136 |
137 |
138 | // selected items grid to items grid
139 |
140 | else if (reorderableGridView == selectedItemsGrid!) {
141 | let convertedPos : CGPoint = self.view.convertPoint(view.center, fromView: selectedItemsGridContainerView)
142 | if (CGRectContainsPoint(itemsGridContainerView.frame, convertedPos)) {
143 | selectedItemsGrid?.removeReorderableView(view)
144 | itemsGrid?.addReorderableView(view)
145 | } else {
146 | reorderableGridView.invalidateLayout()
147 | }
148 | }
149 | }
150 |
151 |
152 |
153 | // MARK: Interface Rotation
154 |
155 | override func didRotateFromInterfaceOrientation(fromInterfaceOrientation: UIInterfaceOrientation) {
156 | selectedItemsGrid?.frame = selectedItemsGridContainerView.bounds
157 | itemsGrid?.frame = itemsGridContainerView.bounds
158 |
159 | selectedItemsGrid?.invalidateLayout()
160 | itemsGrid?.invalidateLayout()
161 | }
162 |
163 |
164 |
165 | // MARK: Utils
166 |
167 | func randomColor () -> UIColor {
168 | var randomRed:CGFloat = CGFloat(drand48())
169 | var randomGreen:CGFloat = CGFloat(drand48())
170 | var randomBlue:CGFloat = CGFloat(drand48())
171 |
172 | return UIColor(red: randomRed, green: randomGreen, blue: randomBlue, alpha: 1.0)
173 | }
174 |
175 | func RGBColor(r: CGFloat, g: CGFloat, b: CGFloat) -> UIColor {
176 | return UIColor (red: r / 255.0, green: g / 255.0, blue: b / 255.0, alpha: 1)
177 | }
178 |
179 | func RGBAColor (r: CGFloat, g: CGFloat, b: CGFloat, a: CGFloat) -> UIColor {
180 | return UIColor (red: r / 255.0, green: g / 255.0, blue: b / 255.0, alpha: a)
181 | }
182 | }
183 |
--------------------------------------------------------------------------------
/ReorderableGridView-Swift/ReorderableGridView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ReorderableGridView.swift
3 | // ReorderableGridView-Swift
4 | //
5 | // Created by Cem Olcay on 19/11/14.
6 | // Copyright (c) 2014 Cem Olcay. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 |
12 | extension UIView {
13 |
14 | // MARK: Frame Extensions
15 |
16 | var x: CGFloat {
17 | return self.frame.origin.x
18 | }
19 |
20 | var y: CGFloat {
21 | return self.frame.origin.y
22 | }
23 |
24 | var w: CGFloat {
25 | return self.frame.size.width
26 | }
27 |
28 | var h: CGFloat {
29 | return self.frame.size.height
30 | }
31 |
32 |
33 | var left: CGFloat {
34 | return self.x
35 | }
36 |
37 | var right: CGFloat {
38 | return self.x + self.w
39 | }
40 |
41 | var top: CGFloat {
42 | return self.y
43 | }
44 |
45 | var bottom: CGFloat {
46 | return self.y + self.h
47 | }
48 |
49 |
50 | func setX (x: CGFloat) {
51 | self.frame = CGRect (x: x, y: self.y, width: self.w, height: self.h)
52 | }
53 |
54 | func setY (y: CGFloat) {
55 | UIView.animateWithDuration(0.2, animations: { () -> Void in
56 | self.frame = CGRect (x: self.x, y: y, width: self.w, height: self.h)
57 | })
58 | }
59 |
60 | func setX (x: CGFloat, y: CGFloat) {
61 | self.frame = CGRect (x: x, y: y, width: self.w, height: self.h)
62 | }
63 |
64 |
65 | func setW (w: CGFloat) {
66 | self.frame = CGRect (x: self.x, y: self.y, width: w, height: self.h)
67 | }
68 |
69 | func setH (h: CGFloat) {
70 | self.frame = CGRect (x: self.x, y: self.y, width: self.w, height: h)
71 | }
72 |
73 | func setW (w: CGFloat, h: CGFloat) {
74 | self.frame = CGRect (x: self.x, y: self.y, width: w, height: h)
75 | }
76 |
77 | func setSize (size: CGSize) {
78 | self.frame = CGRect (x: self.x, y: self.y, width: size.width, height: size.height)
79 | }
80 |
81 | func setPosition (position: CGPoint) {
82 | if (frame.origin == position) {
83 | return
84 | }
85 |
86 | UIView.animateWithDuration(0.2, animations: { () -> Void in
87 | self.frame = CGRect (x: position.x, y: position.y, width: self.w, height: self.h)
88 | })
89 | }
90 |
91 |
92 | func leftWithOffset (offset: CGFloat) -> CGFloat {
93 | return self.left - offset
94 | }
95 |
96 | func rightWithOffset (offset: CGFloat) -> CGFloat {
97 | return self.right + offset
98 | }
99 |
100 | func topWithOffset (offset: CGFloat) -> CGFloat {
101 | return self.top - offset
102 | }
103 |
104 | func botttomWithOffset (offset: CGFloat) -> CGFloat {
105 | return self.bottom + offset
106 | }
107 |
108 |
109 | func setScale (x: CGFloat, y: CGFloat, z: CGFloat) {
110 | self.transform = CGAffineTransformMakeScale(x, y)
111 | }
112 |
113 | convenience init (x: CGFloat, y: CGFloat, w: CGFloat, h: CGFloat) {
114 | self.init (frame: CGRect (x: x, y: y, width: w, height: h))
115 | }
116 | }
117 |
118 |
119 | protocol Reorderable {
120 | func didReorderStartedForView (view: ReorderableView)
121 | func didReorderedView (view: ReorderableView, pan: UIPanGestureRecognizer)
122 | func didReorderEndForView (view: ReorderableView, pan: UIPanGestureRecognizer)
123 | }
124 |
125 |
126 | protocol Draggable {
127 | func didDragStartedForView (ReorderableGridView: ReorderableGridView, view: ReorderableView)
128 | func didDraggedView (ReorderableGridView: ReorderableGridView, view: ReorderableView)
129 | func didDragEndForView (ReorderableGridView: ReorderableGridView, view: ReorderableView)
130 | }
131 |
132 |
133 | func == (lhs: GridPosition, rhs: GridPosition) -> Bool {
134 | return (lhs.x == rhs.x && lhs.y == rhs.y)
135 | }
136 |
137 | struct GridPosition: Equatable {
138 | var x: Int?
139 | var y: Int?
140 |
141 |
142 | func col () -> Int {
143 | return x!
144 | }
145 |
146 | func row () -> Int {
147 | return y!
148 | }
149 |
150 |
151 | func arrayIndex (colsInRow: Int) -> Int {
152 | let index = row()*colsInRow + col()
153 | return index
154 | }
155 |
156 |
157 | func up () -> GridPosition? {
158 | if y <= 0 {
159 | return nil
160 | } else {
161 | return GridPosition(x: x!, y: y!-1)
162 | }
163 | }
164 |
165 | func down () -> GridPosition {
166 | return GridPosition(x: x!, y: y!+1)
167 | }
168 |
169 | func left () -> GridPosition? {
170 | if x <= 0 {
171 | return nil
172 | } else {
173 | return GridPosition (x: x!-1, y: y!)
174 | }
175 | }
176 |
177 | func right () -> GridPosition {
178 | return GridPosition (x: x!+1, y: y!)
179 | }
180 |
181 |
182 | func string () -> String {
183 | return "\(x!), \(y!)"
184 | }
185 |
186 | func detailedString () -> String {
187 | return "x: \(x!), y: \(y!)"
188 | }
189 | }
190 |
191 |
192 | class ReorderableView: UIView, UIGestureRecognizerDelegate {
193 |
194 | // MARK: Properties
195 |
196 | var delegate: Reorderable! = nil
197 | var pan: UIPanGestureRecognizer?
198 | var gridPosition: GridPosition?
199 |
200 | let animationDuration: NSTimeInterval = 0.2
201 | let reorderModeScale: CGFloat = 1.1
202 | let reorderModeAlpha: CGFloat = 0.6
203 |
204 | var isReordering : Bool = false {
205 | didSet {
206 | if isReordering {
207 | startReorderMode()
208 | } else {
209 | endReorderMode()
210 | }
211 | }
212 | }
213 |
214 |
215 |
216 | // MARK: Lifecycle
217 |
218 | convenience init (x: CGFloat, y: CGFloat, w: CGFloat, h: CGFloat) {
219 | self.init (frame: CGRect (x: x, y: y, width: w, height: h))
220 | }
221 |
222 | override init(frame: CGRect) {
223 | super.init(frame: frame)
224 |
225 | var doubleTap = UITapGestureRecognizer (target: self, action: "doubleTapped:")
226 | doubleTap.numberOfTapsRequired = 1
227 | doubleTap.numberOfTouchesRequired = 1
228 | doubleTap.delegate = self
229 |
230 | self.addGestureRecognizer(doubleTap)
231 |
232 |
233 | var longPress = UILongPressGestureRecognizer (target: self, action: "longPressed:")
234 | longPress.numberOfTouchesRequired = 1
235 | longPress.delegate = self
236 |
237 | self.addGestureRecognizer(longPress)
238 | }
239 |
240 | required init(coder aDecoder: NSCoder) {
241 | fatalError("init(coder:) has not been implemented")
242 | }
243 |
244 |
245 |
246 | // MARK: Animations
247 |
248 | func startReorderMode () {
249 | addPan()
250 |
251 | superview?.bringSubviewToFront(self)
252 |
253 | UIView.animateWithDuration(animationDuration, animations: { () -> Void in
254 | self.alpha = self.reorderModeAlpha
255 | self.setScale(self.reorderModeScale, y: self.reorderModeScale, z: self.reorderModeScale)
256 | })
257 | }
258 |
259 | func endReorderMode () {
260 | UIView.animateWithDuration(animationDuration, animations: { () -> Void in
261 | self.alpha = 1
262 | self.setScale(1, y: 1, z: 1)
263 | }) { finished -> Void in
264 | self.removePan()
265 | }
266 | }
267 |
268 |
269 |
270 | // MARK: Gestures
271 |
272 | func addPan () {
273 | pan = UIPanGestureRecognizer (target: self, action: "pan:")
274 | self.addGestureRecognizer(pan!)
275 | }
276 |
277 | func removePan () {
278 | self.removeGestureRecognizer(pan!)
279 | }
280 |
281 |
282 | func longPressed (gesture: UITapGestureRecognizer) {
283 | if isReordering { return } else { isReordering = true }
284 | delegate?.didReorderStartedForView(self)
285 | }
286 |
287 | func doubleTapped (gesture: UITapGestureRecognizer) {
288 | isReordering = !isReordering
289 |
290 | if isReordering {
291 | delegate?.didReorderStartedForView(self)
292 | }
293 | }
294 |
295 | func pan (gesture: UIPanGestureRecognizer) {
296 | switch gesture.state {
297 | case .Ended:
298 | isReordering = false
299 | delegate.didReorderEndForView(self, pan: pan!)
300 |
301 | case .Changed:
302 | delegate.didReorderedView(self, pan: pan!)
303 |
304 | default:
305 | return
306 | }
307 | }
308 |
309 |
310 | func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
311 | return false
312 | }
313 |
314 | }
315 |
316 |
317 | class ReorderableGridView: UIScrollView, Reorderable {
318 |
319 |
320 | // MARK: Properties
321 |
322 | var itemWidth: CGFloat?
323 | var verticalPadding: CGFloat?
324 | var horizontalPadding: CGFloat?
325 | var colsInRow: Int?
326 |
327 | var visibleRect: CGRect?
328 |
329 | var reorderable : Bool = true
330 | var draggable : Bool = true
331 |
332 | var draggableDelegate: Draggable?
333 |
334 | var reorderableViews : [ReorderableView] = []
335 |
336 |
337 |
338 | // MARK: Observers
339 |
340 | var currentCol: Int = 0 {
341 | didSet {
342 | if currentCol > colsInRow!-1 {
343 | currentCol = 0
344 | currentRow++
345 | } else if currentCol < 0 {
346 | currentCol = colsInRow!-1
347 | currentRow--
348 | }
349 | }
350 | }
351 |
352 | var currentRow: Int = 0 {
353 | didSet {
354 | if currentRow < 0 {
355 | currentRow = 0
356 | }
357 | }
358 | }
359 |
360 | override var contentOffset: CGPoint {
361 | didSet {
362 | visibleRect? = CGRect (origin: contentOffset, size: frame.size)
363 | checkReusableViews()
364 | }
365 | }
366 |
367 |
368 |
369 | // MARK: Lifecycle
370 |
371 | init (frame: CGRect, itemWidth: CGFloat, verticalPadding: CGFloat = 10) {
372 | super.init(frame: frame)
373 | self.itemWidth = itemWidth
374 | self.verticalPadding = verticalPadding
375 | self.visibleRect = frame
376 |
377 | invalidateLayout()
378 | }
379 |
380 | required init(coder aDecoder: NSCoder) {
381 | fatalError("init(coder:) has not been implemented")
382 | }
383 |
384 |
385 |
386 | // MARK: ScrollView
387 |
388 | func setContentHeight (height: CGFloat) {
389 | contentSize = CGSize (width: w, height: height)
390 | }
391 |
392 | func addContentHeight (height: CGFloat) {
393 | setContentHeight(contentSize.height + height)
394 | }
395 |
396 | func isViewInVisibleRect (view: ReorderableView) -> Bool {
397 | if let rect = visibleRect {
398 | return CGRectIntersectsRect(view.frame, rect)
399 | } else {
400 | return false
401 | }
402 | }
403 |
404 | func checkReusableViews () {
405 | for view in reorderableViews {
406 | if isViewInVisibleRect(view) {
407 | // is already added to view stack
408 | if let superView = view.superview {
409 | if superView == self {
410 | // already added
411 | continue
412 | } else {
413 | // FIXME: another view is super !
414 | continue
415 | }
416 | } else {
417 | if let gridPos = view.gridPosition {
418 | // add
419 | addSubview(view)
420 | placeView(view, toGridPosition: gridPos)
421 | } else {
422 | // not initilized yet
423 | continue
424 | }
425 | }
426 | } else {
427 | // should removed
428 | if let superView = view.superview {
429 | if superView == self {
430 | // remove
431 | view.removeFromSuperview()
432 | } else {
433 | // FIXME: another view is super !
434 | continue
435 | }
436 | } else {
437 | // already removed
438 | continue
439 | }
440 | }
441 | }
442 | }
443 |
444 |
445 |
446 | // MARK: Layout
447 |
448 | func invalidateLayout () {
449 | colsInRow = Int (self.w / itemWidth!)
450 | horizontalPadding = (self.w - (CGFloat(colsInRow!) * itemWidth!)) / (CGFloat(colsInRow!) - 1)
451 | contentSize.height = contentOffset.y + h
452 |
453 | currentCol = 0
454 | currentRow = 0
455 |
456 | if reorderableViews.isEmpty {
457 | return
458 | }
459 |
460 | for i in 0...reorderableViews.count-1 {
461 | let y = currentRow
462 | let x = currentCol++
463 | let gridPosition = GridPosition (x: x, y: y)
464 |
465 | placeView(reorderableViews[i], toGridPosition: gridPosition)
466 | }
467 | }
468 |
469 | func placeView (view: ReorderableView, toGridPosition: GridPosition) {
470 | view.gridPosition = toGridPosition
471 | view.delegate = self
472 |
473 | let pos = gridPositionToViewPosition(toGridPosition)
474 | view.setPosition(pos)
475 |
476 | let height = view.botttomWithOffset(verticalPadding!)
477 | if height > contentSize.height {
478 | setContentHeight(height)
479 | }
480 | }
481 |
482 | func insertViewAtPosition (view: ReorderableView, position: GridPosition) {
483 | if (view.gridPosition == position) {
484 | return
485 | }
486 |
487 | reorderableViews.removeAtIndex(view.gridPosition!.arrayIndex(colsInRow!))
488 | reorderableViews.insert(view, atIndex: position.arrayIndex(colsInRow!))
489 | invalidateLayout()
490 | }
491 |
492 |
493 |
494 | // MARK: Grid
495 |
496 | func gridPositionToViewPosition (gridPosition: GridPosition) -> CGPoint {
497 | var x : CGFloat = (CGFloat(gridPosition.x! - 1) * (itemWidth! + verticalPadding!)) + itemWidth!
498 | var y : CGFloat = 0
499 |
500 | if let up = gridPosition.up() {
501 | y = viewAtGridPosition(up)!.bottom + verticalPadding!
502 | }
503 |
504 | return CGPoint (x: x, y: y)
505 | }
506 |
507 | func viewAtGridPosition (gridPosition: GridPosition) -> ReorderableView? {
508 | let index = gridPosition.arrayIndex(colsInRow!)
509 | if (index < reorderableViews.count) {
510 | return reorderableViews[index]
511 | } else {
512 | return nil
513 | }
514 | }
515 |
516 |
517 |
518 | // MARK: Adding
519 |
520 | func addReorderableView (view: ReorderableView) {
521 | super.addSubview(view)
522 | reorderableViews.append(view)
523 | invalidateLayout()
524 | }
525 |
526 | func addReorderableView (view: ReorderableView, gridPosition: GridPosition) {
527 | super.addSubview(view)
528 |
529 | var addingIndex = gridPosition.arrayIndex(colsInRow!)
530 | if addingIndex >= reorderableViews.count {
531 | addingIndex = reorderableViews.count
532 | }
533 |
534 | reorderableViews.insert(view, atIndex: addingIndex)
535 | invalidateLayout()
536 | }
537 |
538 |
539 |
540 | // MARK: Removing
541 |
542 | func removeReorderableViewAtGridPosition (gridPosition: GridPosition) {
543 | if let view = viewAtGridPosition(gridPosition) {
544 | reorderableViews.removeAtIndex(gridPosition.arrayIndex(colsInRow!))
545 |
546 | view.removeFromSuperview()
547 | invalidateLayout()
548 | }
549 | }
550 |
551 | func removeReorderableView (view: ReorderableView) {
552 | if let pos = view.gridPosition {
553 | removeReorderableViewAtGridPosition(pos)
554 | } else {
555 | println ("view is not in grid hierarchy")
556 | }
557 | }
558 |
559 |
560 |
561 | // MARK: Reorderable
562 |
563 | func didReorderStartedForView (view: ReorderableView) {
564 | draggableDelegate?.didDragStartedForView(self, view: view)
565 | }
566 |
567 | func didReorderedView (view: ReorderableView, pan: UIPanGestureRecognizer) {
568 |
569 | if !draggable {
570 | return
571 | } else {
572 | draggableDelegate?.didDraggedView(self, view: view)
573 | }
574 |
575 | let location = pan.locationInView(self)
576 | view.center = location
577 |
578 |
579 | if !reorderable {
580 | return
581 | }
582 |
583 | let col : Int = min(Int(location.x) / Int(itemWidth! + horizontalPadding!), colsInRow!-1)
584 | let rowCount : Int = reorderableViews.count/colsInRow!
585 |
586 | var gridPos = GridPosition (x: col, y: 0)
587 | for (var row = 0; row < reorderableViews.count/colsInRow!; row++) {
588 | gridPos.y = row
589 |
590 | if let otherView = viewAtGridPosition(gridPos) {
591 | if otherView == view {
592 | continue
593 | }
594 |
595 | if CGRectContainsPoint(otherView.frame, location) {
596 | //println("im at \(col), \(row), im " + view.gridPosition!.string())
597 | insertViewAtPosition(view, position: gridPos)
598 | }
599 | }
600 | }
601 | }
602 |
603 | func didReorderEndForView (view: ReorderableView, pan: UIPanGestureRecognizer) {
604 | if reorderable {
605 | invalidateLayout()
606 | }
607 |
608 | if draggable {
609 | draggableDelegate?.didDragEndForView(self, view: view)
610 | }
611 | }
612 | }
613 |
--------------------------------------------------------------------------------
/ReorderableGridView-Swift/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // ReorderableGridView-Swift
4 | //
5 | // Created by Cem Olcay on 19/11/14.
6 | // Copyright (c) 2014 Cem Olcay. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension UIFont {
12 |
13 | enum FontType: String {
14 | case Regular = "Regular"
15 | case Bold = "Bold"
16 | case Light = "Light"
17 | case UltraLight = "UltraLight"
18 | case Italic = "Italic"
19 | case Thin = "Thin"
20 | }
21 |
22 | enum FontName: String {
23 | case HelveticaNeue = "HelveticaNeue"
24 | case Helvetica = "Helvetica"
25 | case Futura = "Futura"
26 | case Menlo = "Menlo"
27 | }
28 |
29 | class func Font (name: FontName, type: FontType, size: CGFloat) -> UIFont {
30 | return UIFont (name: name.rawValue + "-" + type.rawValue, size: size)!
31 | }
32 |
33 | class func HelveticaNeue (type: FontType, size: CGFloat) -> UIFont {
34 | return Font(.HelveticaNeue, type: type, size: size)
35 | }
36 | }
37 |
38 | class ViewController: UIViewController {
39 |
40 | // MARK: Properties
41 |
42 | var borderColor: UIColor?
43 | var bgColor: UIColor?
44 | var bottomColor: UIColor?
45 |
46 | var gridView : ReorderableGridView?
47 | var itemCount: Int = 0
48 |
49 |
50 |
51 | // MARK: Lifecycle
52 |
53 | override func viewDidLoad() {
54 | super.viewDidLoad()
55 |
56 | borderColor = RGBColor(233, g: 233, b: 233)
57 | bgColor = RGBColor(242, g: 242, b: 242)
58 | bottomColor = RGBColor(65, g: 65, b: 65)
59 |
60 | self.title = "Reorderable Grid"
61 | self.navigationItem.title = "Reorderable Grid View Demo"
62 | self.view.backgroundColor = bgColor
63 |
64 | setupGridView()
65 | }
66 |
67 | override func viewDidAppear(animated: Bool) {
68 | if let grid = gridView {
69 | grid.invalidateLayout()
70 | }
71 | }
72 |
73 |
74 |
75 | // MARK: Grid View
76 |
77 | func setupGridView () {
78 | let add = UIBarButtonItem (barButtonSystemItem: UIBarButtonSystemItem.Add, target: self, action: "addPressed:")
79 | let remove = UIBarButtonItem (barButtonSystemItem: UIBarButtonSystemItem.Trash, target: self, action: "removePressed:")
80 |
81 | self.navigationItem.leftBarButtonItem = add
82 | self.navigationItem.rightBarButtonItem = remove
83 |
84 | gridView = ReorderableGridView(frame: view.frame, itemWidth: 180, verticalPadding: 20)
85 | view.addSubview(gridView!)
86 |
87 | for _ in 0..<100 {
88 | gridView!.addReorderableView(itemView())
89 | }
90 | }
91 |
92 | func itemView () -> ReorderableView {
93 | let w : CGFloat = 180
94 | let h : CGFloat = 100 + CGFloat(arc4random()%100)
95 |
96 | let view = ReorderableView (x: 0, y: 0, w: w, h: h)
97 | view.tag = itemCount++
98 | view.layer.borderColor = borderColor?.CGColor
99 | view.layer.backgroundColor = UIColor.whiteColor().CGColor
100 | view.layer.borderWidth = 1
101 | view.layer.cornerRadius = 5
102 | view.layer.masksToBounds = true
103 |
104 | let topView = UIView(x: 0, y: 0, w: view.w, h: 50)
105 | view.addSubview(topView)
106 |
107 | let itemLabel = UILabel (frame: topView.frame)
108 | itemLabel.center = topView.center
109 | itemLabel.font = UIFont.HelveticaNeue(.Thin, size: 20)
110 | itemLabel.textAlignment = NSTextAlignment.Center
111 | itemLabel.textColor = bottomColor?
112 | itemLabel.text = "\(view.tag)"
113 | itemLabel.layer.masksToBounds = true
114 | topView.addSubview(itemLabel)
115 |
116 | let sepLayer = CALayer ()
117 | sepLayer.frame = CGRect (x: 0, y: topView.bottom, width: topView.w, height: 1)
118 | sepLayer.backgroundColor = borderColor?.CGColor
119 | topView.layer.addSublayer(sepLayer)
120 |
121 | let bottomView = UIView(frame: CGRect(x: 0, y: topView.bottom, width: view.w, height: view.h-topView.h))
122 | let bottomLayer = CALayer ()
123 | bottomLayer.frame = CGRect (x: 0, y: bottomView.h-5, width: bottomView.w, height: 5)
124 | bottomLayer.backgroundColor = bottomColor?.CGColor
125 | bottomView.layer.addSublayer(bottomLayer)
126 | bottomView.layer.masksToBounds = true
127 | view.addSubview(bottomView)
128 |
129 | return view
130 | }
131 |
132 |
133 |
134 | // MARK: Add/Remove
135 |
136 | func addPressed (sender: AnyObject) {
137 | //gridView?.addReorderableView(itemView())
138 | gridView?.addReorderableView(itemView(), gridPosition: GridPosition (x: 0, y: 1))
139 | }
140 |
141 | func removePressed (sender: AnyObject) {
142 | gridView?.removeReorderableViewAtGridPosition(GridPosition (x: 0, y: 0))
143 | //gridView?.removeReorderableView(gridView!.ReorderableViews[2])
144 | }
145 |
146 |
147 |
148 | // MARK: Interface Rotation
149 |
150 | override func willRotateToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) {
151 | let w = UIScreen.mainScreen().bounds.size.width
152 | let h = UIScreen.mainScreen().bounds.size.height
153 |
154 | gridView?.setW(h, h: w)
155 | gridView?.invalidateLayout()
156 | }
157 |
158 |
159 |
160 | // MARK: Utils
161 |
162 | func randomColor () -> UIColor {
163 | var randomRed:CGFloat = CGFloat(drand48())
164 | var randomGreen:CGFloat = CGFloat(drand48())
165 | var randomBlue:CGFloat = CGFloat(drand48())
166 |
167 | return UIColor(red: randomRed, green: randomGreen, blue: randomBlue, alpha: 1.0)
168 | }
169 |
170 | func RGBColor(r: CGFloat, g: CGFloat, b: CGFloat) -> UIColor {
171 | return UIColor (red: r / 255.0, green: g / 255.0, blue: b / 255.0, alpha: 1)
172 | }
173 |
174 | func RGBAColor (r: CGFloat, g: CGFloat, b: CGFloat, a: CGFloat) -> UIColor {
175 | return UIColor (red: r / 255.0, green: g / 255.0, blue: b / 255.0, alpha: a)
176 | }
177 | }
178 |
179 |
--------------------------------------------------------------------------------
/ReorderableGridView-SwiftTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | com.questa.$(PRODUCT_NAME:rfc1034identifier)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/ReorderableGridView-SwiftTests/ReorderableGridView_SwiftTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ReorderableGridView_SwiftTests.swift
3 | // ReorderableGridView-SwiftTests
4 | //
5 | // Created by Cem Olcay on 19/11/14.
6 | // Copyright (c) 2014 Cem Olcay. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import XCTest
11 |
12 | class ReorderableGridView_SwiftTests: XCTestCase {
13 |
14 | override func setUp() {
15 | super.setUp()
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 | }
18 |
19 | override func tearDown() {
20 | // Put teardown code here. This method is called after the invocation of each test method in the class.
21 | super.tearDown()
22 | }
23 |
24 | func testExample() {
25 | // This is an example of a functional test case.
26 | XCTAssert(true, "Pass")
27 | }
28 |
29 | func testPerformanceExample() {
30 | // This is an example of a performance test case.
31 | self.measureBlock() {
32 | // Put the code you want to measure the time of here.
33 | }
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cemolcay/ReorderableGridView-Swift/176ab79d6a4513444758b2591d27c670ca31101b/demo.gif
--------------------------------------------------------------------------------