├── .swift-version
├── Assets
├── animation.gif
├── screenshot1.png
└── screenshot2.png
├── RAReorderableLayout-Demo
├── RAReorderableLayout-Demo
│ ├── Images.xcassets
│ │ ├── Contents.json
│ │ ├── sample
│ │ │ ├── Sample0.imageset
│ │ │ │ ├── Sample0.jpg
│ │ │ │ └── Contents.json
│ │ │ ├── Sample1.imageset
│ │ │ │ ├── Sample1.jpg
│ │ │ │ └── Contents.json
│ │ │ ├── Sample10.imageset
│ │ │ │ ├── Sample10.jpg
│ │ │ │ └── Contents.json
│ │ │ ├── Sample11.imageset
│ │ │ │ ├── Sample11.jpg
│ │ │ │ └── Contents.json
│ │ │ ├── Sample12.imageset
│ │ │ │ ├── Sample12.jpg
│ │ │ │ └── Contents.json
│ │ │ ├── Sample13.imageset
│ │ │ │ ├── Sample13.jpg
│ │ │ │ └── Contents.json
│ │ │ ├── Sample14.imageset
│ │ │ │ ├── Sample14.jpg
│ │ │ │ └── Contents.json
│ │ │ ├── Sample15.imageset
│ │ │ │ ├── Sample15.jpg
│ │ │ │ └── Contents.json
│ │ │ ├── Sample16.imageset
│ │ │ │ ├── Sample16.jpg
│ │ │ │ └── Contents.json
│ │ │ ├── Sample17.imageset
│ │ │ │ ├── Sample17.jpg
│ │ │ │ └── Contents.json
│ │ │ ├── Sample18.imageset
│ │ │ │ ├── Sample18.jpg
│ │ │ │ └── Contents.json
│ │ │ ├── Sample19.imageset
│ │ │ │ ├── Sample19.jpg
│ │ │ │ └── Contents.json
│ │ │ ├── Sample2.imageset
│ │ │ │ ├── Sample2.jpg
│ │ │ │ └── Contents.json
│ │ │ ├── Sample20.imageset
│ │ │ │ ├── Sample20.jpg
│ │ │ │ └── Contents.json
│ │ │ ├── Sample21.imageset
│ │ │ │ ├── Sample21.jpg
│ │ │ │ └── Contents.json
│ │ │ ├── Sample22.imageset
│ │ │ │ ├── Sample22.jpg
│ │ │ │ └── Contents.json
│ │ │ ├── Sample23.imageset
│ │ │ │ ├── Sample23.jpg
│ │ │ │ └── Contents.json
│ │ │ ├── Sample24.imageset
│ │ │ │ ├── Sample24.jpg
│ │ │ │ └── Contents.json
│ │ │ ├── Sample25.imageset
│ │ │ │ ├── Sample25.jpg
│ │ │ │ └── Contents.json
│ │ │ ├── Sample26.imageset
│ │ │ │ ├── Sample26.jpg
│ │ │ │ └── Contents.json
│ │ │ ├── Sample27.imageset
│ │ │ │ ├── Sample27.jpg
│ │ │ │ └── Contents.json
│ │ │ ├── Sample28.imageset
│ │ │ │ ├── Sample28.jpg
│ │ │ │ └── Contents.json
│ │ │ ├── Sample29.imageset
│ │ │ │ ├── Sample29.jpg
│ │ │ │ └── Contents.json
│ │ │ ├── Sample3.imageset
│ │ │ │ ├── Sample3.jpg
│ │ │ │ └── Contents.json
│ │ │ ├── Sample4.imageset
│ │ │ │ ├── Sample4.jpg
│ │ │ │ └── Contents.json
│ │ │ ├── Sample5.imageset
│ │ │ │ ├── Sample5.jpg
│ │ │ │ └── Contents.json
│ │ │ ├── Sample6.imageset
│ │ │ │ ├── Sample6.jpg
│ │ │ │ └── Contents.json
│ │ │ ├── Sample7.imageset
│ │ │ │ ├── Sample7.jpg
│ │ │ │ └── Contents.json
│ │ │ ├── Sample8.imageset
│ │ │ │ ├── Sample8.jpg
│ │ │ │ └── Contents.json
│ │ │ └── Sample9.imageset
│ │ │ │ ├── Sample9.jpg
│ │ │ │ └── Contents.json
│ │ ├── AppIcon.appiconset
│ │ │ └── Contents.json
│ │ └── LaunchImage.launchimage
│ │ │ └── Contents.json
│ ├── RAReorderableLayout_Demo.xcdatamodeld
│ │ ├── .xccurrentversion
│ │ └── RAReorderableLayout_Demo.xcdatamodel
│ │ │ └── contents
│ ├── AppDelegate.swift
│ ├── Info.plist
│ ├── ViewController.swift
│ ├── Base.lproj
│ │ └── LaunchScreen.xib
│ ├── VerticalViewController.swift
│ ├── HorizontalViewController.swift
│ └── Main.storyboard
├── RAReorderableLayout-Demo.xcodeproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── project.pbxproj
└── RAReorderableLayout-DemoTests
│ ├── Info.plist
│ └── RAReorderableLayout_DemoTests.swift
├── RAReorderableLayout.xcodeproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
├── xcshareddata
│ └── xcschemes
│ │ └── RAReorderableLayout.xcscheme
└── project.pbxproj
├── .travis.yml
├── RAReorderableLayout.podspec
├── RAReorderableLayout
├── RAReorderableLayout.h
├── Info.plist
└── RAReorderableLayout.swift
├── .gitignore
├── LICENSE
└── README.md
/.swift-version:
--------------------------------------------------------------------------------
1 | 3.0
2 |
--------------------------------------------------------------------------------
/Assets/animation.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ra1028/RAReorderableLayout/HEAD/Assets/animation.gif
--------------------------------------------------------------------------------
/Assets/screenshot1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ra1028/RAReorderableLayout/HEAD/Assets/screenshot1.png
--------------------------------------------------------------------------------
/Assets/screenshot2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ra1028/RAReorderableLayout/HEAD/Assets/screenshot2.png
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample0.imageset/Sample0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ra1028/RAReorderableLayout/HEAD/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample0.imageset/Sample0.jpg
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample1.imageset/Sample1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ra1028/RAReorderableLayout/HEAD/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample1.imageset/Sample1.jpg
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample10.imageset/Sample10.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ra1028/RAReorderableLayout/HEAD/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample10.imageset/Sample10.jpg
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample11.imageset/Sample11.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ra1028/RAReorderableLayout/HEAD/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample11.imageset/Sample11.jpg
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample12.imageset/Sample12.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ra1028/RAReorderableLayout/HEAD/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample12.imageset/Sample12.jpg
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample13.imageset/Sample13.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ra1028/RAReorderableLayout/HEAD/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample13.imageset/Sample13.jpg
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample14.imageset/Sample14.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ra1028/RAReorderableLayout/HEAD/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample14.imageset/Sample14.jpg
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample15.imageset/Sample15.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ra1028/RAReorderableLayout/HEAD/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample15.imageset/Sample15.jpg
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample16.imageset/Sample16.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ra1028/RAReorderableLayout/HEAD/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample16.imageset/Sample16.jpg
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample17.imageset/Sample17.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ra1028/RAReorderableLayout/HEAD/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample17.imageset/Sample17.jpg
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample18.imageset/Sample18.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ra1028/RAReorderableLayout/HEAD/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample18.imageset/Sample18.jpg
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample19.imageset/Sample19.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ra1028/RAReorderableLayout/HEAD/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample19.imageset/Sample19.jpg
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample2.imageset/Sample2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ra1028/RAReorderableLayout/HEAD/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample2.imageset/Sample2.jpg
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample20.imageset/Sample20.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ra1028/RAReorderableLayout/HEAD/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample20.imageset/Sample20.jpg
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample21.imageset/Sample21.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ra1028/RAReorderableLayout/HEAD/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample21.imageset/Sample21.jpg
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample22.imageset/Sample22.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ra1028/RAReorderableLayout/HEAD/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample22.imageset/Sample22.jpg
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample23.imageset/Sample23.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ra1028/RAReorderableLayout/HEAD/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample23.imageset/Sample23.jpg
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample24.imageset/Sample24.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ra1028/RAReorderableLayout/HEAD/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample24.imageset/Sample24.jpg
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample25.imageset/Sample25.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ra1028/RAReorderableLayout/HEAD/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample25.imageset/Sample25.jpg
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample26.imageset/Sample26.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ra1028/RAReorderableLayout/HEAD/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample26.imageset/Sample26.jpg
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample27.imageset/Sample27.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ra1028/RAReorderableLayout/HEAD/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample27.imageset/Sample27.jpg
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample28.imageset/Sample28.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ra1028/RAReorderableLayout/HEAD/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample28.imageset/Sample28.jpg
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample29.imageset/Sample29.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ra1028/RAReorderableLayout/HEAD/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample29.imageset/Sample29.jpg
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample3.imageset/Sample3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ra1028/RAReorderableLayout/HEAD/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample3.imageset/Sample3.jpg
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample4.imageset/Sample4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ra1028/RAReorderableLayout/HEAD/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample4.imageset/Sample4.jpg
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample5.imageset/Sample5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ra1028/RAReorderableLayout/HEAD/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample5.imageset/Sample5.jpg
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample6.imageset/Sample6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ra1028/RAReorderableLayout/HEAD/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample6.imageset/Sample6.jpg
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample7.imageset/Sample7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ra1028/RAReorderableLayout/HEAD/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample7.imageset/Sample7.jpg
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample8.imageset/Sample8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ra1028/RAReorderableLayout/HEAD/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample8.imageset/Sample8.jpg
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample9.imageset/Sample9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ra1028/RAReorderableLayout/HEAD/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample9.imageset/Sample9.jpg
--------------------------------------------------------------------------------
/RAReorderableLayout.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | # reference: http://www.objc.io/issue-6/travis-ci.html
2 |
3 | language: objective-c
4 | # before_install: cd Example && pod install && cd -
5 | script:
6 | - xctool test -workspace Example/RAReorderableLayout.xcworkspace -scheme RAReorderableLayout -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO
7 |
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/RAReorderableLayout_Demo.xcdatamodeld/.xccurrentversion:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | _XCCurrentVersionName
6 | RAReorderableLayout_Demo.xcdatamodel
7 |
8 |
9 |
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // RAReorderableLayout-Demo
4 | //
5 | // Created by Ryo Aoyama on 10/29/14.
6 | // Copyright (c) 2014 Ryo Aoyama. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CoreData
11 |
12 | @UIApplicationMain
13 | class AppDelegate: UIResponder, UIApplicationDelegate {
14 | var window: UIWindow?
15 | }
16 |
17 |
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/RAReorderableLayout_Demo.xcdatamodeld/RAReorderableLayout_Demo.xcdatamodel/contents:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample0.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "Sample0.jpg"
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 | }
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample1.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "Sample1.jpg"
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 | }
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample2.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "Sample2.jpg"
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 | }
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample3.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "Sample3.jpg"
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 | }
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample4.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "Sample4.jpg"
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 | }
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample5.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "Sample5.jpg"
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 | }
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample6.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "Sample6.jpg"
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 | }
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample7.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "Sample7.jpg"
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 | }
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample8.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "Sample8.jpg"
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 | }
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample9.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "Sample9.jpg"
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 | }
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample10.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "Sample10.jpg"
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 | }
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample11.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "Sample11.jpg"
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 | }
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample12.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "Sample12.jpg"
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 | }
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample13.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "Sample13.jpg"
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 | }
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample14.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "Sample14.jpg"
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 | }
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample15.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "Sample15.jpg"
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 | }
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample16.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "Sample16.jpg"
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 | }
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample17.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "Sample17.jpg"
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 | }
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample18.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "Sample18.jpg"
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 | }
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample19.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "Sample19.jpg"
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 | }
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample20.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "Sample20.jpg"
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 | }
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample21.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "Sample21.jpg"
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 | }
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample22.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "Sample22.jpg"
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 | }
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample23.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "Sample23.jpg"
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 | }
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample24.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "Sample24.jpg"
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 | }
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample25.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "Sample25.jpg"
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 | }
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample26.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "Sample26.jpg"
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 | }
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample27.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "Sample27.jpg"
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 | }
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample28.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "Sample28.jpg"
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 | }
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/sample/Sample29.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "Sample29.jpg"
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 | }
--------------------------------------------------------------------------------
/RAReorderableLayout.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = "RAReorderableLayout"
3 | s.version = "0.6.1"
4 | s.summary = "A UICollectionView layout which you can move items with drag and drop."
5 | s.license = { :type => 'MIT', :file => 'LICENSE' }
6 | s.homepage = "https://github.com/ra1028"
7 | s.author = { "ra1028" => "r.fe51028.r@gmail.com" }
8 | s.platform = :ios, '8.0'
9 | s.source = { :git => "https://github.com/ra1028/RAReorderableLayout.git", :tag => s.version.to_s }
10 | s.requires_arc = true
11 | s.source_files = 'RAReorderableLayout/*.swift'
12 | end
13 |
--------------------------------------------------------------------------------
/RAReorderableLayout/RAReorderableLayout.h:
--------------------------------------------------------------------------------
1 | //
2 | // RAReorderableLayout.h
3 | // RAReorderableLayout
4 | //
5 | // Created by Yimin Lin on 8/27/15.
6 | // Copyright © 2015 Yowoo Technology Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for RAReorderableLayout.
12 | FOUNDATION_EXPORT double RAReorderableLayoutVersionNumber;
13 |
14 | //! Project version string for RAReorderableLayout.
15 | FOUNDATION_EXPORT const unsigned char RAReorderableLayoutVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
20 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # OS X
2 | .DS_Store
3 |
4 | # Xcode
5 | build/
6 | *.pbxuser
7 | !default.pbxuser
8 | *.mode1v3
9 | !default.mode1v3
10 | *.mode2v3
11 | !default.mode2v3
12 | *.perspectivev3
13 | !default.perspectivev3
14 | xcuserdata
15 | *.xccheckout
16 | profile
17 | *.moved-aside
18 | DerivedData
19 | *.hmap
20 | *.ipa
21 |
22 | # Bundler
23 | .bundle
24 |
25 | # We recommend against adding the Pods directory to your .gitignore. However
26 | # you should judge for yourself, the pros and cons are mentioned at:
27 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
28 | #
29 | # Note: if you ignore the Pods directory, make sure to uncomment
30 | # `pod install` in .travis.yml
31 | #
32 | # Pods/
33 |
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-DemoTests/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 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/RAReorderableLayout/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 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 ra1028
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-DemoTests/RAReorderableLayout_DemoTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RAReorderableLayout_DemoTests.swift
3 | // RAReorderableLayout-DemoTests
4 | //
5 | // Created by Ryo Aoyama on 10/29/14.
6 | // Copyright (c) 2014 Ryo Aoyama. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import XCTest
11 |
12 | class RAReorderableLayout_DemoTests: 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 |
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.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" : "1x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "2x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "29x29",
26 | "scale" : "3x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "2x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "40x40",
36 | "scale" : "3x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "57x57",
41 | "scale" : "1x"
42 | },
43 | {
44 | "idiom" : "iphone",
45 | "size" : "57x57",
46 | "scale" : "2x"
47 | },
48 | {
49 | "idiom" : "iphone",
50 | "size" : "60x60",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "iphone",
55 | "size" : "60x60",
56 | "scale" : "3x"
57 | }
58 | ],
59 | "info" : {
60 | "version" : 1,
61 | "author" : "xcode"
62 | }
63 | }
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIcons
10 |
11 | CFBundleIcons~ipad
12 |
13 | CFBundleIdentifier
14 | $(PRODUCT_BUNDLE_IDENTIFIER)
15 | CFBundleInfoDictionaryVersion
16 | 6.0
17 | CFBundleName
18 | $(PRODUCT_NAME)
19 | CFBundlePackageType
20 | APPL
21 | CFBundleShortVersionString
22 | 1.0
23 | CFBundleSignature
24 | ????
25 | CFBundleVersion
26 | 1
27 | LSRequiresIPhoneOS
28 |
29 | UILaunchStoryboardName
30 | Main
31 | UIMainStoryboardFile
32 | Main
33 | UIRequiredDeviceCapabilities
34 |
35 | armv7
36 |
37 | UISupportedInterfaceOrientations
38 |
39 | UIInterfaceOrientationPortrait
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/Images.xcassets/LaunchImage.launchimage/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "orientation" : "portrait",
5 | "idiom" : "iphone",
6 | "extent" : "full-screen",
7 | "minimum-system-version" : "8.0",
8 | "subtype" : "736h",
9 | "scale" : "3x"
10 | },
11 | {
12 | "orientation" : "landscape",
13 | "idiom" : "iphone",
14 | "extent" : "full-screen",
15 | "minimum-system-version" : "8.0",
16 | "subtype" : "736h",
17 | "scale" : "3x"
18 | },
19 | {
20 | "orientation" : "portrait",
21 | "idiom" : "iphone",
22 | "extent" : "full-screen",
23 | "minimum-system-version" : "8.0",
24 | "subtype" : "667h",
25 | "scale" : "2x"
26 | },
27 | {
28 | "orientation" : "portrait",
29 | "idiom" : "iphone",
30 | "extent" : "full-screen",
31 | "minimum-system-version" : "7.0",
32 | "scale" : "2x"
33 | },
34 | {
35 | "orientation" : "portrait",
36 | "idiom" : "iphone",
37 | "extent" : "full-screen",
38 | "minimum-system-version" : "7.0",
39 | "subtype" : "retina4",
40 | "scale" : "2x"
41 | },
42 | {
43 | "orientation" : "portrait",
44 | "idiom" : "iphone",
45 | "extent" : "full-screen",
46 | "scale" : "1x"
47 | },
48 | {
49 | "orientation" : "portrait",
50 | "idiom" : "iphone",
51 | "extent" : "full-screen",
52 | "scale" : "2x"
53 | },
54 | {
55 | "orientation" : "portrait",
56 | "idiom" : "iphone",
57 | "extent" : "full-screen",
58 | "subtype" : "retina4",
59 | "scale" : "2x"
60 | }
61 | ],
62 | "info" : {
63 | "version" : 1,
64 | "author" : "xcode"
65 | }
66 | }
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // RAReorderableLayout-Demo
4 | //
5 | // Created by Ryo Aoyama on 10/29/14.
6 | // Copyright (c) 2014 Ryo Aoyama. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ViewController: UIViewController {
12 | @IBOutlet weak var verticalButton: RAButton!
13 |
14 | @IBOutlet weak var horizontalButton: RAButton!
15 |
16 | required init?(coder aDecoder: NSCoder) {
17 | super.init(coder: aDecoder)
18 | }
19 |
20 | override func viewDidLoad() {
21 | super.viewDidLoad()
22 | title = "RAReorderableLayout"
23 | verticalButton.isExclusiveTouch = true
24 | horizontalButton.isExclusiveTouch = true
25 | }
26 |
27 | override func viewWillAppear(_ animated: Bool) {
28 | super.viewWillAppear(animated)
29 | let num1: CGFloat = CGFloat(arc4random_uniform(256)) / 255.0
30 | let num2: CGFloat = CGFloat(arc4random_uniform(256)) / 255.0
31 | let num3: CGFloat = CGFloat(arc4random_uniform(256)) / 255.0
32 | let color1: UIColor = UIColor(red: num1, green: num2, blue: num3, alpha: 1.0)
33 | let color2: UIColor = UIColor(red: num3, green: num2, blue: num1, alpha: 1.0)
34 |
35 | if (num1 + num2 + num3) / 3.0 >= 0.5 {
36 | verticalButton.setTitleColor(UIColor.black, for: UIControlState())
37 | horizontalButton.setTitleColor(UIColor.black, for: UIControlState())
38 | }else {
39 | verticalButton.setTitleColor(UIColor.white, for: UIControlState())
40 | horizontalButton.setTitleColor(UIColor.white, for: UIControlState())
41 | }
42 |
43 | verticalButton.backgroundColor = color1
44 | horizontalButton.backgroundColor = color2
45 | }
46 | }
47 |
48 | class RAButton: UIButton {
49 | var baseView: UIView!
50 |
51 | override var isHighlighted: Bool {
52 | didSet {
53 | let transform: CGAffineTransform = isHighlighted ?
54 | CGAffineTransform(scaleX: 1.1, y: 1.1) : CGAffineTransform.identity
55 | UIView.animate(
56 | withDuration: 0.05,
57 | delay: 0,
58 | options: .beginFromCurrentState,
59 | animations: {
60 | self.transform = transform
61 | },
62 | completion: nil
63 | )
64 | }
65 | }
66 |
67 | required init?(coder aDecoder: NSCoder) {
68 | super.init(coder: aDecoder)
69 | configure()
70 | }
71 |
72 | override func layoutSubviews() {
73 | super.layoutSubviews()
74 | layer.cornerRadius = bounds.width / 2;
75 | }
76 |
77 | private func configure() {
78 | baseView = UIView(frame: bounds)
79 | layer.cornerRadius = bounds.width
80 | baseView.addSubview(self)
81 | translatesAutoresizingMaskIntoConstraints = false
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | RAReorderableLayout
2 | =======================
3 |
4 | #### A UICollectionView layout which you can move items with drag and drop.
5 |
6 |
7 | ## Screen shots
8 | 
9 | 
10 |
11 |
12 | ## Animation
13 | 
14 |
15 | ## Requirements
16 | - Swift 3.0 / Xcode 8
17 | OS X 10.9 or later
18 | iOS 8.0 or later
19 | watchOS 2.0 or later
20 | tvOS 9.0 or later
21 |
22 | _Still wanna use swift2.2 or 2.3?_
23 | -> You can use [0.5.0](https://github.com/ra1028/RAReorderableLayout/tree/0.5.0) instead.
24 |
25 | ## Installation
26 | __iOS8 or later__
27 |
28 | ### CocoaPods
29 | ```ruby
30 | # Podfile
31 | use_frameworks!
32 |
33 | target 'YOUR_TARGET_NAME' do
34 | pod 'RAReorderableLayout'
35 | end
36 |
37 | ```
38 | ### Carthage
39 | ```ruby
40 | # Cartfile
41 | github "ra1028/RAReorderableLayout"
42 | ```
43 |
44 | ## Usage
45 | Setup your collection view to use RAReorderableLayout.
46 | You must reorder cells information array in RAReorderableLayoutDelegate protocol to support reordering capability.
47 | Specifically, please refer to Demo-project.
48 |
49 |
50 | ## Protocol
51 |
52 | Delegate
53 | ```
54 | optional func collectionView(collectionView: UICollectionView, atIndexPath: NSIndexPath, willMoveToIndexPath toIndexPath: NSIndexPath)
55 | optional func collectionView(collectionView: UICollectionView, atIndexPath: NSIndexPath, didMoveToIndexPath toIndexPath: NSIndexPath)
56 |
57 | optional func collectionView(collectionView: UICollectionView, allowMoveAtIndexPath indexPath: NSIndexPath) -> Bool
58 | optional func collectionView(collectionView: UICollectionView, atIndexPath: NSIndexPath, canMoveToIndexPath: NSIndexPath) -> Bool
59 |
60 | optional func collectionView(collectionView: UICollectionView, collectionViewLayout layout: RAReorderableLayout, willBeginDraggingItemAtIndexPath indexPath: NSIndexPath)
61 | optional func collectionView(collectionView: UICollectionView, collectionViewLayout layout: RAReorderableLayout, didBeginDraggingItemAtIndexPath indexPath: NSIndexPath)
62 | optional func collectionView(collectionView: UICollectionView, collectionViewLayout layout: RAReorderableLayout, willEndDraggingItemToIndexPath indexPath: NSIndexPath)
63 | optional func collectionView(collectionView: UICollectionView, collectionViewLayout layout: RAReorderableLayout, didEndDraggingItemToIndexPath indexPath: NSIndexPath)
64 | ```
65 |
66 | Datasource
67 | ```
68 | optional func collectionView(collectionView: UICollectionView, reorderingItemAlphaInSection section: Int) -> CGFloat
69 | optional func scrollTrigerEdgeInsetsInCollectionView(collectionView: UICollectionView) -> UIEdgeInsets
70 | optional func scrollTrigerPaddingInCollectionView(collectionView: UICollectionView) -> UIEdgeInsets
71 | optional func scrollSpeedValueInCollectionView(collectionView: UICollectionView) -> CGFloat
72 | ```
73 |
74 | ## License
75 | RAReorderableLayout is available under the MIT license. See the LICENSE file for more info.
76 |
--------------------------------------------------------------------------------
/RAReorderableLayout.xcodeproj/xcshareddata/xcschemes/RAReorderableLayout.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
34 |
35 |
45 |
46 |
52 |
53 |
54 |
55 |
56 |
57 |
63 |
64 |
70 |
71 |
72 |
73 |
75 |
76 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/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 |
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/VerticalViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // VerticalViewController.swift
3 | // RAReorderableLayout-Demo
4 | //
5 | // Created by Ryo Aoyama on 11/17/14.
6 | // Copyright (c) 2014 Ryo Aoyama. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class VerticalViewController: UIViewController, RAReorderableLayoutDelegate, RAReorderableLayoutDataSource {
12 |
13 | @IBOutlet var collectionView: UICollectionView!
14 |
15 | var imagesForSection0: [UIImage] = []
16 | var imagesForSection1: [UIImage] = []
17 |
18 | override func viewDidLoad() {
19 | super.viewDidLoad()
20 | self.title = "RAReorderableLayout"
21 | let nib = UINib(nibName: "verticalCell", bundle: nil)
22 | collectionView.register(nib, forCellWithReuseIdentifier: "cell")
23 | collectionView.delegate = self
24 | collectionView.dataSource = self
25 |
26 | for index in 0..<18 {
27 | let name = "Sample\(index).jpg"
28 | let image = UIImage(named: name)
29 | imagesForSection0.append(image!)
30 | }
31 | for index in 18..<30 {
32 | let name = "Sample\(index).jpg"
33 | let image = UIImage(named: name)
34 | imagesForSection1.append(image!)
35 | }
36 | }
37 |
38 | override func viewDidLayoutSubviews() {
39 | super.viewDidLayoutSubviews()
40 | collectionView.contentInset = UIEdgeInsetsMake(topLayoutGuide.length, 0, 0, 0)
41 | }
42 |
43 | // RAReorderableLayout delegate datasource
44 |
45 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
46 | let screenWidth = UIScreen.main.bounds.width
47 | let threePiecesWidth = floor(screenWidth / 3.0 - ((2.0 / 3) * 2))
48 | let twoPiecesWidth = floor(screenWidth / 2.0 - (2.0 / 2))
49 | if (indexPath as NSIndexPath).section == 0 {
50 | return CGSize(width: threePiecesWidth, height: threePiecesWidth)
51 | }else {
52 | return CGSize(width: twoPiecesWidth, height: twoPiecesWidth)
53 | }
54 | }
55 |
56 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
57 | return 2.0
58 | }
59 |
60 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
61 | return 2.0
62 | }
63 |
64 | func numberOfSections(in collectionView: UICollectionView) -> Int {
65 | return 2
66 | }
67 |
68 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
69 | return UIEdgeInsetsMake(0, 0, 2.0, 0)
70 | }
71 |
72 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
73 | if section == 0 {
74 | return imagesForSection0.count
75 | }else {
76 | return imagesForSection1.count
77 | }
78 | }
79 |
80 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
81 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "verticalCell", for: indexPath) as! RACollectionViewCell
82 |
83 | if (indexPath as NSIndexPath).section == 0 {
84 | cell.imageView.image = imagesForSection0[(indexPath as NSIndexPath).item]
85 | }else {
86 | cell.imageView.image = imagesForSection1[(indexPath as NSIndexPath).item]
87 | }
88 | return cell
89 | }
90 |
91 | func collectionView(_ collectionView: UICollectionView, allowMoveAt indexPath: IndexPath) -> Bool {
92 | if collectionView.numberOfItems(inSection: (indexPath as NSIndexPath).section) <= 1 {
93 | return false
94 | }
95 | return true
96 | }
97 |
98 | func collectionView(_ collectionView: UICollectionView, at: IndexPath, willMoveTo toIndexPath: IndexPath) {
99 |
100 | }
101 |
102 | func collectionView(_ collectionView: UICollectionView, at atIndexPath: IndexPath, didMoveTo toIndexPath: IndexPath) {
103 | var photo: UIImage
104 | if (atIndexPath as NSIndexPath).section == 0 {
105 | photo = imagesForSection0.remove(at: (atIndexPath as NSIndexPath).item)
106 | }else {
107 | photo = imagesForSection1.remove(at: (atIndexPath as NSIndexPath).item)
108 | }
109 |
110 | if (toIndexPath as NSIndexPath).section == 0 {
111 | imagesForSection0.insert(photo, at: (toIndexPath as NSIndexPath).item)
112 | }else {
113 | imagesForSection1.insert(photo, at: (toIndexPath as NSIndexPath).item)
114 | }
115 | }
116 |
117 | func scrollTrigerEdgeInsetsInCollectionView(_ collectionView: UICollectionView) -> UIEdgeInsets {
118 | return UIEdgeInsetsMake(100.0, 100.0, 100.0, 100.0)
119 | }
120 |
121 | func collectionView(_ collectionView: UICollectionView, reorderingItemAlphaInSection section: Int) -> CGFloat {
122 | if section == 0 {
123 | return 0
124 | }else {
125 | return 0.3
126 | }
127 | }
128 |
129 | func scrollTrigerPaddingInCollectionView(_ collectionView: UICollectionView) -> UIEdgeInsets {
130 | return UIEdgeInsetsMake(collectionView.contentInset.top, 0, collectionView.contentInset.bottom, 0)
131 | }
132 | }
133 |
134 | class RACollectionViewCell: UICollectionViewCell {
135 | var imageView: UIImageView!
136 | var gradientLayer: CAGradientLayer?
137 | var hilightedCover: UIView!
138 | override var isHighlighted: Bool {
139 | didSet {
140 | hilightedCover.isHidden = !isHighlighted
141 | }
142 | }
143 |
144 | required init?(coder aDecoder: NSCoder) {
145 | super.init(coder: aDecoder)
146 | configure()
147 | }
148 |
149 | override func layoutSubviews() {
150 | super.layoutSubviews()
151 | imageView.frame = bounds
152 | hilightedCover.frame = bounds
153 | applyGradation(imageView)
154 | }
155 |
156 | private func configure() {
157 | imageView = UIImageView()
158 | imageView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
159 | imageView.contentMode = UIViewContentMode.scaleAspectFill
160 | addSubview(imageView)
161 |
162 | hilightedCover = UIView()
163 | hilightedCover.autoresizingMask = [.flexibleWidth, .flexibleHeight]
164 | hilightedCover.backgroundColor = UIColor(white: 0, alpha: 0.5)
165 | hilightedCover.isHidden = true
166 | addSubview(hilightedCover)
167 | }
168 |
169 | private func applyGradation(_ gradientView: UIView!) {
170 | gradientLayer?.removeFromSuperlayer()
171 | gradientLayer = nil
172 |
173 | gradientLayer = CAGradientLayer()
174 | gradientLayer!.frame = gradientView.bounds
175 |
176 | let mainColor = UIColor(white: 0, alpha: 0.3).cgColor
177 | let subColor = UIColor.clear.cgColor
178 | gradientLayer!.colors = [subColor, mainColor]
179 | gradientLayer!.locations = [0, 1]
180 |
181 | gradientView.layer.addSublayer(gradientLayer!)
182 | }
183 | }
184 |
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/HorizontalViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HorizontalViewController.swift
3 | // RAReorderableLayout-Demo
4 | //
5 | // Created by Ryo Aoyama on 11/17/14.
6 | // Copyright (c) 2014 Ryo Aoyama. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 |
12 | class HorizontalViewController: UIViewController, RAReorderableLayoutDelegate, RAReorderableLayoutDataSource {
13 | @IBOutlet weak var collectionView: UICollectionView!
14 | @IBOutlet weak var gradientView: UIView!
15 | private var gradientLayer: CAGradientLayer?
16 | private var books: [Book] = []
17 |
18 | override func viewDidLoad() {
19 | super.viewDidLoad()
20 | title = "RAReorderableLayout"
21 | collectionView.register(BookCell.self, forCellWithReuseIdentifier: "horizontalCell")
22 | collectionView.delegate = self
23 | collectionView.dataSource = self
24 | (collectionView.collectionViewLayout as! RAReorderableLayout).scrollDirection = .horizontal
25 | applyGradation()
26 |
27 | let aScalars = "A".unicodeScalars
28 | let zScalars = "Z".unicodeScalars
29 | let aAsciiCode = aScalars[aScalars.startIndex].value
30 | let zAsciiCode = zScalars[zScalars.startIndex].value
31 | books = (aAsciiCode...zAsciiCode)
32 | .flatMap(UnicodeScalar.init)
33 | .map(Character.init)
34 | .enumerated()
35 | .map {
36 | let title = "Book \(String($1))"
37 | let color = UIColor(hue: 255.0 / 26.0 * CGFloat($0) / 255.0, saturation: 1.0, brightness: 0.9, alpha: 1.0)
38 | return .init(title: title, color: color)
39 | }
40 | }
41 |
42 | override func viewDidLayoutSubviews() {
43 | super.viewDidLayoutSubviews()
44 | gradientLayer?.frame = gradientView.bounds
45 | }
46 |
47 | private func applyGradation() {
48 | gradientLayer = CAGradientLayer()
49 | gradientLayer!.frame = gradientView.bounds
50 | let mainColor = UIColor(white: 0, alpha: 0.3).cgColor
51 | let subColor = UIColor.clear.cgColor
52 | gradientLayer!.colors = [subColor, mainColor]
53 | gradientLayer!.locations = [0, 1]
54 | gradientView.layer.insertSublayer(gradientLayer!, at: 0)
55 | }
56 |
57 | // collectionView delegate datasource
58 |
59 | func numberOfSections(in collectionView: UICollectionView) -> Int {
60 | return 1
61 | }
62 |
63 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
64 | return books.count
65 | }
66 |
67 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
68 | return CGSize(width: 130.0, height: 170.0)
69 | }
70 |
71 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
72 | return UIEdgeInsetsMake(0, 20.0, 0, 20.0)
73 | }
74 |
75 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
76 | return 20.0
77 | }
78 |
79 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
80 | var cell: BookCell
81 | cell = collectionView.dequeueReusableCell(withReuseIdentifier: "horizontalCell", for: indexPath) as! BookCell
82 | cell.book = books[(indexPath as NSIndexPath).item]
83 | return cell
84 | }
85 |
86 | func collectionView(_ collectionView: UICollectionView, at: IndexPath, willMoveTo toIndexPath: IndexPath) {
87 |
88 | }
89 |
90 | func collectionView(_ collectionView: UICollectionView, at: IndexPath, didMoveTo toIndexPath: IndexPath) {
91 | let book = books.remove(at: (toIndexPath as NSIndexPath).item)
92 | books.insert(book, at: (toIndexPath as NSIndexPath).item)
93 | }
94 |
95 | func scrollTrigerEdgeInsetsInCollectionView(_ collectionView: UICollectionView) -> UIEdgeInsets {
96 | return UIEdgeInsetsMake(0, 50, 0, 50)
97 | }
98 |
99 | func scrollSpeedValueInCollectionView(_ collectionView: UICollectionView) -> CGFloat {
100 | return 15.0
101 | }
102 | }
103 |
104 | class BookCell: UICollectionViewCell {
105 | private var backCoverView: UIView!
106 | private var pagesView: UIView!
107 | private var frontCoverView: UIView!
108 | private var bindingView: UIView!
109 | private var titleLabel: UILabel!
110 | var book: Book? {
111 | didSet {
112 | titleLabel.text = book?.title
113 | color = book?.color
114 | }
115 | }
116 | var color: UIColor? {
117 | didSet {
118 | backCoverView.backgroundColor = getDarkColor(color, minusValue: 20.0)
119 | frontCoverView.backgroundColor = color
120 | bindingView.backgroundColor = getDarkColor(color, minusValue: 50.0)
121 | }
122 | }
123 |
124 | required init?(coder aDecoder: NSCoder) {
125 | super.init(coder: aDecoder)
126 | }
127 |
128 | override init(frame: CGRect) {
129 | super.init(frame: frame)
130 | configure()
131 | }
132 |
133 | override func prepareForReuse() {
134 | super.prepareForReuse()
135 | titleLabel.text = nil
136 | }
137 |
138 | private func configure() {
139 | backCoverView = UIView(frame: bounds)
140 | backCoverView.backgroundColor = getDarkColor(UIColor.red, minusValue: 20.0)
141 | backCoverView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
142 |
143 | pagesView = UIView(frame: CGRect(x: 15.0, y: 0, width: bounds.width - 25.0, height: bounds.height - 5.0))
144 | pagesView.backgroundColor = UIColor.white
145 | pagesView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
146 |
147 | frontCoverView = UIView(frame: CGRect(x: 0, y: 0, width: bounds.width, height: bounds.height - 10.0))
148 | frontCoverView.backgroundColor = UIColor.red
149 | frontCoverView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
150 |
151 | bindingView = UIView(frame: CGRect(x: 0, y: 0, width: 15.0, height: bounds.height))
152 | bindingView.backgroundColor = getDarkColor(backCoverView?.backgroundColor, minusValue: 50.0)
153 | bindingView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
154 | bindingView.layer.borderWidth = 1.0
155 | bindingView.layer.borderColor = UIColor.black.cgColor
156 |
157 | titleLabel = UILabel(frame: CGRect(x: 15.0, y: 30.0, width: bounds.width - 16.0, height: 30.0))
158 | titleLabel.backgroundColor = UIColor(white: 1.0, alpha: 0.8)
159 | titleLabel.textColor = UIColor.black
160 | titleLabel.textAlignment = .center
161 | titleLabel.font = UIFont.boldSystemFont(ofSize: 20.0)
162 |
163 | contentView.addSubview(backCoverView)
164 | contentView.addSubview(pagesView)
165 | contentView.addSubview(frontCoverView)
166 | contentView.addSubview(bindingView)
167 | contentView.addSubview(titleLabel)
168 |
169 | let backPath = UIBezierPath(roundedRect: backCoverView!.bounds, byRoundingCorners: [.topRight, .bottomRight], cornerRadii: CGSize(width: 10.0, height: 10.0))
170 | let backMask = CAShapeLayer()
171 | backMask.frame = backCoverView!.bounds
172 | backMask.path = backPath.cgPath
173 | let backLineLayer = CAShapeLayer()
174 | backLineLayer.frame = backCoverView!.bounds
175 | backLineLayer.path = backPath.cgPath
176 | backLineLayer.strokeColor = UIColor.black.cgColor
177 | backLineLayer.fillColor = UIColor.clear.cgColor
178 | backLineLayer.lineWidth = 2.0
179 | backCoverView!.layer.mask = backMask
180 | backCoverView!.layer.insertSublayer(backLineLayer, at: 0)
181 |
182 | let frontPath = UIBezierPath(roundedRect: frontCoverView!.bounds, byRoundingCorners: [.topRight, .bottomRight], cornerRadii: CGSize(width: 10.0, height: 10.0))
183 | let frontMask = CAShapeLayer()
184 | frontMask.frame = frontCoverView!.bounds
185 | frontMask.path = frontPath.cgPath
186 | let frontLineLayer = CAShapeLayer()
187 | frontLineLayer.path = frontPath.cgPath
188 | frontLineLayer.strokeColor = UIColor.black.cgColor
189 | frontLineLayer.fillColor = UIColor.clear.cgColor
190 | frontLineLayer.lineWidth = 2.0
191 | frontCoverView!.layer.mask = frontMask
192 | frontCoverView!.layer.insertSublayer(frontLineLayer, at: 0)
193 | }
194 |
195 | private func getDarkColor(_ color: UIColor?, minusValue: CGFloat) -> UIColor? {
196 | if color == nil {
197 | return nil
198 | }
199 | var r: CGFloat = 0
200 | var g: CGFloat = 0
201 | var b: CGFloat = 0
202 | var a: CGFloat = 0
203 | color!.getRed(&r, green: &g, blue: &b, alpha: &a)
204 | r -= max(minusValue / 255.0, 0)
205 | g -= max(minusValue / 255.0, 0)
206 | b -= max(minusValue / 255.0, 0)
207 | return UIColor(red: r, green: g, blue: b, alpha: a)
208 | }
209 | }
210 |
211 | class Book: NSObject {
212 | var title: String?
213 | var color: UIColor?
214 |
215 | init(title: String?, color: UIColor) {
216 | super.init()
217 | self.title = title
218 | self.color = color
219 | }
220 | }
221 |
--------------------------------------------------------------------------------
/RAReorderableLayout.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | DFF5E7531B8F05CE003726B0 /* RAReorderableLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = DFF5E7521B8F05CE003726B0 /* RAReorderableLayout.h */; settings = {ATTRIBUTES = (Public, ); }; };
11 | DFF5E75B1B8F061B003726B0 /* RAReorderableLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFF5E75A1B8F061B003726B0 /* RAReorderableLayout.swift */; };
12 | /* End PBXBuildFile section */
13 |
14 | /* Begin PBXFileReference section */
15 | DFF5E74F1B8F05CE003726B0 /* RAReorderableLayout.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RAReorderableLayout.framework; sourceTree = BUILT_PRODUCTS_DIR; };
16 | DFF5E7521B8F05CE003726B0 /* RAReorderableLayout.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RAReorderableLayout.h; sourceTree = ""; };
17 | DFF5E7541B8F05CE003726B0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
18 | DFF5E75A1B8F061B003726B0 /* RAReorderableLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RAReorderableLayout.swift; sourceTree = ""; };
19 | /* End PBXFileReference section */
20 |
21 | /* Begin PBXFrameworksBuildPhase section */
22 | DFF5E74B1B8F05CE003726B0 /* Frameworks */ = {
23 | isa = PBXFrameworksBuildPhase;
24 | buildActionMask = 2147483647;
25 | files = (
26 | );
27 | runOnlyForDeploymentPostprocessing = 0;
28 | };
29 | /* End PBXFrameworksBuildPhase section */
30 |
31 | /* Begin PBXGroup section */
32 | DFF5E7451B8F05CE003726B0 = {
33 | isa = PBXGroup;
34 | children = (
35 | DFF5E7511B8F05CE003726B0 /* RAReorderableLayout */,
36 | DFF5E7501B8F05CE003726B0 /* Products */,
37 | );
38 | sourceTree = "";
39 | };
40 | DFF5E7501B8F05CE003726B0 /* Products */ = {
41 | isa = PBXGroup;
42 | children = (
43 | DFF5E74F1B8F05CE003726B0 /* RAReorderableLayout.framework */,
44 | );
45 | name = Products;
46 | sourceTree = "";
47 | };
48 | DFF5E7511B8F05CE003726B0 /* RAReorderableLayout */ = {
49 | isa = PBXGroup;
50 | children = (
51 | DFF5E7521B8F05CE003726B0 /* RAReorderableLayout.h */,
52 | DFF5E75A1B8F061B003726B0 /* RAReorderableLayout.swift */,
53 | DFF5E7541B8F05CE003726B0 /* Info.plist */,
54 | );
55 | path = RAReorderableLayout;
56 | sourceTree = "";
57 | };
58 | /* End PBXGroup section */
59 |
60 | /* Begin PBXHeadersBuildPhase section */
61 | DFF5E74C1B8F05CE003726B0 /* Headers */ = {
62 | isa = PBXHeadersBuildPhase;
63 | buildActionMask = 2147483647;
64 | files = (
65 | DFF5E7531B8F05CE003726B0 /* RAReorderableLayout.h in Headers */,
66 | );
67 | runOnlyForDeploymentPostprocessing = 0;
68 | };
69 | /* End PBXHeadersBuildPhase section */
70 |
71 | /* Begin PBXNativeTarget section */
72 | DFF5E74E1B8F05CE003726B0 /* RAReorderableLayout */ = {
73 | isa = PBXNativeTarget;
74 | buildConfigurationList = DFF5E7571B8F05CE003726B0 /* Build configuration list for PBXNativeTarget "RAReorderableLayout" */;
75 | buildPhases = (
76 | DFF5E74A1B8F05CE003726B0 /* Sources */,
77 | DFF5E74B1B8F05CE003726B0 /* Frameworks */,
78 | DFF5E74C1B8F05CE003726B0 /* Headers */,
79 | DFF5E74D1B8F05CE003726B0 /* Resources */,
80 | );
81 | buildRules = (
82 | );
83 | dependencies = (
84 | );
85 | name = RAReorderableLayout;
86 | productName = RAReorderableLayout;
87 | productReference = DFF5E74F1B8F05CE003726B0 /* RAReorderableLayout.framework */;
88 | productType = "com.apple.product-type.framework";
89 | };
90 | /* End PBXNativeTarget section */
91 |
92 | /* Begin PBXProject section */
93 | DFF5E7461B8F05CE003726B0 /* Project object */ = {
94 | isa = PBXProject;
95 | attributes = {
96 | LastSwiftUpdateCheck = 0700;
97 | LastUpgradeCheck = 0800;
98 | ORGANIZATIONNAME = "Yowoo Technology Inc.";
99 | TargetAttributes = {
100 | DFF5E74E1B8F05CE003726B0 = {
101 | CreatedOnToolsVersion = 7.0;
102 | LastSwiftMigration = 0800;
103 | };
104 | };
105 | };
106 | buildConfigurationList = DFF5E7491B8F05CE003726B0 /* Build configuration list for PBXProject "RAReorderableLayout" */;
107 | compatibilityVersion = "Xcode 3.2";
108 | developmentRegion = English;
109 | hasScannedForEncodings = 0;
110 | knownRegions = (
111 | en,
112 | );
113 | mainGroup = DFF5E7451B8F05CE003726B0;
114 | productRefGroup = DFF5E7501B8F05CE003726B0 /* Products */;
115 | projectDirPath = "";
116 | projectRoot = "";
117 | targets = (
118 | DFF5E74E1B8F05CE003726B0 /* RAReorderableLayout */,
119 | );
120 | };
121 | /* End PBXProject section */
122 |
123 | /* Begin PBXResourcesBuildPhase section */
124 | DFF5E74D1B8F05CE003726B0 /* Resources */ = {
125 | isa = PBXResourcesBuildPhase;
126 | buildActionMask = 2147483647;
127 | files = (
128 | );
129 | runOnlyForDeploymentPostprocessing = 0;
130 | };
131 | /* End PBXResourcesBuildPhase section */
132 |
133 | /* Begin PBXSourcesBuildPhase section */
134 | DFF5E74A1B8F05CE003726B0 /* Sources */ = {
135 | isa = PBXSourcesBuildPhase;
136 | buildActionMask = 2147483647;
137 | files = (
138 | DFF5E75B1B8F061B003726B0 /* RAReorderableLayout.swift in Sources */,
139 | );
140 | runOnlyForDeploymentPostprocessing = 0;
141 | };
142 | /* End PBXSourcesBuildPhase section */
143 |
144 | /* Begin XCBuildConfiguration section */
145 | DFF5E7551B8F05CE003726B0 /* Debug */ = {
146 | isa = XCBuildConfiguration;
147 | buildSettings = {
148 | ALWAYS_SEARCH_USER_PATHS = NO;
149 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
150 | CLANG_CXX_LIBRARY = "libc++";
151 | CLANG_ENABLE_MODULES = YES;
152 | CLANG_ENABLE_OBJC_ARC = YES;
153 | CLANG_WARN_BOOL_CONVERSION = YES;
154 | CLANG_WARN_CONSTANT_CONVERSION = YES;
155 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
156 | CLANG_WARN_EMPTY_BODY = YES;
157 | CLANG_WARN_ENUM_CONVERSION = YES;
158 | CLANG_WARN_INT_CONVERSION = YES;
159 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
160 | CLANG_WARN_UNREACHABLE_CODE = YES;
161 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
162 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
163 | COPY_PHASE_STRIP = NO;
164 | CURRENT_PROJECT_VERSION = 1;
165 | DEBUG_INFORMATION_FORMAT = dwarf;
166 | ENABLE_STRICT_OBJC_MSGSEND = YES;
167 | ENABLE_TESTABILITY = YES;
168 | GCC_C_LANGUAGE_STANDARD = gnu99;
169 | GCC_DYNAMIC_NO_PIC = NO;
170 | GCC_NO_COMMON_BLOCKS = YES;
171 | GCC_OPTIMIZATION_LEVEL = 0;
172 | GCC_PREPROCESSOR_DEFINITIONS = (
173 | "DEBUG=1",
174 | "$(inherited)",
175 | );
176 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
177 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
178 | GCC_WARN_UNDECLARED_SELECTOR = YES;
179 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
180 | GCC_WARN_UNUSED_FUNCTION = YES;
181 | GCC_WARN_UNUSED_VARIABLE = YES;
182 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
183 | MTL_ENABLE_DEBUG_INFO = YES;
184 | ONLY_ACTIVE_ARCH = YES;
185 | SDKROOT = iphoneos;
186 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
187 | TARGETED_DEVICE_FAMILY = "1,2";
188 | VERSIONING_SYSTEM = "apple-generic";
189 | VERSION_INFO_PREFIX = "";
190 | };
191 | name = Debug;
192 | };
193 | DFF5E7561B8F05CE003726B0 /* Release */ = {
194 | isa = XCBuildConfiguration;
195 | buildSettings = {
196 | ALWAYS_SEARCH_USER_PATHS = NO;
197 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
198 | CLANG_CXX_LIBRARY = "libc++";
199 | CLANG_ENABLE_MODULES = YES;
200 | CLANG_ENABLE_OBJC_ARC = YES;
201 | CLANG_WARN_BOOL_CONVERSION = YES;
202 | CLANG_WARN_CONSTANT_CONVERSION = YES;
203 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
204 | CLANG_WARN_EMPTY_BODY = YES;
205 | CLANG_WARN_ENUM_CONVERSION = YES;
206 | CLANG_WARN_INT_CONVERSION = YES;
207 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
208 | CLANG_WARN_UNREACHABLE_CODE = YES;
209 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
210 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
211 | COPY_PHASE_STRIP = NO;
212 | CURRENT_PROJECT_VERSION = 1;
213 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
214 | ENABLE_NS_ASSERTIONS = NO;
215 | ENABLE_STRICT_OBJC_MSGSEND = YES;
216 | GCC_C_LANGUAGE_STANDARD = gnu99;
217 | GCC_NO_COMMON_BLOCKS = YES;
218 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
219 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
220 | GCC_WARN_UNDECLARED_SELECTOR = YES;
221 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
222 | GCC_WARN_UNUSED_FUNCTION = YES;
223 | GCC_WARN_UNUSED_VARIABLE = YES;
224 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
225 | MTL_ENABLE_DEBUG_INFO = NO;
226 | SDKROOT = iphoneos;
227 | TARGETED_DEVICE_FAMILY = "1,2";
228 | VALIDATE_PRODUCT = YES;
229 | VERSIONING_SYSTEM = "apple-generic";
230 | VERSION_INFO_PREFIX = "";
231 | };
232 | name = Release;
233 | };
234 | DFF5E7581B8F05CE003726B0 /* Debug */ = {
235 | isa = XCBuildConfiguration;
236 | buildSettings = {
237 | CLANG_ENABLE_MODULES = YES;
238 | DEFINES_MODULE = YES;
239 | DYLIB_COMPATIBILITY_VERSION = 1;
240 | DYLIB_CURRENT_VERSION = 1;
241 | DYLIB_INSTALL_NAME_BASE = "@rpath";
242 | INFOPLIST_FILE = RAReorderableLayout/Info.plist;
243 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
244 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
245 | PRODUCT_BUNDLE_IDENTIFIER = "com.yo-woo.RAReorderableLayout";
246 | PRODUCT_NAME = "$(TARGET_NAME)";
247 | SKIP_INSTALL = YES;
248 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
249 | SWIFT_VERSION = 3.0;
250 | };
251 | name = Debug;
252 | };
253 | DFF5E7591B8F05CE003726B0 /* Release */ = {
254 | isa = XCBuildConfiguration;
255 | buildSettings = {
256 | CLANG_ENABLE_MODULES = YES;
257 | DEFINES_MODULE = YES;
258 | DYLIB_COMPATIBILITY_VERSION = 1;
259 | DYLIB_CURRENT_VERSION = 1;
260 | DYLIB_INSTALL_NAME_BASE = "@rpath";
261 | INFOPLIST_FILE = RAReorderableLayout/Info.plist;
262 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
263 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
264 | PRODUCT_BUNDLE_IDENTIFIER = "com.yo-woo.RAReorderableLayout";
265 | PRODUCT_NAME = "$(TARGET_NAME)";
266 | SKIP_INSTALL = YES;
267 | SWIFT_VERSION = 3.0;
268 | };
269 | name = Release;
270 | };
271 | /* End XCBuildConfiguration section */
272 |
273 | /* Begin XCConfigurationList section */
274 | DFF5E7491B8F05CE003726B0 /* Build configuration list for PBXProject "RAReorderableLayout" */ = {
275 | isa = XCConfigurationList;
276 | buildConfigurations = (
277 | DFF5E7551B8F05CE003726B0 /* Debug */,
278 | DFF5E7561B8F05CE003726B0 /* Release */,
279 | );
280 | defaultConfigurationIsVisible = 0;
281 | defaultConfigurationName = Release;
282 | };
283 | DFF5E7571B8F05CE003726B0 /* Build configuration list for PBXNativeTarget "RAReorderableLayout" */ = {
284 | isa = XCConfigurationList;
285 | buildConfigurations = (
286 | DFF5E7581B8F05CE003726B0 /* Debug */,
287 | DFF5E7591B8F05CE003726B0 /* Release */,
288 | );
289 | defaultConfigurationIsVisible = 0;
290 | defaultConfigurationName = Release;
291 | };
292 | /* End XCConfigurationList section */
293 | };
294 | rootObject = DFF5E7461B8F05CE003726B0 /* Project object */;
295 | }
296 |
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 2A972DBE1A195D940084B0D5 /* VerticalViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A972DBD1A195D930084B0D5 /* VerticalViewController.swift */; };
11 | 2A972DC01A195F0C0084B0D5 /* HorizontalViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A972DBF1A195F0C0084B0D5 /* HorizontalViewController.swift */; };
12 | 2A972DC21A1961BF0084B0D5 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2A972DC11A1961BF0084B0D5 /* Main.storyboard */; };
13 | 2AF54EDC1A002CD1007A7144 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AF54EDB1A002CD1007A7144 /* AppDelegate.swift */; };
14 | 2AF54EDF1A002CD1007A7144 /* RAReorderableLayout_Demo.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 2AF54EDD1A002CD1007A7144 /* RAReorderableLayout_Demo.xcdatamodeld */; };
15 | 2AF54EE11A002CD1007A7144 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AF54EE01A002CD1007A7144 /* ViewController.swift */; };
16 | 2AF54EE61A002CD1007A7144 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2AF54EE51A002CD1007A7144 /* Images.xcassets */; };
17 | 2AF54F031A002D2B007A7144 /* RAReorderableLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AF54F021A002D2B007A7144 /* RAReorderableLayout.swift */; };
18 | /* End PBXBuildFile section */
19 |
20 | /* Begin PBXFileReference section */
21 | 2A972DBD1A195D930084B0D5 /* VerticalViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = VerticalViewController.swift; sourceTree = ""; tabWidth = 4; };
22 | 2A972DBF1A195F0C0084B0D5 /* HorizontalViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = HorizontalViewController.swift; sourceTree = ""; tabWidth = 4; };
23 | 2A972DC11A1961BF0084B0D5 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; };
24 | 2AF54ED61A002CD1007A7144 /* RAReorderableLayout-Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "RAReorderableLayout-Demo.app"; sourceTree = BUILT_PRODUCTS_DIR; };
25 | 2AF54EDA1A002CD1007A7144 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
26 | 2AF54EDB1A002CD1007A7144 /* AppDelegate.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; tabWidth = 4; };
27 | 2AF54EDE1A002CD1007A7144 /* RAReorderableLayout_Demo.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = RAReorderableLayout_Demo.xcdatamodel; sourceTree = ""; };
28 | 2AF54EE01A002CD1007A7144 /* ViewController.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; tabWidth = 4; };
29 | 2AF54EE51A002CD1007A7144 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
30 | 2AF54EE81A002CD1007A7144 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; };
31 | 2AF54EF31A002CD1007A7144 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
32 | 2AF54EF41A002CD1007A7144 /* RAReorderableLayout_DemoTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RAReorderableLayout_DemoTests.swift; sourceTree = ""; };
33 | 2AF54F021A002D2B007A7144 /* RAReorderableLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RAReorderableLayout.swift; sourceTree = ""; };
34 | /* End PBXFileReference section */
35 |
36 | /* Begin PBXFrameworksBuildPhase section */
37 | 2AF54ED31A002CD1007A7144 /* Frameworks */ = {
38 | isa = PBXFrameworksBuildPhase;
39 | buildActionMask = 2147483647;
40 | files = (
41 | );
42 | runOnlyForDeploymentPostprocessing = 0;
43 | };
44 | /* End PBXFrameworksBuildPhase section */
45 |
46 | /* Begin PBXGroup section */
47 | 2AF54ECD1A002CD1007A7144 = {
48 | isa = PBXGroup;
49 | children = (
50 | 2AF54F011A002D2B007A7144 /* RAReorderableLayout */,
51 | 2AF54ED81A002CD1007A7144 /* RAReorderableLayout-Demo */,
52 | 2AF54EF11A002CD1007A7144 /* RAReorderableLayout-DemoTests */,
53 | 2AF54ED71A002CD1007A7144 /* Products */,
54 | );
55 | sourceTree = "";
56 | };
57 | 2AF54ED71A002CD1007A7144 /* Products */ = {
58 | isa = PBXGroup;
59 | children = (
60 | 2AF54ED61A002CD1007A7144 /* RAReorderableLayout-Demo.app */,
61 | );
62 | name = Products;
63 | sourceTree = "";
64 | };
65 | 2AF54ED81A002CD1007A7144 /* RAReorderableLayout-Demo */ = {
66 | isa = PBXGroup;
67 | children = (
68 | 2AF54EDB1A002CD1007A7144 /* AppDelegate.swift */,
69 | 2AF54EE01A002CD1007A7144 /* ViewController.swift */,
70 | 2A972DBD1A195D930084B0D5 /* VerticalViewController.swift */,
71 | 2A972DBF1A195F0C0084B0D5 /* HorizontalViewController.swift */,
72 | 2A972DC11A1961BF0084B0D5 /* Main.storyboard */,
73 | 2AF54EE51A002CD1007A7144 /* Images.xcassets */,
74 | 2AF54EE71A002CD1007A7144 /* LaunchScreen.xib */,
75 | 2AF54EDD1A002CD1007A7144 /* RAReorderableLayout_Demo.xcdatamodeld */,
76 | 2AF54ED91A002CD1007A7144 /* Supporting Files */,
77 | );
78 | path = "RAReorderableLayout-Demo";
79 | sourceTree = "";
80 | };
81 | 2AF54ED91A002CD1007A7144 /* Supporting Files */ = {
82 | isa = PBXGroup;
83 | children = (
84 | 2AF54EDA1A002CD1007A7144 /* Info.plist */,
85 | );
86 | name = "Supporting Files";
87 | sourceTree = "";
88 | };
89 | 2AF54EF11A002CD1007A7144 /* RAReorderableLayout-DemoTests */ = {
90 | isa = PBXGroup;
91 | children = (
92 | 2AF54EF41A002CD1007A7144 /* RAReorderableLayout_DemoTests.swift */,
93 | 2AF54EF21A002CD1007A7144 /* Supporting Files */,
94 | );
95 | path = "RAReorderableLayout-DemoTests";
96 | sourceTree = "";
97 | };
98 | 2AF54EF21A002CD1007A7144 /* Supporting Files */ = {
99 | isa = PBXGroup;
100 | children = (
101 | 2AF54EF31A002CD1007A7144 /* Info.plist */,
102 | );
103 | name = "Supporting Files";
104 | sourceTree = "";
105 | };
106 | 2AF54F011A002D2B007A7144 /* RAReorderableLayout */ = {
107 | isa = PBXGroup;
108 | children = (
109 | 2AF54F021A002D2B007A7144 /* RAReorderableLayout.swift */,
110 | );
111 | name = RAReorderableLayout;
112 | path = ../RAReorderableLayout;
113 | sourceTree = "";
114 | };
115 | /* End PBXGroup section */
116 |
117 | /* Begin PBXNativeTarget section */
118 | 2AF54ED51A002CD1007A7144 /* RAReorderableLayout-Demo */ = {
119 | isa = PBXNativeTarget;
120 | buildConfigurationList = 2AF54EF81A002CD1007A7144 /* Build configuration list for PBXNativeTarget "RAReorderableLayout-Demo" */;
121 | buildPhases = (
122 | 2AF54ED21A002CD1007A7144 /* Sources */,
123 | 2AF54ED31A002CD1007A7144 /* Frameworks */,
124 | 2AF54ED41A002CD1007A7144 /* Resources */,
125 | );
126 | buildRules = (
127 | );
128 | dependencies = (
129 | );
130 | name = "RAReorderableLayout-Demo";
131 | productName = "RAReorderableLayout-Demo";
132 | productReference = 2AF54ED61A002CD1007A7144 /* RAReorderableLayout-Demo.app */;
133 | productType = "com.apple.product-type.application";
134 | };
135 | /* End PBXNativeTarget section */
136 |
137 | /* Begin PBXProject section */
138 | 2AF54ECE1A002CD1007A7144 /* Project object */ = {
139 | isa = PBXProject;
140 | attributes = {
141 | LastSwiftUpdateCheck = 0730;
142 | LastUpgradeCheck = 0800;
143 | ORGANIZATIONNAME = "Ryo Aoyama";
144 | TargetAttributes = {
145 | 2AF54ED51A002CD1007A7144 = {
146 | CreatedOnToolsVersion = 6.1;
147 | LastSwiftMigration = 0800;
148 | };
149 | };
150 | };
151 | buildConfigurationList = 2AF54ED11A002CD1007A7144 /* Build configuration list for PBXProject "RAReorderableLayout-Demo" */;
152 | compatibilityVersion = "Xcode 3.2";
153 | developmentRegion = English;
154 | hasScannedForEncodings = 0;
155 | knownRegions = (
156 | en,
157 | Base,
158 | );
159 | mainGroup = 2AF54ECD1A002CD1007A7144;
160 | productRefGroup = 2AF54ED71A002CD1007A7144 /* Products */;
161 | projectDirPath = "";
162 | projectRoot = "";
163 | targets = (
164 | 2AF54ED51A002CD1007A7144 /* RAReorderableLayout-Demo */,
165 | );
166 | };
167 | /* End PBXProject section */
168 |
169 | /* Begin PBXResourcesBuildPhase section */
170 | 2AF54ED41A002CD1007A7144 /* Resources */ = {
171 | isa = PBXResourcesBuildPhase;
172 | buildActionMask = 2147483647;
173 | files = (
174 | 2AF54EE61A002CD1007A7144 /* Images.xcassets in Resources */,
175 | 2A972DC21A1961BF0084B0D5 /* Main.storyboard in Resources */,
176 | );
177 | runOnlyForDeploymentPostprocessing = 0;
178 | };
179 | /* End PBXResourcesBuildPhase section */
180 |
181 | /* Begin PBXSourcesBuildPhase section */
182 | 2AF54ED21A002CD1007A7144 /* Sources */ = {
183 | isa = PBXSourcesBuildPhase;
184 | buildActionMask = 2147483647;
185 | files = (
186 | 2AF54F031A002D2B007A7144 /* RAReorderableLayout.swift in Sources */,
187 | 2A972DBE1A195D940084B0D5 /* VerticalViewController.swift in Sources */,
188 | 2AF54EE11A002CD1007A7144 /* ViewController.swift in Sources */,
189 | 2AF54EDC1A002CD1007A7144 /* AppDelegate.swift in Sources */,
190 | 2A972DC01A195F0C0084B0D5 /* HorizontalViewController.swift in Sources */,
191 | 2AF54EDF1A002CD1007A7144 /* RAReorderableLayout_Demo.xcdatamodeld in Sources */,
192 | );
193 | runOnlyForDeploymentPostprocessing = 0;
194 | };
195 | /* End PBXSourcesBuildPhase section */
196 |
197 | /* Begin PBXVariantGroup section */
198 | 2AF54EE71A002CD1007A7144 /* LaunchScreen.xib */ = {
199 | isa = PBXVariantGroup;
200 | children = (
201 | 2AF54EE81A002CD1007A7144 /* Base */,
202 | );
203 | name = LaunchScreen.xib;
204 | sourceTree = "";
205 | };
206 | /* End PBXVariantGroup section */
207 |
208 | /* Begin XCBuildConfiguration section */
209 | 2AF54EF61A002CD1007A7144 /* Debug */ = {
210 | isa = XCBuildConfiguration;
211 | buildSettings = {
212 | ALWAYS_SEARCH_USER_PATHS = NO;
213 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
214 | CLANG_CXX_LIBRARY = "libc++";
215 | CLANG_ENABLE_MODULES = YES;
216 | CLANG_ENABLE_OBJC_ARC = YES;
217 | CLANG_WARN_BOOL_CONVERSION = YES;
218 | CLANG_WARN_CONSTANT_CONVERSION = YES;
219 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
220 | CLANG_WARN_EMPTY_BODY = YES;
221 | CLANG_WARN_ENUM_CONVERSION = YES;
222 | CLANG_WARN_INT_CONVERSION = YES;
223 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
224 | CLANG_WARN_UNREACHABLE_CODE = YES;
225 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
226 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
227 | COPY_PHASE_STRIP = NO;
228 | ENABLE_STRICT_OBJC_MSGSEND = YES;
229 | ENABLE_TESTABILITY = YES;
230 | GCC_C_LANGUAGE_STANDARD = gnu99;
231 | GCC_DYNAMIC_NO_PIC = NO;
232 | GCC_NO_COMMON_BLOCKS = YES;
233 | GCC_OPTIMIZATION_LEVEL = 0;
234 | GCC_PREPROCESSOR_DEFINITIONS = (
235 | "DEBUG=1",
236 | "$(inherited)",
237 | );
238 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
239 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
240 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
241 | GCC_WARN_UNDECLARED_SELECTOR = YES;
242 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
243 | GCC_WARN_UNUSED_FUNCTION = YES;
244 | GCC_WARN_UNUSED_VARIABLE = YES;
245 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
246 | MTL_ENABLE_DEBUG_INFO = YES;
247 | ONLY_ACTIVE_ARCH = YES;
248 | SDKROOT = iphoneos;
249 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
250 | };
251 | name = Debug;
252 | };
253 | 2AF54EF71A002CD1007A7144 /* Release */ = {
254 | isa = XCBuildConfiguration;
255 | buildSettings = {
256 | ALWAYS_SEARCH_USER_PATHS = NO;
257 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
258 | CLANG_CXX_LIBRARY = "libc++";
259 | CLANG_ENABLE_MODULES = YES;
260 | CLANG_ENABLE_OBJC_ARC = YES;
261 | CLANG_WARN_BOOL_CONVERSION = YES;
262 | CLANG_WARN_CONSTANT_CONVERSION = YES;
263 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
264 | CLANG_WARN_EMPTY_BODY = YES;
265 | CLANG_WARN_ENUM_CONVERSION = YES;
266 | CLANG_WARN_INT_CONVERSION = YES;
267 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
268 | CLANG_WARN_UNREACHABLE_CODE = YES;
269 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
270 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
271 | COPY_PHASE_STRIP = YES;
272 | ENABLE_NS_ASSERTIONS = NO;
273 | ENABLE_STRICT_OBJC_MSGSEND = YES;
274 | GCC_C_LANGUAGE_STANDARD = gnu99;
275 | GCC_NO_COMMON_BLOCKS = YES;
276 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
277 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
278 | GCC_WARN_UNDECLARED_SELECTOR = YES;
279 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
280 | GCC_WARN_UNUSED_FUNCTION = YES;
281 | GCC_WARN_UNUSED_VARIABLE = YES;
282 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
283 | MTL_ENABLE_DEBUG_INFO = NO;
284 | SDKROOT = iphoneos;
285 | VALIDATE_PRODUCT = YES;
286 | };
287 | name = Release;
288 | };
289 | 2AF54EF91A002CD1007A7144 /* Debug */ = {
290 | isa = XCBuildConfiguration;
291 | buildSettings = {
292 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
293 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
294 | FRAMEWORK_SEARCH_PATHS = (
295 | "$(inherited)",
296 | "$(PROJECT_DIR)",
297 | );
298 | INFOPLIST_FILE = "RAReorderableLayout-Demo/Info.plist";
299 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
300 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
301 | LIBRARY_SEARCH_PATHS = (
302 | "$(inherited)",
303 | "$(PROJECT_DIR)",
304 | );
305 | PRODUCT_BUNDLE_IDENTIFIER = "com.ryo.$(PRODUCT_NAME:rfc1034identifier)";
306 | PRODUCT_NAME = "$(TARGET_NAME)";
307 | SWIFT_VERSION = 3.0;
308 | };
309 | name = Debug;
310 | };
311 | 2AF54EFA1A002CD1007A7144 /* Release */ = {
312 | isa = XCBuildConfiguration;
313 | buildSettings = {
314 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
315 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
316 | FRAMEWORK_SEARCH_PATHS = (
317 | "$(inherited)",
318 | "$(PROJECT_DIR)",
319 | );
320 | INFOPLIST_FILE = "RAReorderableLayout-Demo/Info.plist";
321 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
322 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
323 | LIBRARY_SEARCH_PATHS = (
324 | "$(inherited)",
325 | "$(PROJECT_DIR)",
326 | );
327 | PRODUCT_BUNDLE_IDENTIFIER = "com.ryo.$(PRODUCT_NAME:rfc1034identifier)";
328 | PRODUCT_NAME = "$(TARGET_NAME)";
329 | SWIFT_VERSION = 2.3;
330 | };
331 | name = Release;
332 | };
333 | /* End XCBuildConfiguration section */
334 |
335 | /* Begin XCConfigurationList section */
336 | 2AF54ED11A002CD1007A7144 /* Build configuration list for PBXProject "RAReorderableLayout-Demo" */ = {
337 | isa = XCConfigurationList;
338 | buildConfigurations = (
339 | 2AF54EF61A002CD1007A7144 /* Debug */,
340 | 2AF54EF71A002CD1007A7144 /* Release */,
341 | );
342 | defaultConfigurationIsVisible = 0;
343 | defaultConfigurationName = Release;
344 | };
345 | 2AF54EF81A002CD1007A7144 /* Build configuration list for PBXNativeTarget "RAReorderableLayout-Demo" */ = {
346 | isa = XCConfigurationList;
347 | buildConfigurations = (
348 | 2AF54EF91A002CD1007A7144 /* Debug */,
349 | 2AF54EFA1A002CD1007A7144 /* Release */,
350 | );
351 | defaultConfigurationIsVisible = 0;
352 | defaultConfigurationName = Release;
353 | };
354 | /* End XCConfigurationList section */
355 |
356 | /* Begin XCVersionGroup section */
357 | 2AF54EDD1A002CD1007A7144 /* RAReorderableLayout_Demo.xcdatamodeld */ = {
358 | isa = XCVersionGroup;
359 | children = (
360 | 2AF54EDE1A002CD1007A7144 /* RAReorderableLayout_Demo.xcdatamodel */,
361 | );
362 | currentVersion = 2AF54EDE1A002CD1007A7144 /* RAReorderableLayout_Demo.xcdatamodel */;
363 | path = RAReorderableLayout_Demo.xcdatamodeld;
364 | sourceTree = "";
365 | versionGroupType = wrapper.xcdatamodel;
366 | };
367 | /* End XCVersionGroup section */
368 | };
369 | rootObject = 2AF54ECE1A002CD1007A7144 /* Project object */;
370 | }
371 |
--------------------------------------------------------------------------------
/RAReorderableLayout/RAReorderableLayout.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RAReorderableLayout.swift
3 | // RAReorderableLayout
4 | //
5 | // Created by Ryo Aoyama on 10/12/14.
6 | // Copyright (c) 2014 Ryo Aoyama. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | public protocol RAReorderableLayoutDelegate: UICollectionViewDelegateFlowLayout {
12 | func collectionView(_ collectionView: UICollectionView, at: IndexPath, willMoveTo toIndexPath: IndexPath)
13 | func collectionView(_ collectionView: UICollectionView, at: IndexPath, didMoveTo toIndexPath: IndexPath)
14 | func collectionView(_ collectionView: UICollectionView, allowMoveAt indexPath: IndexPath) -> Bool
15 | func collectionView(_ collectionView: UICollectionView, at: IndexPath, canMoveTo: IndexPath) -> Bool
16 |
17 | func collectionView(_ collectionView: UICollectionView, collectionView layout: RAReorderableLayout, willBeginDraggingItemAt indexPath: IndexPath)
18 | func collectionView(_ collectionView: UICollectionView, collectionView layout: RAReorderableLayout, didBeginDraggingItemAt indexPath: IndexPath)
19 | func collectionView(_ collectionView: UICollectionView, collectionView layout: RAReorderableLayout, willEndDraggingItemTo indexPath: IndexPath)
20 | func collectionView(_ collectionView: UICollectionView, collectionView layout: RAReorderableLayout, didEndDraggingItemTo indexPath: IndexPath)
21 | }
22 |
23 | public protocol RAReorderableLayoutDataSource: UICollectionViewDataSource {
24 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
25 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
26 |
27 | func collectionView(_ collectionView: UICollectionView, reorderingItemAlphaInSection section: Int) -> CGFloat
28 | func scrollTrigerEdgeInsetsInCollectionView(_ collectionView: UICollectionView) -> UIEdgeInsets
29 | func scrollTrigerPaddingInCollectionView(_ collectionView: UICollectionView) -> UIEdgeInsets
30 | func scrollSpeedValueInCollectionView(_ collectionView: UICollectionView) -> CGFloat
31 | }
32 |
33 | public extension RAReorderableLayoutDataSource {
34 | func collectionView(_ collectionView: UICollectionView, reorderingItemAlphaInSection section: Int) -> CGFloat {
35 | return 0
36 | }
37 | func scrollTrigerEdgeInsetsInCollectionView(_ collectionView: UICollectionView) -> UIEdgeInsets {
38 | return .init(top: 100, left: 100, bottom: 100, right: 100)
39 | }
40 | func scrollTrigerPaddingInCollectionView(_ collectionView: UICollectionView) -> UIEdgeInsets {
41 | return .zero
42 | }
43 | func scrollSpeedValueInCollectionView(_ collectionView: UICollectionView) -> CGFloat {
44 | return 10
45 | }
46 | }
47 |
48 | public extension RAReorderableLayoutDelegate {
49 | func collectionView(_ collectionView: UICollectionView, at: IndexPath, willMoveTo toIndexPath: IndexPath) {}
50 | func collectionView(_ collectionView: UICollectionView, at: IndexPath, didMoveTo toIndexPath: IndexPath) {}
51 | func collectionView(_ collectionView: UICollectionView, allowMoveAt indexPath: IndexPath) -> Bool {
52 | return true
53 | }
54 | func collectionView(_ collectionView: UICollectionView, at: IndexPath, canMoveTo: IndexPath) -> Bool {
55 | return true
56 | }
57 |
58 | func collectionView(_ collectionView: UICollectionView, collectionView layout: RAReorderableLayout, willBeginDraggingItemAt indexPath: IndexPath) {}
59 | func collectionView(_ collectionView: UICollectionView, collectionView layout: RAReorderableLayout, didBeginDraggingItemAt indexPath: IndexPath) {}
60 | func collectionView(_ collectionView: UICollectionView, collectionView layout: RAReorderableLayout, willEndDraggingItemTo indexPath: IndexPath) {}
61 | func collectionView(_ collectionView: UICollectionView, collectionView layout: RAReorderableLayout, didEndDraggingItemTo indexPath: IndexPath) {}
62 | }
63 |
64 | open class RAReorderableLayout: UICollectionViewFlowLayout, UIGestureRecognizerDelegate {
65 |
66 | fileprivate enum direction {
67 | case toTop
68 | case toEnd
69 | case stay
70 |
71 | fileprivate func scrollValue(_ speedValue: CGFloat, percentage: CGFloat) -> CGFloat {
72 | var value: CGFloat = 0.0
73 | switch self {
74 | case .toTop:
75 | value = -speedValue
76 | case .toEnd:
77 | value = speedValue
78 | case .stay:
79 | return 0
80 | }
81 |
82 | let proofedPercentage: CGFloat = max(min(1.0, percentage), 0)
83 | return value * proofedPercentage
84 | }
85 | }
86 |
87 | public weak var delegate: RAReorderableLayoutDelegate? {
88 | get { return collectionView?.delegate as? RAReorderableLayoutDelegate }
89 | set { collectionView?.delegate = delegate }
90 | }
91 |
92 | public weak var dataSource: RAReorderableLayoutDataSource? {
93 | set { collectionView?.dataSource = dataSource }
94 | get { return collectionView?.dataSource as? RAReorderableLayoutDataSource }
95 | }
96 |
97 | fileprivate var displayLink: CADisplayLink?
98 |
99 | fileprivate var longPress: UILongPressGestureRecognizer?
100 |
101 | fileprivate var panGesture: UIPanGestureRecognizer?
102 |
103 | fileprivate var continuousScrollDirection: direction = .stay
104 |
105 | fileprivate var cellFakeView: RACellFakeView?
106 |
107 | fileprivate var panTranslation: CGPoint?
108 |
109 | fileprivate var fakeCellCenter: CGPoint?
110 |
111 | fileprivate var trigerInsets = UIEdgeInsetsMake(100.0, 100.0, 100.0, 100.0)
112 |
113 | fileprivate var trigerPadding = UIEdgeInsets.zero
114 |
115 | fileprivate var scrollSpeedValue: CGFloat = 10.0
116 |
117 | fileprivate var offsetFromTop: CGFloat {
118 | let contentOffset = collectionView!.contentOffset
119 | return scrollDirection == .vertical ? contentOffset.y : contentOffset.x
120 | }
121 |
122 | fileprivate var insetsTop: CGFloat {
123 | let contentInsets = collectionView!.contentInset
124 | return scrollDirection == .vertical ? contentInsets.top : contentInsets.left
125 | }
126 |
127 | fileprivate var insetsEnd: CGFloat {
128 | let contentInsets = collectionView!.contentInset
129 | return scrollDirection == .vertical ? contentInsets.bottom : contentInsets.right
130 | }
131 |
132 | fileprivate var contentLength: CGFloat {
133 | let contentSize = collectionView!.contentSize
134 | return scrollDirection == .vertical ? contentSize.height : contentSize.width
135 | }
136 |
137 | fileprivate var collectionViewLength: CGFloat {
138 | let collectionViewSize = collectionView!.bounds.size
139 | return scrollDirection == .vertical ? collectionViewSize.height : collectionViewSize.width
140 | }
141 |
142 | fileprivate var fakeCellTopEdge: CGFloat? {
143 | if let fakeCell = cellFakeView {
144 | return scrollDirection == .vertical ? fakeCell.frame.minY : fakeCell.frame.minX
145 | }
146 | return nil
147 | }
148 |
149 | fileprivate var fakeCellEndEdge: CGFloat? {
150 | if let fakeCell = cellFakeView {
151 | return scrollDirection == .vertical ? fakeCell.frame.maxY : fakeCell.frame.maxX
152 | }
153 | return nil
154 | }
155 |
156 | fileprivate var triggerInsetTop: CGFloat {
157 | return scrollDirection == .vertical ? trigerInsets.top : trigerInsets.left
158 | }
159 |
160 | fileprivate var triggerInsetEnd: CGFloat {
161 | return scrollDirection == .vertical ? trigerInsets.top : trigerInsets.left
162 | }
163 |
164 | fileprivate var triggerPaddingTop: CGFloat {
165 | return scrollDirection == .vertical ? trigerPadding.top : trigerPadding.left
166 | }
167 |
168 | fileprivate var triggerPaddingEnd: CGFloat {
169 | return scrollDirection == .vertical ? trigerPadding.bottom : trigerPadding.right
170 | }
171 |
172 | required public init?(coder aDecoder: NSCoder) {
173 | super.init(coder: aDecoder)
174 | configureObserver()
175 | }
176 |
177 | public override init() {
178 | super.init()
179 | configureObserver()
180 | }
181 |
182 | deinit {
183 | removeObserver(self, forKeyPath: "collectionView")
184 | }
185 |
186 | override open func prepare() {
187 | super.prepare()
188 |
189 | // scroll trigger insets
190 | if let insets = dataSource?.scrollTrigerEdgeInsetsInCollectionView(self.collectionView!) {
191 | trigerInsets = insets
192 | }
193 |
194 | // scroll trier padding
195 | if let padding = dataSource?.scrollTrigerPaddingInCollectionView(self.collectionView!) {
196 | trigerPadding = padding
197 | }
198 |
199 | // scroll speed value
200 | if let speed = dataSource?.scrollSpeedValueInCollectionView(collectionView!) {
201 | scrollSpeedValue = speed
202 | }
203 | }
204 |
205 | override open func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
206 | guard let attributesArray = super.layoutAttributesForElements(in: rect) else { return nil }
207 |
208 | attributesArray.filter {
209 | $0.representedElementCategory == .cell
210 | }.filter {
211 | $0.indexPath == (cellFakeView?.indexPath)
212 | }.forEach {
213 | // reordering cell alpha
214 |
215 | $0.alpha = dataSource?.collectionView(self.collectionView!, reorderingItemAlphaInSection: $0.indexPath.section) ?? 0
216 | }
217 |
218 | return attributesArray
219 | }
220 |
221 | open override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
222 | if keyPath == "collectionView" {
223 | setUpGestureRecognizers()
224 | }else {
225 | super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
226 | }
227 | }
228 |
229 | fileprivate func configureObserver() {
230 | addObserver(self, forKeyPath: "collectionView", options: [], context: nil)
231 | }
232 |
233 | fileprivate func setUpDisplayLink() {
234 | guard displayLink == nil else {
235 | return
236 | }
237 |
238 | displayLink = CADisplayLink(target: self, selector: #selector(RAReorderableLayout.continuousScroll))
239 | displayLink!.add(to: RunLoop.main, forMode: RunLoopMode.commonModes)
240 | }
241 |
242 | fileprivate func invalidateDisplayLink() {
243 | continuousScrollDirection = .stay
244 | displayLink?.invalidate()
245 | displayLink = nil
246 | }
247 |
248 | // begein scroll
249 | fileprivate func beginScrollIfNeeded() {
250 | if cellFakeView == nil { return }
251 |
252 | if fakeCellTopEdge! <= offsetFromTop + triggerPaddingTop + triggerInsetTop {
253 | continuousScrollDirection = .toTop
254 | setUpDisplayLink()
255 | } else if fakeCellEndEdge! >= offsetFromTop + collectionViewLength - triggerPaddingEnd - triggerInsetEnd {
256 | continuousScrollDirection = .toEnd
257 | setUpDisplayLink()
258 | } else {
259 | invalidateDisplayLink()
260 | }
261 | }
262 |
263 | // move item
264 | fileprivate func moveItemIfNeeded() {
265 | guard let fakeCell = cellFakeView,
266 | let atIndexPath = fakeCell.indexPath,
267 | let toIndexPath = collectionView!.indexPathForItem(at: fakeCell.center) else {
268 | return
269 | }
270 |
271 | guard atIndexPath != toIndexPath else { return }
272 |
273 | // can move item
274 | if let canMove = delegate?.collectionView(collectionView!, at: atIndexPath, canMoveTo: toIndexPath) , !canMove {
275 | return
276 | }
277 |
278 | // will move item
279 | delegate?.collectionView(collectionView!, at: atIndexPath, willMoveTo: toIndexPath)
280 |
281 | let attribute = self.layoutAttributesForItem(at: toIndexPath)!
282 | collectionView!.performBatchUpdates({
283 | fakeCell.indexPath = toIndexPath
284 | fakeCell.cellFrame = attribute.frame
285 | fakeCell.changeBoundsIfNeeded(attribute.bounds)
286 |
287 | self.collectionView!.deleteItems(at: [atIndexPath])
288 | self.collectionView!.insertItems(at: [toIndexPath])
289 |
290 | // did move item
291 | self.delegate?.collectionView(self.collectionView!, at: atIndexPath, didMoveTo: toIndexPath)
292 | }, completion:nil)
293 | }
294 |
295 | internal func continuousScroll() {
296 | guard let fakeCell = cellFakeView else { return }
297 |
298 | let percentage = calcTriggerPercentage()
299 | var scrollRate = continuousScrollDirection.scrollValue(self.scrollSpeedValue, percentage: percentage)
300 |
301 | let offset = offsetFromTop
302 | let length = collectionViewLength
303 |
304 | if contentLength + insetsTop + insetsEnd <= length {
305 | return
306 | }
307 |
308 | if offset + scrollRate <= -insetsTop {
309 | scrollRate = -insetsTop - offset
310 | } else if offset + scrollRate >= contentLength + insetsEnd - length {
311 | scrollRate = contentLength + insetsEnd - length - offset
312 | }
313 |
314 | collectionView!.performBatchUpdates({
315 | if self.scrollDirection == .vertical {
316 | self.fakeCellCenter?.y += scrollRate
317 | fakeCell.center.y = self.fakeCellCenter!.y + self.panTranslation!.y
318 | self.collectionView?.contentOffset.y += scrollRate
319 | } else {
320 | self.fakeCellCenter?.x += scrollRate
321 | fakeCell.center.x = self.fakeCellCenter!.x + self.panTranslation!.x
322 | self.collectionView?.contentOffset.x += scrollRate
323 | }
324 | }, completion: nil)
325 |
326 | moveItemIfNeeded()
327 | }
328 |
329 | fileprivate func calcTriggerPercentage() -> CGFloat {
330 | guard cellFakeView != nil else { return 0 }
331 |
332 | let offset = offsetFromTop
333 | let offsetEnd = offsetFromTop + collectionViewLength
334 | let paddingEnd = triggerPaddingEnd
335 |
336 | var percentage: CGFloat = 0
337 |
338 | if self.continuousScrollDirection == .toTop {
339 | if let fakeCellEdge = fakeCellTopEdge {
340 | percentage = 1.0 - ((fakeCellEdge - (offset + triggerPaddingTop)) / triggerInsetTop)
341 | }
342 | }else if continuousScrollDirection == .toEnd {
343 | if let fakeCellEdge = fakeCellEndEdge {
344 | percentage = 1.0 - (((insetsTop + offsetEnd - paddingEnd) - (fakeCellEdge + insetsTop)) / triggerInsetEnd)
345 | }
346 | }
347 |
348 | percentage = min(1.0, percentage)
349 | percentage = max(0, percentage)
350 | return percentage
351 | }
352 |
353 | // gesture recognizers
354 | fileprivate func setUpGestureRecognizers() {
355 | guard let collectionView = collectionView else { return }
356 | guard longPress == nil && panGesture == nil else {return }
357 |
358 | longPress = UILongPressGestureRecognizer(target: self, action: #selector(RAReorderableLayout.handleLongPress(_:)))
359 | panGesture = UIPanGestureRecognizer(target: self, action: #selector(RAReorderableLayout.handlePanGesture(_:)))
360 | longPress?.delegate = self
361 | panGesture?.delegate = self
362 | panGesture?.maximumNumberOfTouches = 1
363 | let gestures: NSArray! = collectionView.gestureRecognizers as NSArray!
364 | gestures.enumerateObjects(options: []) { gestureRecognizer, index, finish in
365 | if gestureRecognizer is UILongPressGestureRecognizer {
366 | (gestureRecognizer as AnyObject).require(toFail: self.longPress!)
367 | }
368 | collectionView.addGestureRecognizer(self.longPress!)
369 | collectionView.addGestureRecognizer(self.panGesture!)
370 | }
371 | }
372 |
373 | open func cancelDrag() {
374 | cancelDrag(nil)
375 | }
376 |
377 | fileprivate func cancelDrag(_ toIndexPath: IndexPath!) {
378 | guard cellFakeView != nil else { return }
379 |
380 | // will end drag item
381 | self.delegate?.collectionView(self.collectionView!, collectionView: self, willEndDraggingItemTo: toIndexPath)
382 |
383 | collectionView?.scrollsToTop = true
384 |
385 | fakeCellCenter = nil
386 |
387 | invalidateDisplayLink()
388 |
389 | cellFakeView!.pushBackView {
390 | self.cellFakeView!.removeFromSuperview()
391 | self.cellFakeView = nil
392 | self.invalidateLayout()
393 |
394 | // did end drag item
395 | self.delegate?.collectionView(self.collectionView!, collectionView: self, didEndDraggingItemTo: toIndexPath)
396 | }
397 | }
398 |
399 | // long press gesture
400 | internal func handleLongPress(_ longPress: UILongPressGestureRecognizer!) {
401 | let location = longPress.location(in: collectionView)
402 | var indexPath: IndexPath? = collectionView?.indexPathForItem(at: location)
403 |
404 | if let cellFakeView = cellFakeView {
405 | indexPath = cellFakeView.indexPath
406 | }
407 |
408 | if indexPath == nil { return }
409 |
410 | switch longPress.state {
411 | case .began:
412 | // will begin drag item
413 | delegate?.collectionView(self.collectionView!, collectionView: self, willBeginDraggingItemAt: indexPath!)
414 | collectionView?.scrollsToTop = false
415 |
416 | let currentCell = collectionView?.cellForItem(at: indexPath!)
417 |
418 | cellFakeView = RACellFakeView(cell: currentCell!)
419 | cellFakeView!.indexPath = indexPath
420 | cellFakeView!.originalCenter = currentCell?.center
421 | cellFakeView!.cellFrame = layoutAttributesForItem(at: indexPath!)!.frame
422 | collectionView?.addSubview(cellFakeView!)
423 |
424 | fakeCellCenter = cellFakeView!.center
425 |
426 | invalidateLayout()
427 |
428 | cellFakeView?.pushFowardView()
429 |
430 | // did begin drag item
431 | delegate?.collectionView(self.collectionView!, collectionView: self, didBeginDraggingItemAt: indexPath!)
432 |
433 | case .cancelled, .ended:
434 | cancelDrag(indexPath)
435 | default:
436 | break
437 | }
438 | }
439 |
440 | // pan gesture
441 | func handlePanGesture(_ pan: UIPanGestureRecognizer!) {
442 | panTranslation = pan.translation(in: collectionView!)
443 | if let cellFakeView = cellFakeView,
444 | let fakeCellCenter = fakeCellCenter,
445 | let panTranslation = panTranslation {
446 | switch pan.state {
447 | case .changed:
448 | cellFakeView.center.x = fakeCellCenter.x + panTranslation.x
449 | cellFakeView.center.y = fakeCellCenter.y + panTranslation.y
450 |
451 | beginScrollIfNeeded()
452 | moveItemIfNeeded()
453 | case .cancelled, .ended:
454 | invalidateDisplayLink()
455 | default:
456 | break
457 | }
458 | }
459 | }
460 |
461 | // gesture recognize delegate
462 | open func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
463 | // allow move item
464 | let location = gestureRecognizer.location(in: collectionView)
465 | if let indexPath = collectionView?.indexPathForItem(at: location) ,
466 | delegate?.collectionView(self.collectionView!, allowMoveAt: indexPath) == false {
467 | return false
468 | }
469 |
470 | switch gestureRecognizer {
471 | case longPress:
472 | return !(collectionView!.panGestureRecognizer.state != .possible && collectionView!.panGestureRecognizer.state != .failed)
473 | case panGesture:
474 | return !(longPress!.state == .possible || longPress!.state == .failed)
475 | default:
476 | return true
477 | }
478 | }
479 |
480 | open func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
481 | switch gestureRecognizer {
482 | case panGesture:
483 | return otherGestureRecognizer == longPress
484 | case collectionView?.panGestureRecognizer:
485 | return (longPress!.state != .possible || longPress!.state != .failed)
486 | default:
487 | return true
488 | }
489 | }
490 | }
491 |
492 | private class RACellFakeView: UIView {
493 |
494 | weak var cell: UICollectionViewCell?
495 |
496 | var cellFakeImageView: UIImageView?
497 |
498 | var cellFakeHightedView: UIImageView?
499 |
500 | fileprivate var indexPath: IndexPath?
501 |
502 | fileprivate var originalCenter: CGPoint?
503 |
504 | fileprivate var cellFrame: CGRect?
505 |
506 | required init?(coder aDecoder: NSCoder) {
507 | super.init(coder: aDecoder)
508 | }
509 |
510 | init(cell: UICollectionViewCell) {
511 | super.init(frame: cell.frame)
512 |
513 | self.cell = cell
514 |
515 | layer.shadowColor = UIColor.black.cgColor
516 | layer.shadowOffset = CGSize(width: 0, height: 0)
517 | layer.shadowOpacity = 0
518 | layer.shadowRadius = 5.0
519 | layer.shouldRasterize = false
520 |
521 | cellFakeImageView = UIImageView(frame: self.bounds)
522 | cellFakeImageView?.contentMode = UIViewContentMode.scaleAspectFill
523 | cellFakeImageView?.autoresizingMask = [.flexibleWidth , .flexibleHeight]
524 |
525 | cellFakeHightedView = UIImageView(frame: self.bounds)
526 | cellFakeHightedView?.contentMode = UIViewContentMode.scaleAspectFill
527 | cellFakeHightedView?.autoresizingMask = [.flexibleWidth , .flexibleHeight]
528 |
529 | cell.isHighlighted = true
530 | cellFakeHightedView?.image = getCellImage()
531 | cell.isHighlighted = false
532 | cellFakeImageView?.image = getCellImage()
533 |
534 | addSubview(cellFakeImageView!)
535 | addSubview(cellFakeHightedView!)
536 | }
537 |
538 | func changeBoundsIfNeeded(_ bounds: CGRect) {
539 | if self.bounds.equalTo(bounds) { return }
540 |
541 | UIView.animate(
542 | withDuration: 0.3,
543 | delay: 0,
544 | options: [.curveEaseInOut, .beginFromCurrentState],
545 | animations: {
546 | self.bounds = bounds
547 | },
548 | completion: nil
549 | )
550 | }
551 |
552 | func pushFowardView() {
553 | UIView.animate(
554 | withDuration: 0.3,
555 | delay: 0,
556 | options: [.curveEaseInOut, .beginFromCurrentState],
557 | animations: {
558 | self.center = self.originalCenter!
559 | self.transform = CGAffineTransform(scaleX: 1.1, y: 1.1)
560 | self.cellFakeHightedView!.alpha = 0;
561 | let shadowAnimation = CABasicAnimation(keyPath: "shadowOpacity")
562 | shadowAnimation.fromValue = 0
563 | shadowAnimation.toValue = 0.7
564 | shadowAnimation.isRemovedOnCompletion = false
565 | shadowAnimation.fillMode = kCAFillModeForwards
566 | self.layer.add(shadowAnimation, forKey: "applyShadow")
567 | },
568 | completion: { _ in
569 | self.cellFakeHightedView?.removeFromSuperview()
570 | }
571 | )
572 | }
573 |
574 | func pushBackView(_ completion: (()->Void)?) {
575 | UIView.animate(
576 | withDuration: 0.3,
577 | delay: 0,
578 | options: [.curveEaseInOut, .beginFromCurrentState],
579 | animations: {
580 | self.transform = CGAffineTransform.identity
581 | self.frame = self.cellFrame!
582 | let shadowAnimation = CABasicAnimation(keyPath: "shadowOpacity")
583 | shadowAnimation.fromValue = 0.7
584 | shadowAnimation.toValue = 0
585 | shadowAnimation.isRemovedOnCompletion = false
586 | shadowAnimation.fillMode = kCAFillModeForwards
587 | self.layer.add(shadowAnimation, forKey: "removeShadow")
588 | },
589 | completion: { _ in
590 | completion?()
591 | }
592 | )
593 | }
594 |
595 | fileprivate func getCellImage() -> UIImage {
596 | UIGraphicsBeginImageContextWithOptions(cell!.bounds.size, false, UIScreen.main.scale * 2)
597 | defer { UIGraphicsEndImageContext() }
598 | cell!.drawHierarchy(in: cell!.bounds, afterScreenUpdates: true)
599 |
600 | return UIGraphicsGetImageFromCurrentImageContext()!
601 | }
602 | }
603 |
604 | // Convenience method
605 | private func ~= (obj:NSObjectProtocol?, r:UIGestureRecognizer) -> Bool {
606 | return r.isEqual(obj)
607 | }
608 |
--------------------------------------------------------------------------------
/RAReorderableLayout-Demo/RAReorderableLayout-Demo/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 |
70 |
71 |
72 |
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 |
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 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
--------------------------------------------------------------------------------