├── .DS_Store
├── MMCollectionViewFlowLayout
├── Assets.xcassets
│ ├── Contents.json
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── .DS_Store
├── MMCollectionViewFlowLayout
│ ├── .DS_Store
│ ├── MMLayoutProtocol.swift
│ ├── MMCollectionViewLayoutAttributes.swift
│ ├── Transition
│ │ ├── CrossFadeAttributesTransition.swift
│ │ ├── ZoomInOutAttributesTransition.swift
│ │ ├── ParallaxAttributesTransition.swift
│ │ ├── PageAttributesTransition.swift
│ │ ├── RotateInOutAttributesTransition.swift
│ │ ├── CubeAttributesTransition.swift
│ │ ├── LinearCardAttributesTransition.swift
│ │ └── TurnAttributesTransition.swift
│ ├── UIView+Anchor.swift
│ └── MMCollectionViewFlowLayout.swift
├── Info.plist
├── Base.lproj
│ └── LaunchScreen.storyboard
├── AppDelegate.swift
├── ViewController.swift
├── ImageCollectionViewController.swift
└── Main.storyboard
├── MMCollectionViewFlowLayout.xcodeproj
├── xcuserdata
│ └── iean.xcuserdatad
│ │ ├── xcdebugger
│ │ └── Breakpoints_v2.xcbkptlist
│ │ └── xcschemes
│ │ ├── xcschememanagement.plist
│ │ └── MMCollectionViewFlowLayout.xcscheme
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcuserdata
│ │ └── iean.xcuserdatad
│ │ └── UserInterfaceState.xcuserstate
└── project.pbxproj
└── README.md
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edsum/MMCollectionViewFlowLayout/HEAD/.DS_Store
--------------------------------------------------------------------------------
/MMCollectionViewFlowLayout/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/MMCollectionViewFlowLayout/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edsum/MMCollectionViewFlowLayout/HEAD/MMCollectionViewFlowLayout/.DS_Store
--------------------------------------------------------------------------------
/MMCollectionViewFlowLayout/MMCollectionViewFlowLayout/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edsum/MMCollectionViewFlowLayout/HEAD/MMCollectionViewFlowLayout/MMCollectionViewFlowLayout/.DS_Store
--------------------------------------------------------------------------------
/MMCollectionViewFlowLayout.xcodeproj/xcuserdata/iean.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/MMCollectionViewFlowLayout.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/MMCollectionViewFlowLayout.xcodeproj/project.xcworkspace/xcuserdata/iean.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edsum/MMCollectionViewFlowLayout/HEAD/MMCollectionViewFlowLayout.xcodeproj/project.xcworkspace/xcuserdata/iean.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/MMCollectionViewFlowLayout/MMCollectionViewFlowLayout/MMLayoutProtocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MMLayoutProtocol.swift
3 | // MMCollectionViewFlowLayout
4 | //
5 | // Created by Iean on 2017/5/18.
6 | // Copyright © 2017年 Iean. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | public protocol MMLayoutProtocol {
12 | func transiton(_ position: CGFloat, _ collectionView: UICollectionView, _ attributes: MMCollectionViewLayoutAttributes)
13 | }
14 |
--------------------------------------------------------------------------------
/MMCollectionViewFlowLayout.xcodeproj/xcuserdata/iean.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | MMCollectionViewFlowLayout.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | 0E12769E1ECCC257000BEC68
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/MMCollectionViewFlowLayout/MMCollectionViewFlowLayout/MMCollectionViewLayoutAttributes.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MMCollectionViewLayoutAttributes.swift
3 | // MMCollectionViewFlowLayout
4 | //
5 | // Created by Iean on 2017/5/18.
6 | // Copyright © 2017年 Iean. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | public class MMCollectionViewLayoutAttributes: UICollectionViewLayoutAttributes {
13 | public var contentView: UIView?
14 |
15 | public override func copy(with zone: NSZone? = nil) -> Any {
16 | let c: MMCollectionViewLayoutAttributes = super.copy(with: zone) as! MMCollectionViewLayoutAttributes
17 | c.contentView = contentView
18 | return c
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/MMCollectionViewFlowLayout/MMCollectionViewFlowLayout/Transition/CrossFadeAttributesTransition.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CrossFadeAttributesTransition.swift
3 | // MMCollectionViewFlowLayout
4 | //
5 | // Created by Iean on 2017/5/18.
6 | // Copyright © 2017年 Iean. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | /// 淡入淡出
12 | public struct CrossFadeAttributesTransition: MMLayoutProtocol {
13 | public init() {}
14 |
15 | public func transiton(_ position: CGFloat, _ collectionView: UICollectionView, _ attributes: MMCollectionViewLayoutAttributes) {
16 | let contentOffset: CGPoint = collectionView.contentOffset
17 | attributes.frame = CGRect(origin: contentOffset, size: attributes.frame.size)
18 | attributes.alpha = 1-abs(position)
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/MMCollectionViewFlowLayout/MMCollectionViewFlowLayout/Transition/ZoomInOutAttributesTransition.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ZoomInOutAttributesTransition.swift
3 | // MMCollectionViewFlowLayout
4 | //
5 | // Created by Iean on 2017/5/18.
6 | // Copyright © 2017年 Iean. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | /// 变小移出,变大进入
12 | public struct ZoomInOutAttributesTransition: MMLayoutProtocol {
13 |
14 | /// scaleRate决定最大比例率
15 | /// 0 表示无比例,1表示最大值的大小将为最大值,最小值将消失
16 | public var scaleRate: CGFloat
17 |
18 | public init(scaleRate: CGFloat = 0.2) {
19 | self.scaleRate = scaleRate
20 | }
21 |
22 | public func transiton(_ position: CGFloat, _ collectionView: UICollectionView, _ attributes: MMCollectionViewLayoutAttributes) {
23 | if abs(position) >= 1 {
24 | attributes.contentView?.transform = .identity
25 | }else {
26 | let scaleFactor: CGFloat = scaleRate*position+1.0
27 | attributes.contentView?.transform = CGAffineTransform(scaleX: scaleFactor, y: scaleFactor)
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/MMCollectionViewFlowLayout/MMCollectionViewFlowLayout/UIView+Anchor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+Anchor.swift
3 | // MMCollectionViewFlowLayout
4 | //
5 | // Created by Iean on 2017/5/18.
6 | // Copyright © 2017年 Iean. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension UIView {
12 | func keepCenterAndApplyAnchorPoint(_ point: CGPoint) {
13 |
14 | guard layer.anchorPoint != point else {
15 | return
16 | }
17 |
18 | var newPoint: CGPoint = CGPoint(x: bounds.width*point.x, y: bounds.height*point.y)
19 | var oldPoint: CGPoint = CGPoint(x: bounds.width*layer.anchorPoint.x, y: bounds.height*layer.anchorPoint.y)
20 |
21 | newPoint = newPoint.applying(transform)
22 | oldPoint = oldPoint.applying(transform)
23 |
24 | var c: CGPoint = layer.position
25 | c.x -= oldPoint.x
26 | c.x += newPoint.x
27 |
28 | c.y -= oldPoint.y
29 | c.y += newPoint.y
30 |
31 | layer.position = c
32 | layer.anchorPoint = point
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/MMCollectionViewFlowLayout/MMCollectionViewFlowLayout/Transition/ParallaxAttributesTransition.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ParallaxAttributesTransition.swift
3 | // MMCollectionViewFlowLayout
4 | //
5 | // Created by Iean on 2017/5/18.
6 | // Copyright © 2017年 Iean. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 |
12 | /// 视差效果
13 | public struct ParallaxAttributesTransition: MMLayoutProtocol {
14 |
15 | /// 速度越高,视差越明显
16 | /// 建议在[0, 1]中,0 表示无视差,默认是0.5
17 | public var speed: CGFloat
18 |
19 | public init(speed: CGFloat = 0.5) {
20 | self.speed = speed
21 | }
22 |
23 | public func transiton(_ position: CGFloat, _ collectionView: UICollectionView, _ attributes: MMCollectionViewLayoutAttributes) {
24 | if abs(position) >= 1 {
25 | attributes.contentView?.transform = .identity
26 | }else {
27 | let width: CGFloat = collectionView.frame.width
28 | let transitionX: CGFloat = -(width*speed*position)
29 | attributes.contentView?.transform = CGAffineTransform(translationX: transitionX, y: 0)
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/MMCollectionViewFlowLayout/MMCollectionViewFlowLayout/Transition/PageAttributesTransition.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PageAttributesTransition.swift
3 | // MMCollectionViewFlowLayout
4 | //
5 | // Created by Iean on 2017/5/18.
6 | // Copyright © 2017年 Iean. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | /// 覆盖效果
12 | public struct PageAttributesTransition: MMLayoutProtocol {
13 |
14 | public var scaleRate: CGFloat
15 |
16 | public init(scaleRate: CGFloat = 0.2) {
17 | self.scaleRate = scaleRate
18 | }
19 |
20 | public func transiton(_ position: CGFloat, _ collectionView: UICollectionView, _ attributes: MMCollectionViewLayoutAttributes) {
21 | let contentOffset: CGPoint = collectionView.contentOffset
22 | let itemOrigin: CGPoint = attributes.frame.origin
23 | let scaleFactor: CGFloat = scaleRate*min(position, 0)+1.0
24 | var transform: CGAffineTransform = CGAffineTransform(scaleX: scaleFactor, y: scaleFactor)
25 | transform = transform.concatenating(CGAffineTransform(translationX: position < 0 ? contentOffset.x - itemOrigin.x : 0, y: 0))
26 | attributes.transform = transform
27 | attributes.zIndex = attributes.indexPath.row
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/MMCollectionViewFlowLayout/MMCollectionViewFlowLayout/Transition/RotateInOutAttributesTransition.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RotateInOutAttributesTransition.swift
3 | // MMCollectionViewFlowLayout
4 | //
5 | // Created by Iean on 2017/5/18.
6 | // Copyright © 2017年 Iean. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | /// 旋转渐隐
12 | /// 必须将cell中的'clipsToBounds'设置为false
13 | public struct RotateInOutAttributesTransition: MMLayoutProtocol {
14 |
15 | /// 远离中心的单元格中应用的alpa
16 | /// [0, 1]的取值,默认是 0
17 | public var minAlpha: CGFloat
18 |
19 | /// 将应用于cell的最大旋转角度
20 | /// [0, 2pi]的取值,默认是0.25pi
21 | public var maxRotate: CGFloat
22 |
23 | public init(minAlpha: CGFloat = 0, maxRotate: CGFloat = CGFloat(Double.pi/4)) {
24 | self.minAlpha = minAlpha
25 | self.maxRotate = maxRotate
26 | }
27 |
28 | public func transiton(_ position: CGFloat, _ collectionView: UICollectionView, _ attributes: MMCollectionViewLayoutAttributes) {
29 | if abs(position) >= 1 {
30 | attributes.contentView?.transform = .identity
31 | attributes.alpha = 1.0
32 | }else {
33 | let rotateFactor: CGFloat = maxRotate*position
34 | attributes.zIndex = attributes.indexPath.row
35 | attributes.alpha = 1.0-abs(position)+minAlpha
36 | attributes.contentView?.transform = CGAffineTransform(rotationAngle: rotateFactor)
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/MMCollectionViewFlowLayout/MMCollectionViewFlowLayout/Transition/CubeAttributesTransition.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CubeAttributesTransition.swift
3 | // MMCollectionViewFlowLayout
4 | //
5 | // Created by Iean on 2017/5/18.
6 | // Copyright © 2017年 Iean. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | /// 3D翻转
12 | public struct CubeAttributesTransition: MMLayoutProtocol {
13 |
14 | /// 透视度
15 | /// [-1/2000, -1/200],必须为负数,默认是-1/500
16 | public var perspective: CGFloat
17 |
18 | /// 旋转最大角度
19 | public var totalAngle: CGFloat
20 |
21 | public init(perspective: CGFloat = -1/500, totalAngle: CGFloat = CGFloat(Double.pi/2)) {
22 | self.perspective = perspective
23 | self.totalAngle = totalAngle
24 | }
25 |
26 | public func transiton(_ position: CGFloat, _ collectionView: UICollectionView, _ attributes: MMCollectionViewLayoutAttributes) {
27 | if abs(position) >= 1 {
28 | attributes.contentView?.layer.transform = CATransform3DIdentity
29 | }else {
30 | let rotateAngle: CGFloat = totalAngle*position
31 | var transform: CATransform3D = CATransform3DIdentity
32 | transform.m34 = perspective
33 | transform = CATransform3DRotate(transform, rotateAngle, 0, 1, 0)
34 |
35 | // attributes.transform = transform
36 | attributes.contentView?.layer.transform = transform
37 | attributes.contentView?.keepCenterAndApplyAnchorPoint(CGPoint(x: position > 0 ? 0 : 1, y: 0.5))
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/MMCollectionViewFlowLayout/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/MMCollectionViewFlowLayout/MMCollectionViewFlowLayout/Transition/LinearCardAttributesTransition.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LinearCardAttributesTransition.swift
3 | // MMCollectionViewFlowLayout
4 | //
5 | // Created by Iean on 2017/5/18.
6 | // Copyright © 2017年 Iean. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | /// 横向移动,中间大,两边小
12 | /// 必须将cell中的'clipsToBounds'设置为false
13 | public struct LinearCardAttributesTransition: MMLayoutProtocol {
14 |
15 | /// 远离中心的单元格中应用的alpa
16 | /// [0, 1]的取值,默认是 0
17 | public var minAlpha: CGFloat
18 |
19 | /// 两个cell之间的间距比
20 | public var itemSpacing: CGFloat
21 |
22 | /// 作用在cell使得其成为卡的比例大小
23 | public var scaleRotate: CGFloat
24 |
25 | public init(minAlpha: CGFloat = 0.5, itemSpacing: CGFloat = 0.4, scaleRotate: CGFloat = 0.7) {
26 | self.minAlpha = minAlpha
27 | self.itemSpacing = itemSpacing
28 | self.scaleRotate = scaleRotate
29 | }
30 |
31 | public func transiton(_ position: CGFloat, _ collectionView: UICollectionView, _ attributes: MMCollectionViewLayoutAttributes) {
32 | let width: CGFloat = collectionView.frame.width
33 | let transitionX: CGFloat = -width*itemSpacing*position
34 | let scaleFactor: CGFloat = scaleRotate-0.1*abs(position)
35 |
36 | let scaleTransform: CGAffineTransform = CGAffineTransform(scaleX: scaleFactor, y: scaleFactor)
37 | let transitionTransform: CGAffineTransform = CGAffineTransform(translationX: transitionX, y: 0)
38 |
39 | attributes.alpha = 1.0-abs(position)+minAlpha
40 | attributes.transform = transitionTransform.concatenating(scaleTransform)
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/MMCollectionViewFlowLayout/MMCollectionViewFlowLayout/Transition/TurnAttributesTransition.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TurnAttributesTransition.swift
3 | // MMCollectionViewFlowLayout
4 | //
5 | // Created by Iean on 2017/5/18.
6 | // Copyright © 2017年 Iean. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | /// 翻页渐隐
12 | public struct TurnAttributesTransition: MMLayoutProtocol {
13 |
14 | /// 透视度
15 | /// [-1/2000, -1/200],必须为负数,默认是-1/1000
16 | public var perspective: CGFloat
17 |
18 | public init(perspective: CGFloat = -1/1000) {
19 | self.perspective = perspective
20 | }
21 |
22 | public func transiton(_ position: CGFloat, _ collectionView: UICollectionView, _ attributes: MMCollectionViewLayoutAttributes) {
23 | if abs(position) >= 1{
24 | attributes.contentView?.layer.transform = CATransform3DIdentity
25 | }else {
26 | let rotateAngle: CGFloat = CGFloat(Double.pi/2)*min(position, 0)
27 | var transform: CATransform3D = CATransform3DIdentity
28 | transform.m34 = perspective
29 | transform = CATransform3DRotate(transform, rotateAngle, 0, 1, 0)
30 |
31 | let contentOffset: CGPoint = collectionView.contentOffset
32 | let itemOrigin: CGPoint = attributes.frame.origin
33 | transform = CATransform3DTranslate(transform, contentOffset.x-itemOrigin.x, 0, 0)
34 | transform = CATransform3DScale(transform, 1.0, 0.8, 1.0)
35 |
36 | attributes.contentView?.layer.transform = transform
37 | attributes.contentView?.keepCenterAndApplyAnchorPoint(CGPoint(x: 0, y: 0.5))
38 | attributes.alpha = 1-abs(position)
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/MMCollectionViewFlowLayout/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/MMCollectionViewFlowLayout/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | }
88 | ],
89 | "info" : {
90 | "version" : 1,
91 | "author" : "xcode"
92 | }
93 | }
--------------------------------------------------------------------------------
/MMCollectionViewFlowLayout/MMCollectionViewFlowLayout/MMCollectionViewFlowLayout.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MMCollectionViewFlowLayout.swift
3 | // MMCollectionViewFlowLayout
4 | //
5 | // Created by Iean on 2017/5/18.
6 | // Copyright © 2017年 Iean. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | public class MMCollectionViewFlowLayout: UICollectionViewFlowLayout {
12 |
13 |
14 | /// 处理转场
15 | public var transition: MMLayoutProtocol?
16 |
17 | /// 可以记录layout attributes的其他属性
18 | public override class var layoutAttributesClass: AnyClass {
19 | return MMCollectionViewLayoutAttributes.self
20 | }
21 |
22 | public override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
23 | guard let attributes = super.layoutAttributesForElements(in: rect) else {
24 | return nil
25 | }
26 | return attributes.flatMap { $0.copy() as? UICollectionViewLayoutAttributes}.map {
27 | self.transformLayoutAttributes($0)
28 | }
29 | }
30 |
31 | override public func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
32 | return true
33 | }
34 |
35 | private func transformLayoutAttributes(_ attributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
36 | guard let collectionView = self.collectionView, let a = attributes as? MMCollectionViewLayoutAttributes else {
37 | return attributes
38 | }
39 | // cell的中点和屏幕的中点之间的距离的比率对于每次cell的位置都是确定的。
40 | let width: CGFloat = collectionView.frame.width
41 | let centerX: CGFloat = width*0.5
42 | let offset: CGFloat = collectionView.contentOffset.x
43 | let itemX: CGFloat = a.center.x-offset
44 | let position = (itemX-centerX)/width
45 |
46 | // 一旦我们开始使用就缓存contentView
47 | if a.contentView == nil {
48 | a.contentView = collectionView.cellForItem(at: attributes.indexPath)?.contentView
49 | }
50 | transition?.transiton(position, collectionView, a)
51 | return a
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/MMCollectionViewFlowLayout/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // MMCollectionViewFlowLayout
4 | //
5 | // Created by Iean on 2017/5/18.
6 | // Copyright © 2017年 Iean. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | func applicationWillResignActive(_ application: UIApplication) {
23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
25 | }
26 |
27 | func applicationDidEnterBackground(_ application: UIApplication) {
28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | func applicationWillEnterForeground(_ application: UIApplication) {
33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
34 | }
35 |
36 | func applicationDidBecomeActive(_ application: UIApplication) {
37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
38 | }
39 |
40 | func applicationWillTerminate(_ application: UIApplication) {
41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 | }
43 |
44 |
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/MMCollectionViewFlowLayout/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // MMCollectionViewFlowLayout
4 | //
5 | // Created by Iean on 2017/5/18.
6 | // Copyright © 2017年 Iean. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ViewController: UITableViewController {
12 |
13 | private let transitions: [(MMLayoutProtocol, Bool)] = [(ParallaxAttributesTransition(), true),
14 | (ZoomInOutAttributesTransition(), true),
15 | (RotateInOutAttributesTransition(), false),
16 | (LinearCardAttributesTransition(), false),
17 | (CubeAttributesTransition(), true),
18 | (CrossFadeAttributesTransition(), true),
19 | (TurnAttributesTransition(), true),
20 | (PageAttributesTransition(), true)]
21 |
22 |
23 | override func viewDidLoad() {
24 | super.viewDidLoad()
25 | }
26 |
27 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
28 | if let dist = segue.destination as? ImageCollectionViewController, let indexPath = sender as? IndexPath {
29 | dist.transition = transitions[indexPath.row]
30 | }
31 | }
32 |
33 | // MARK: - TableView Delegate and DataSource
34 |
35 | override func numberOfSections(in tableView: UITableView) -> Int {
36 | return 1
37 | }
38 |
39 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
40 | return transitions.count
41 | }
42 |
43 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
44 | let c = UITableViewCell(style: .default, reuseIdentifier: nil)
45 |
46 | c.textLabel?.font = UIFont.systemFont(ofSize: 12)
47 | c.textLabel?.text = "\(transitions[indexPath.row].0.self)"
48 |
49 | return c
50 | }
51 |
52 | override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
53 | performSegue(withIdentifier: "ShowCollectionViewController", sender: indexPath)
54 | }
55 |
56 | }
57 |
58 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # MMCollectionViewFlowLayout
2 | 一个针对多种业务需求的**UICollectionView** 。
3 | 当您从一个项目滚动到另一个项目时,**UICollectionView**没有转换效果。 有很多方法可以为**UICollectionView**编写动画,但使用**UICollectionViewLayout**子类是最简单的一个。
4 |
5 | -       
6 |
7 | # 使用方法
8 | * 下载项目到本地:方式一:
9 | 终端输入: $ git clone https://github.com/edsum/MMCollectionViewFlowLayout
10 | 方式二: 如下图
11 | 
12 |
13 | * 把 `MMCollectionViewFlowLayout`文件夹拖入项目
14 | 
15 |
16 | * 设置你的`UICollectionView`的`collectionViewLayout`,为`MMCollectionViewFlowLayout`,设置`MMCollectionViewFlowLayout`的transition,目前提供了八种动画形式,代码如下:
17 |
18 | ```
19 | let layout = MMCollectionViewFlowLayout()
20 | layout.transition = ParallaxAttributesTransition()
21 | collectionView.collectionViewLayout = layout
22 | ```
23 | # 定制
24 | Transition的实现是基于`MMLayoutProtocol`协议的实现。他们大多数都有额外的参数,您可以调整转换。 你也可以编写自己的动画。
25 |
26 | # 期待
27 |
28 | * 如果你发现了哪些bug,欢迎及时Issues;
29 | * 作者将不定期更新新的动画模式;
30 | * 如果你有更好玩的可以@Me:ed_sun0129@163.com
--------------------------------------------------------------------------------
/MMCollectionViewFlowLayout.xcodeproj/xcuserdata/iean.xcuserdatad/xcschemes/MMCollectionViewFlowLayout.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/MMCollectionViewFlowLayout/ImageCollectionViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageCollectionViewController.swift
3 | // MMCollectionViewFlowLayout
4 | //
5 | // Created by Iean on 2017/5/18.
6 | // Copyright © 2017年 Iean. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class SimpleCollectionViewCell: UICollectionViewCell {
12 |
13 | @IBOutlet weak var imageView: UIImageView!
14 | @IBOutlet weak var titleLabel: UILabel!
15 |
16 | func bind(color: String, imageName: String) {
17 | titleLabel.text = "\(arc4random_uniform(1000))"
18 | backgroundColor = .clear
19 | contentView.backgroundColor = color.hexColor
20 | imageView.image = UIImage(named: imageName)
21 | }
22 | }
23 |
24 | extension String {
25 | var hexColor: UIColor {
26 | let hex = trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
27 | var int = UInt32()
28 | Scanner(string: hex).scanHexInt32(&int)
29 | let a, r, g, b: UInt32
30 | switch hex.characters.count {
31 | case 3: // RGB (12-bit)
32 | (a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17)
33 | case 6: // RGB (24-bit)
34 | (a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF)
35 | case 8: // ARGB (32-bit)
36 | (a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF)
37 | default:
38 | return .clear
39 | }
40 | return UIColor(red: CGFloat(r) / 255, green: CGFloat(g) / 255, blue: CGFloat(b) / 255, alpha: CGFloat(a) / 255)
41 | }
42 | }
43 |
44 | class ImageCollectionViewController: UICollectionViewController {
45 |
46 | var transition: (MMLayoutProtocol, Bool)? {
47 | didSet{
48 | if let layout = collectionView?.collectionViewLayout as? MMCollectionViewFlowLayout {
49 | layout.transition = transition?.0
50 | }
51 | }
52 | }
53 |
54 | let cellIdentifier = "SimpleCollectionViewCell"
55 | let vcs = [("f44336", "nature1"),
56 | ("9c27b0", "nature2"),
57 | ("3f51b5", "nature3"),
58 | ("03a9f4", "animal1"),
59 | ("009688", "animal2"),
60 | ("8bc34a", "animal3")]
61 |
62 | override func viewDidLoad() {
63 | super.viewDidLoad()
64 | // Do any additional setup after loading the view, typically from a nib.
65 |
66 | // Must turn paging on.
67 | collectionView?.isPagingEnabled = true
68 |
69 | }
70 |
71 | override func didReceiveMemoryWarning() {
72 | super.didReceiveMemoryWarning()
73 | // Dispose of any resources that can be recreated.
74 | }
75 |
76 | @IBAction func didSwipeDown(_ sender: Any) {
77 | dismiss(animated: true, completion: nil)
78 | }
79 |
80 | override var prefersStatusBarHidden: Bool { return true }
81 | }
82 |
83 | extension ImageCollectionViewController: UICollectionViewDelegateFlowLayout {
84 | override func numberOfSections(in collectionView: UICollectionView) -> Int {
85 | return 1
86 | }
87 |
88 | override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
89 | return vcs.count
90 | }
91 |
92 | override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
93 | let c = collectionView.dequeueReusableCell(withReuseIdentifier: cellIdentifier, for: indexPath)
94 |
95 | if let cell = c as? SimpleCollectionViewCell {
96 | let v = vcs[indexPath.row]
97 | cell.bind(color: v.0, imageName: v.1)
98 | cell.clipsToBounds = transition?.1 ?? true
99 | }
100 |
101 | return c
102 | }
103 |
104 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
105 | return view.bounds.size
106 | }
107 |
108 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
109 | return .zero
110 | }
111 |
112 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
113 | return 0
114 | }
115 |
116 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
117 | return 0
118 | }
119 | }
120 |
121 |
--------------------------------------------------------------------------------
/MMCollectionViewFlowLayout/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 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
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 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
--------------------------------------------------------------------------------
/MMCollectionViewFlowLayout.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 0E1276A31ECCC257000BEC68 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1276A21ECCC257000BEC68 /* AppDelegate.swift */; };
11 | 0E1276A51ECCC257000BEC68 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1276A41ECCC257000BEC68 /* ViewController.swift */; };
12 | 0E1276AA1ECCC257000BEC68 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0E1276A91ECCC257000BEC68 /* Assets.xcassets */; };
13 | 0E1276AD1ECCC257000BEC68 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E1276AB1ECCC257000BEC68 /* LaunchScreen.storyboard */; };
14 | 0E2BF1B11ECD674000FA6C58 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E2BF1B01ECD674000FA6C58 /* Main.storyboard */; };
15 | 0E2BF1B51ECD67AD00FA6C58 /* ImageCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E2BF1B41ECD67AD00FA6C58 /* ImageCollectionViewController.swift */; };
16 | 0E2BF1EA1ECD704E00FA6C58 /* UIView+Anchor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E2BF1E91ECD704E00FA6C58 /* UIView+Anchor.swift */; };
17 | 0E2BF1EC1ECD722800FA6C58 /* MMLayoutProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E2BF1EB1ECD722800FA6C58 /* MMLayoutProtocol.swift */; };
18 | 0E2BF1EF1ECD723100FA6C58 /* MMCollectionViewFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E2BF1ED1ECD723100FA6C58 /* MMCollectionViewFlowLayout.swift */; };
19 | 0E2BF1F01ECD723100FA6C58 /* MMCollectionViewLayoutAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E2BF1EE1ECD723100FA6C58 /* MMCollectionViewLayoutAttributes.swift */; };
20 | 0E2BF1F31ECD725800FA6C58 /* ParallaxAttributesTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E2BF1F21ECD725800FA6C58 /* ParallaxAttributesTransition.swift */; };
21 | 0E2BF1F51ECD726400FA6C58 /* ZoomInOutAttributesTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E2BF1F41ECD726400FA6C58 /* ZoomInOutAttributesTransition.swift */; };
22 | 0E2BF1F71ECD727400FA6C58 /* RotateInOutAttributesTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E2BF1F61ECD727400FA6C58 /* RotateInOutAttributesTransition.swift */; };
23 | 0E2BF1F91ECD728500FA6C58 /* LinearCardAttributesTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E2BF1F81ECD728500FA6C58 /* LinearCardAttributesTransition.swift */; };
24 | 0E2BF1FB1ECD729000FA6C58 /* CubeAttributesTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E2BF1FA1ECD729000FA6C58 /* CubeAttributesTransition.swift */; };
25 | 0E2BF1FD1ECD729A00FA6C58 /* CrossFadeAttributesTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E2BF1FC1ECD729A00FA6C58 /* CrossFadeAttributesTransition.swift */; };
26 | 0E2BF1FF1ECD72B200FA6C58 /* TurnAttributesTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E2BF1FE1ECD72B200FA6C58 /* TurnAttributesTransition.swift */; };
27 | 0E2BF2011ECD72C200FA6C58 /* PageAttributesTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E2BF2001ECD72C200FA6C58 /* PageAttributesTransition.swift */; };
28 | /* End PBXBuildFile section */
29 |
30 | /* Begin PBXFileReference section */
31 | 0E12769F1ECCC257000BEC68 /* MMCollectionViewFlowLayout.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MMCollectionViewFlowLayout.app; sourceTree = BUILT_PRODUCTS_DIR; };
32 | 0E1276A21ECCC257000BEC68 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
33 | 0E1276A41ECCC257000BEC68 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
34 | 0E1276A91ECCC257000BEC68 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
35 | 0E1276AC1ECCC257000BEC68 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
36 | 0E1276AE1ECCC257000BEC68 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
37 | 0E2BF1B01ECD674000FA6C58 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; };
38 | 0E2BF1B41ECD67AD00FA6C58 /* ImageCollectionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageCollectionViewController.swift; sourceTree = ""; };
39 | 0E2BF1E91ECD704E00FA6C58 /* UIView+Anchor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Anchor.swift"; sourceTree = ""; };
40 | 0E2BF1EB1ECD722800FA6C58 /* MMLayoutProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MMLayoutProtocol.swift; sourceTree = ""; };
41 | 0E2BF1ED1ECD723100FA6C58 /* MMCollectionViewFlowLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MMCollectionViewFlowLayout.swift; sourceTree = ""; };
42 | 0E2BF1EE1ECD723100FA6C58 /* MMCollectionViewLayoutAttributes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MMCollectionViewLayoutAttributes.swift; sourceTree = ""; };
43 | 0E2BF1F21ECD725800FA6C58 /* ParallaxAttributesTransition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParallaxAttributesTransition.swift; sourceTree = ""; };
44 | 0E2BF1F41ECD726400FA6C58 /* ZoomInOutAttributesTransition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZoomInOutAttributesTransition.swift; sourceTree = ""; };
45 | 0E2BF1F61ECD727400FA6C58 /* RotateInOutAttributesTransition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RotateInOutAttributesTransition.swift; sourceTree = ""; };
46 | 0E2BF1F81ECD728500FA6C58 /* LinearCardAttributesTransition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LinearCardAttributesTransition.swift; sourceTree = ""; };
47 | 0E2BF1FA1ECD729000FA6C58 /* CubeAttributesTransition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CubeAttributesTransition.swift; sourceTree = ""; };
48 | 0E2BF1FC1ECD729A00FA6C58 /* CrossFadeAttributesTransition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CrossFadeAttributesTransition.swift; sourceTree = ""; };
49 | 0E2BF1FE1ECD72B200FA6C58 /* TurnAttributesTransition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TurnAttributesTransition.swift; sourceTree = ""; };
50 | 0E2BF2001ECD72C200FA6C58 /* PageAttributesTransition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PageAttributesTransition.swift; sourceTree = ""; };
51 | /* End PBXFileReference section */
52 |
53 | /* Begin PBXFrameworksBuildPhase section */
54 | 0E12769C1ECCC257000BEC68 /* Frameworks */ = {
55 | isa = PBXFrameworksBuildPhase;
56 | buildActionMask = 2147483647;
57 | files = (
58 | );
59 | runOnlyForDeploymentPostprocessing = 0;
60 | };
61 | /* End PBXFrameworksBuildPhase section */
62 |
63 | /* Begin PBXGroup section */
64 | 0E1276961ECCC257000BEC68 = {
65 | isa = PBXGroup;
66 | children = (
67 | 0E1276A11ECCC257000BEC68 /* MMCollectionViewFlowLayout */,
68 | 0E1276A01ECCC257000BEC68 /* Products */,
69 | );
70 | sourceTree = "";
71 | };
72 | 0E1276A01ECCC257000BEC68 /* Products */ = {
73 | isa = PBXGroup;
74 | children = (
75 | 0E12769F1ECCC257000BEC68 /* MMCollectionViewFlowLayout.app */,
76 | );
77 | name = Products;
78 | sourceTree = "";
79 | };
80 | 0E1276A11ECCC257000BEC68 /* MMCollectionViewFlowLayout */ = {
81 | isa = PBXGroup;
82 | children = (
83 | 0E2BF1E51ECD6FF500FA6C58 /* MMCollectionViewFlowLayout */,
84 | 0E1276A21ECCC257000BEC68 /* AppDelegate.swift */,
85 | 0E1276A41ECCC257000BEC68 /* ViewController.swift */,
86 | 0E2BF1B41ECD67AD00FA6C58 /* ImageCollectionViewController.swift */,
87 | 0E2BF1B01ECD674000FA6C58 /* Main.storyboard */,
88 | 0E1276A91ECCC257000BEC68 /* Assets.xcassets */,
89 | 0E1276AB1ECCC257000BEC68 /* LaunchScreen.storyboard */,
90 | 0E1276AE1ECCC257000BEC68 /* Info.plist */,
91 | );
92 | path = MMCollectionViewFlowLayout;
93 | sourceTree = "";
94 | };
95 | 0E2BF1E51ECD6FF500FA6C58 /* MMCollectionViewFlowLayout */ = {
96 | isa = PBXGroup;
97 | children = (
98 | 0E2BF1F11ECD724100FA6C58 /* Transition */,
99 | 0E2BF1EB1ECD722800FA6C58 /* MMLayoutProtocol.swift */,
100 | 0E2BF1ED1ECD723100FA6C58 /* MMCollectionViewFlowLayout.swift */,
101 | 0E2BF1EE1ECD723100FA6C58 /* MMCollectionViewLayoutAttributes.swift */,
102 | 0E2BF1E91ECD704E00FA6C58 /* UIView+Anchor.swift */,
103 | );
104 | path = MMCollectionViewFlowLayout;
105 | sourceTree = "";
106 | };
107 | 0E2BF1F11ECD724100FA6C58 /* Transition */ = {
108 | isa = PBXGroup;
109 | children = (
110 | 0E2BF1F21ECD725800FA6C58 /* ParallaxAttributesTransition.swift */,
111 | 0E2BF1F41ECD726400FA6C58 /* ZoomInOutAttributesTransition.swift */,
112 | 0E2BF1F61ECD727400FA6C58 /* RotateInOutAttributesTransition.swift */,
113 | 0E2BF1F81ECD728500FA6C58 /* LinearCardAttributesTransition.swift */,
114 | 0E2BF1FA1ECD729000FA6C58 /* CubeAttributesTransition.swift */,
115 | 0E2BF1FC1ECD729A00FA6C58 /* CrossFadeAttributesTransition.swift */,
116 | 0E2BF1FE1ECD72B200FA6C58 /* TurnAttributesTransition.swift */,
117 | 0E2BF2001ECD72C200FA6C58 /* PageAttributesTransition.swift */,
118 | );
119 | path = Transition;
120 | sourceTree = "";
121 | };
122 | /* End PBXGroup section */
123 |
124 | /* Begin PBXNativeTarget section */
125 | 0E12769E1ECCC257000BEC68 /* MMCollectionViewFlowLayout */ = {
126 | isa = PBXNativeTarget;
127 | buildConfigurationList = 0E1276B11ECCC257000BEC68 /* Build configuration list for PBXNativeTarget "MMCollectionViewFlowLayout" */;
128 | buildPhases = (
129 | 0E12769B1ECCC257000BEC68 /* Sources */,
130 | 0E12769C1ECCC257000BEC68 /* Frameworks */,
131 | 0E12769D1ECCC257000BEC68 /* Resources */,
132 | );
133 | buildRules = (
134 | );
135 | dependencies = (
136 | );
137 | name = MMCollectionViewFlowLayout;
138 | productName = MMCollectionViewFlowLayout;
139 | productReference = 0E12769F1ECCC257000BEC68 /* MMCollectionViewFlowLayout.app */;
140 | productType = "com.apple.product-type.application";
141 | };
142 | /* End PBXNativeTarget section */
143 |
144 | /* Begin PBXProject section */
145 | 0E1276971ECCC257000BEC68 /* Project object */ = {
146 | isa = PBXProject;
147 | attributes = {
148 | LastSwiftUpdateCheck = 0830;
149 | LastUpgradeCheck = 0830;
150 | ORGANIZATIONNAME = Iean;
151 | TargetAttributes = {
152 | 0E12769E1ECCC257000BEC68 = {
153 | CreatedOnToolsVersion = 8.3.2;
154 | DevelopmentTeam = FMD48QW6R3;
155 | ProvisioningStyle = Automatic;
156 | };
157 | };
158 | };
159 | buildConfigurationList = 0E12769A1ECCC257000BEC68 /* Build configuration list for PBXProject "MMCollectionViewFlowLayout" */;
160 | compatibilityVersion = "Xcode 3.2";
161 | developmentRegion = English;
162 | hasScannedForEncodings = 0;
163 | knownRegions = (
164 | en,
165 | Base,
166 | );
167 | mainGroup = 0E1276961ECCC257000BEC68;
168 | productRefGroup = 0E1276A01ECCC257000BEC68 /* Products */;
169 | projectDirPath = "";
170 | projectRoot = "";
171 | targets = (
172 | 0E12769E1ECCC257000BEC68 /* MMCollectionViewFlowLayout */,
173 | );
174 | };
175 | /* End PBXProject section */
176 |
177 | /* Begin PBXResourcesBuildPhase section */
178 | 0E12769D1ECCC257000BEC68 /* Resources */ = {
179 | isa = PBXResourcesBuildPhase;
180 | buildActionMask = 2147483647;
181 | files = (
182 | 0E2BF1B11ECD674000FA6C58 /* Main.storyboard in Resources */,
183 | 0E1276AD1ECCC257000BEC68 /* LaunchScreen.storyboard in Resources */,
184 | 0E1276AA1ECCC257000BEC68 /* Assets.xcassets in Resources */,
185 | );
186 | runOnlyForDeploymentPostprocessing = 0;
187 | };
188 | /* End PBXResourcesBuildPhase section */
189 |
190 | /* Begin PBXSourcesBuildPhase section */
191 | 0E12769B1ECCC257000BEC68 /* Sources */ = {
192 | isa = PBXSourcesBuildPhase;
193 | buildActionMask = 2147483647;
194 | files = (
195 | 0E2BF1EF1ECD723100FA6C58 /* MMCollectionViewFlowLayout.swift in Sources */,
196 | 0E2BF1B51ECD67AD00FA6C58 /* ImageCollectionViewController.swift in Sources */,
197 | 0E2BF1EA1ECD704E00FA6C58 /* UIView+Anchor.swift in Sources */,
198 | 0E2BF1F51ECD726400FA6C58 /* ZoomInOutAttributesTransition.swift in Sources */,
199 | 0E2BF1EC1ECD722800FA6C58 /* MMLayoutProtocol.swift in Sources */,
200 | 0E2BF1F31ECD725800FA6C58 /* ParallaxAttributesTransition.swift in Sources */,
201 | 0E2BF1F71ECD727400FA6C58 /* RotateInOutAttributesTransition.swift in Sources */,
202 | 0E2BF1F91ECD728500FA6C58 /* LinearCardAttributesTransition.swift in Sources */,
203 | 0E1276A51ECCC257000BEC68 /* ViewController.swift in Sources */,
204 | 0E2BF1F01ECD723100FA6C58 /* MMCollectionViewLayoutAttributes.swift in Sources */,
205 | 0E2BF1FF1ECD72B200FA6C58 /* TurnAttributesTransition.swift in Sources */,
206 | 0E2BF1FD1ECD729A00FA6C58 /* CrossFadeAttributesTransition.swift in Sources */,
207 | 0E2BF1FB1ECD729000FA6C58 /* CubeAttributesTransition.swift in Sources */,
208 | 0E2BF2011ECD72C200FA6C58 /* PageAttributesTransition.swift in Sources */,
209 | 0E1276A31ECCC257000BEC68 /* AppDelegate.swift in Sources */,
210 | );
211 | runOnlyForDeploymentPostprocessing = 0;
212 | };
213 | /* End PBXSourcesBuildPhase section */
214 |
215 | /* Begin PBXVariantGroup section */
216 | 0E1276AB1ECCC257000BEC68 /* LaunchScreen.storyboard */ = {
217 | isa = PBXVariantGroup;
218 | children = (
219 | 0E1276AC1ECCC257000BEC68 /* Base */,
220 | );
221 | name = LaunchScreen.storyboard;
222 | sourceTree = "";
223 | };
224 | /* End PBXVariantGroup section */
225 |
226 | /* Begin XCBuildConfiguration section */
227 | 0E1276AF1ECCC257000BEC68 /* Debug */ = {
228 | isa = XCBuildConfiguration;
229 | buildSettings = {
230 | ALWAYS_SEARCH_USER_PATHS = NO;
231 | CLANG_ANALYZER_NONNULL = YES;
232 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
233 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
234 | CLANG_CXX_LIBRARY = "libc++";
235 | CLANG_ENABLE_MODULES = YES;
236 | CLANG_ENABLE_OBJC_ARC = YES;
237 | CLANG_WARN_BOOL_CONVERSION = YES;
238 | CLANG_WARN_CONSTANT_CONVERSION = YES;
239 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
240 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
241 | CLANG_WARN_EMPTY_BODY = YES;
242 | CLANG_WARN_ENUM_CONVERSION = YES;
243 | CLANG_WARN_INFINITE_RECURSION = YES;
244 | CLANG_WARN_INT_CONVERSION = YES;
245 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
246 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
247 | CLANG_WARN_UNREACHABLE_CODE = YES;
248 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
249 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
250 | COPY_PHASE_STRIP = NO;
251 | DEBUG_INFORMATION_FORMAT = dwarf;
252 | ENABLE_STRICT_OBJC_MSGSEND = YES;
253 | ENABLE_TESTABILITY = YES;
254 | GCC_C_LANGUAGE_STANDARD = gnu99;
255 | GCC_DYNAMIC_NO_PIC = NO;
256 | GCC_NO_COMMON_BLOCKS = YES;
257 | GCC_OPTIMIZATION_LEVEL = 0;
258 | GCC_PREPROCESSOR_DEFINITIONS = (
259 | "DEBUG=1",
260 | "$(inherited)",
261 | );
262 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
263 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
264 | GCC_WARN_UNDECLARED_SELECTOR = YES;
265 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
266 | GCC_WARN_UNUSED_FUNCTION = YES;
267 | GCC_WARN_UNUSED_VARIABLE = YES;
268 | IPHONEOS_DEPLOYMENT_TARGET = 10.3;
269 | MTL_ENABLE_DEBUG_INFO = YES;
270 | ONLY_ACTIVE_ARCH = YES;
271 | SDKROOT = iphoneos;
272 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
273 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
274 | TARGETED_DEVICE_FAMILY = "1,2";
275 | };
276 | name = Debug;
277 | };
278 | 0E1276B01ECCC257000BEC68 /* Release */ = {
279 | isa = XCBuildConfiguration;
280 | buildSettings = {
281 | ALWAYS_SEARCH_USER_PATHS = NO;
282 | CLANG_ANALYZER_NONNULL = YES;
283 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
284 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
285 | CLANG_CXX_LIBRARY = "libc++";
286 | CLANG_ENABLE_MODULES = YES;
287 | CLANG_ENABLE_OBJC_ARC = YES;
288 | CLANG_WARN_BOOL_CONVERSION = YES;
289 | CLANG_WARN_CONSTANT_CONVERSION = YES;
290 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
291 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
292 | CLANG_WARN_EMPTY_BODY = YES;
293 | CLANG_WARN_ENUM_CONVERSION = YES;
294 | CLANG_WARN_INFINITE_RECURSION = YES;
295 | CLANG_WARN_INT_CONVERSION = YES;
296 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
297 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
298 | CLANG_WARN_UNREACHABLE_CODE = YES;
299 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
300 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
301 | COPY_PHASE_STRIP = NO;
302 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
303 | ENABLE_NS_ASSERTIONS = NO;
304 | ENABLE_STRICT_OBJC_MSGSEND = YES;
305 | GCC_C_LANGUAGE_STANDARD = gnu99;
306 | GCC_NO_COMMON_BLOCKS = YES;
307 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
308 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
309 | GCC_WARN_UNDECLARED_SELECTOR = YES;
310 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
311 | GCC_WARN_UNUSED_FUNCTION = YES;
312 | GCC_WARN_UNUSED_VARIABLE = YES;
313 | IPHONEOS_DEPLOYMENT_TARGET = 10.3;
314 | MTL_ENABLE_DEBUG_INFO = NO;
315 | SDKROOT = iphoneos;
316 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
317 | TARGETED_DEVICE_FAMILY = "1,2";
318 | VALIDATE_PRODUCT = YES;
319 | };
320 | name = Release;
321 | };
322 | 0E1276B21ECCC257000BEC68 /* Debug */ = {
323 | isa = XCBuildConfiguration;
324 | buildSettings = {
325 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
326 | DEVELOPMENT_TEAM = FMD48QW6R3;
327 | INFOPLIST_FILE = MMCollectionViewFlowLayout/Info.plist;
328 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
329 | PRODUCT_BUNDLE_IDENTIFIER = com.edsum.www.MMCollectionViewFlowLayout;
330 | PRODUCT_NAME = "$(TARGET_NAME)";
331 | SWIFT_VERSION = 3.0;
332 | };
333 | name = Debug;
334 | };
335 | 0E1276B31ECCC257000BEC68 /* Release */ = {
336 | isa = XCBuildConfiguration;
337 | buildSettings = {
338 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
339 | DEVELOPMENT_TEAM = FMD48QW6R3;
340 | INFOPLIST_FILE = MMCollectionViewFlowLayout/Info.plist;
341 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
342 | PRODUCT_BUNDLE_IDENTIFIER = com.edsum.www.MMCollectionViewFlowLayout;
343 | PRODUCT_NAME = "$(TARGET_NAME)";
344 | SWIFT_VERSION = 3.0;
345 | };
346 | name = Release;
347 | };
348 | /* End XCBuildConfiguration section */
349 |
350 | /* Begin XCConfigurationList section */
351 | 0E12769A1ECCC257000BEC68 /* Build configuration list for PBXProject "MMCollectionViewFlowLayout" */ = {
352 | isa = XCConfigurationList;
353 | buildConfigurations = (
354 | 0E1276AF1ECCC257000BEC68 /* Debug */,
355 | 0E1276B01ECCC257000BEC68 /* Release */,
356 | );
357 | defaultConfigurationIsVisible = 0;
358 | defaultConfigurationName = Release;
359 | };
360 | 0E1276B11ECCC257000BEC68 /* Build configuration list for PBXNativeTarget "MMCollectionViewFlowLayout" */ = {
361 | isa = XCConfigurationList;
362 | buildConfigurations = (
363 | 0E1276B21ECCC257000BEC68 /* Debug */,
364 | 0E1276B31ECCC257000BEC68 /* Release */,
365 | );
366 | defaultConfigurationIsVisible = 0;
367 | defaultConfigurationName = Release;
368 | };
369 | /* End XCConfigurationList section */
370 | };
371 | rootObject = 0E1276971ECCC257000BEC68 /* Project object */;
372 | }
373 |
--------------------------------------------------------------------------------