├── .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 | - ![Parallax](http://img.blog.csdn.net/20170518220642054?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxNDc5NTAyMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) ![Cards](http://img.blog.csdn.net/20170518220941102?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxNDc5NTAyMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) ![CrossFade](http://img.blog.csdn.net/20170518221001128?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxNDc5NTAyMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) ![Cube](http://img.blog.csdn.net/20170518221027300?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxNDc5NTAyMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) ![Page](http://img.blog.csdn.net/20170518221053520?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxNDc5NTAyMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) ![RotateInOut](http://img.blog.csdn.net/20170518221110744?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxNDc5NTAyMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) ![ZoomInOut](http://img.blog.csdn.net/20170518221132005?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxNDc5NTAyMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 6 | 7 | # 使用方法 8 | * 下载项目到本地:方式一: 9 | 终端输入: $ git clone https://github.com/edsum/MMCollectionViewFlowLayout 10 | 方式二: 如下图 11 | ![这里写图片描述](http://img.blog.csdn.net/20170518145034096?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxNDc5NTAyMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 12 | 13 | * 把 `MMCollectionViewFlowLayout`文件夹拖入项目 14 | ![需要的类文件都在这里](http://img.blog.csdn.net/20170518144346523?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxNDc5NTAyMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 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 | --------------------------------------------------------------------------------