├── .gitignore ├── JHCollectionViewLayout.podspec ├── JHCollectionViewLayout ├── JHCollectionViewLayout.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata ├── JHCollectionViewLayout │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── Class │ │ ├── JHHorizontalPageFlowlayout.h │ │ ├── JHHorizontalPageFlowlayout.m │ │ ├── JHWaterfallCollectionLayout.h │ │ └── JHWaterfallCollectionLayout.m │ ├── Demo │ │ ├── BaseViewController.h │ │ ├── BaseViewController.m │ │ ├── HorizontalPageViewController.h │ │ ├── HorizontalPageViewController.m │ │ ├── JHCollectionViewCell.h │ │ ├── JHCollectionViewCell.m │ │ ├── JHCollectionViewCell.xib │ │ ├── WaterfallViewController.h │ │ └── WaterfallViewController.m │ ├── Info.plist │ ├── ViewController.h │ ├── ViewController.m │ └── main.m ├── JHCollectionViewLayoutTests │ ├── Info.plist │ └── JHCollectionViewLayoutTests.m └── JHCollectionViewLayoutUITests │ ├── Info.plist │ └── JHCollectionViewLayoutUITests.m ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | # CocoaPods 32 | # 33 | # We recommend against adding the Pods directory to your .gitignore. However 34 | # you should judge for yourself, the pros and cons are mentioned at: 35 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 36 | # 37 | # Pods/ 38 | 39 | # Carthage 40 | # 41 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 42 | # Carthage/Checkouts 43 | 44 | Carthage/Build 45 | 46 | # fastlane 47 | # 48 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 49 | # screenshots whenever they are needed. 50 | # For more information about the recommended setup visit: 51 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 52 | 53 | fastlane/report.xml 54 | fastlane/Preview.html 55 | fastlane/screenshots 56 | fastlane/test_output 57 | 58 | # Code Injection 59 | # 60 | # After new code Injection tools there's a generated folder /iOSInjectionProject 61 | # https://github.com/johnno1962/injectionforxcode 62 | 63 | iOSInjectionProject/ 64 | -------------------------------------------------------------------------------- /JHCollectionViewLayout.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod spec lint JHCollectionViewLayout.podspec' to ensure this is a 3 | # valid spec and to remove all comments including this before submitting the spec. 4 | # 5 | # To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html 6 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/ 7 | # 8 | 9 | Pod::Spec.new do |s| 10 | 11 | # ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 12 | # 13 | # These will help people to find your library, and whilst it 14 | # can feel like a chore to fill in it's definitely to your advantage. The 15 | # summary should be tweet-length, and the description more in depth. 16 | # 17 | 18 | s.name = "JHCollectionViewLayout" 19 | s.version = "0.0.1" 20 | s.summary = "collectionView的横向布局和瀑布流" 21 | 22 | # This description is used to generate tags and improve search results. 23 | # * Think: What does it do? Why did you write it? What is the focus? 24 | # * Try to keep it short, snappy and to the point. 25 | # * Write the description between the DESC delimiters below. 26 | # * Finally, don't worry about the indent, CocoaPods strips it! 27 | s.description = <<-DESC 28 | collectionView的横向布局和瀑布流,collectionView的横向布局和瀑布流 29 | DESC 30 | s.homepage = "https://github.com/huangjianwengit/JHCollectionViewLayout" 31 | # s.screenshots = "www.example.com/screenshots_1.gif", "www.example.com/screenshots_2.gif" 32 | 33 | 34 | # ――― Spec License ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 35 | # 36 | # Licensing your code is important. See http://choosealicense.com for more info. 37 | # CocoaPods will detect a license file if there is a named LICENSE* 38 | # Popular ones are 'MIT', 'BSD' and 'Apache License, Version 2.0'. 39 | # 40 | 41 | #s.license = "MIT (example)" 42 | s.license = { :type => "MIT", :file => "LICENSE" } 43 | 44 | 45 | # ――― Author Metadata ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 46 | # 47 | # Specify the authors of the library, with email addresses. Email addresses 48 | # of the authors are extracted from the SCM log. E.g. $ git log. CocoaPods also 49 | # accepts just a name if you'd rather not provide an email address. 50 | # 51 | # Specify a social_media_url where others can refer to, for example a twitter 52 | # profile URL. 53 | # 54 | 55 | s.author = { "Jivan-ios" => "1330336393@qq.com" } 56 | # Or just: s.author = "Jivan-ios" 57 | # s.authors = { "Jivan-ios" => "1330336393@qq.com" } 58 | # s.social_media_url = "http://twitter.com/Jivan-ios" 59 | 60 | # ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 61 | # 62 | # If this Pod runs only on iOS or OS X, then specify the platform and 63 | # the deployment target. You can optionally include the target after the platform. 64 | # 65 | 66 | # s.platform = :ios 67 | s.platform = :ios, "8.0" 68 | 69 | # When using multiple platforms 70 | # s.ios.deployment_target = "5.0" 71 | # s.osx.deployment_target = "10.7" 72 | # s.watchos.deployment_target = "2.0" 73 | # s.tvos.deployment_target = "9.0" 74 | 75 | 76 | # ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 77 | # 78 | # Specify the location from where the source should be retrieved. 79 | # Supports git, hg, bzr, svn and HTTP. 80 | # 81 | 82 | s.source = { :git => "https://github.com/huangjianwengit/JHCollectionViewLayout.git", :tag => "#{s.version}" } 83 | 84 | 85 | # ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 86 | # 87 | # CocoaPods is smart about how it includes source code. For source files 88 | # giving a folder will include any swift, h, m, mm, c & cpp files. 89 | # For header files it will include any header in the folder. 90 | # Not including the public_header_files will make all headers public. 91 | # 92 | 93 | s.source_files = "Class", "JHCollectionViewLayout/JHCollectionViewLayout/Class/**/*.{h,m}" 94 | #s.exclude_files = "Classes/Exclude" 95 | 96 | # s.public_header_files = "Classes/**/*.h" 97 | 98 | 99 | # ――― Resources ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 100 | # 101 | # A list of resources included with the Pod. These are copied into the 102 | # target bundle with a build phase script. Anything else will be cleaned. 103 | # You can preserve files from being cleaned, please don't preserve 104 | # non-essential files like tests, examples and documentation. 105 | # 106 | 107 | # s.resource = "icon.png" 108 | # s.resources = "Resources/*.png" 109 | 110 | # s.preserve_paths = "FilesToSave", "MoreFilesToSave" 111 | 112 | 113 | # ――― Project Linking ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 114 | # 115 | # Link your library with frameworks, or libraries. Libraries do not include 116 | # the lib prefix of their name. 117 | # 118 | 119 | s.framework = "UIKit" 120 | # s.frameworks = "SomeFramework", "AnotherFramework" 121 | 122 | # s.library = "iconv" 123 | # s.libraries = "iconv", "xml2" 124 | 125 | 126 | # ――― Project Settings ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 127 | # 128 | # If your library depends on compiler flags you can set them in the xcconfig hash 129 | # where they will only apply to your library. If you depend on other Podspecs 130 | # you can include multiple dependencies to ensure it works. 131 | 132 | # s.requires_arc = true 133 | 134 | # s.xcconfig = { "HEADER_SEARCH_PATHS" => "$(SDKROOT)/usr/include/libxml2" } 135 | # s.dependency "JSONKit", "~> 1.4" 136 | 137 | end 138 | -------------------------------------------------------------------------------- /JHCollectionViewLayout/JHCollectionViewLayout.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 8C816A161FF09FBF00392890 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C816A151FF09FBF00392890 /* AppDelegate.m */; }; 11 | 8C816A191FF09FBF00392890 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C816A181FF09FBF00392890 /* ViewController.m */; }; 12 | 8C816A1C1FF09FBF00392890 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8C816A1A1FF09FBF00392890 /* Main.storyboard */; }; 13 | 8C816A1E1FF09FBF00392890 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8C816A1D1FF09FBF00392890 /* Assets.xcassets */; }; 14 | 8C816A211FF09FBF00392890 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8C816A1F1FF09FBF00392890 /* LaunchScreen.storyboard */; }; 15 | 8C816A241FF09FBF00392890 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C816A231FF09FBF00392890 /* main.m */; }; 16 | 8C816A2E1FF09FC000392890 /* JHCollectionViewLayoutTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C816A2D1FF09FC000392890 /* JHCollectionViewLayoutTests.m */; }; 17 | 8C816A391FF09FC000392890 /* JHCollectionViewLayoutUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C816A381FF09FC000392890 /* JHCollectionViewLayoutUITests.m */; }; 18 | 8C816A491FF0A03600392890 /* JHWaterfallCollectionLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C816A481FF0A03600392890 /* JHWaterfallCollectionLayout.m */; }; 19 | 8C816A4D1FF0A10D00392890 /* WaterfallViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C816A4C1FF0A10D00392890 /* WaterfallViewController.m */; }; 20 | 8C816A511FF0A15200392890 /* JHCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C816A4E1FF0A15200392890 /* JHCollectionViewCell.m */; }; 21 | 8C816A521FF0A15200392890 /* JHCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 8C816A4F1FF0A15200392890 /* JHCollectionViewCell.xib */; }; 22 | 8C816A551FF0A30E00392890 /* JHHorizontalPageFlowlayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C816A541FF0A30E00392890 /* JHHorizontalPageFlowlayout.m */; }; 23 | 8C816A581FF0A38100392890 /* HorizontalPageViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C816A571FF0A38100392890 /* HorizontalPageViewController.m */; }; 24 | 8C816A5B1FF0AC2700392890 /* BaseViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C816A5A1FF0AC2700392890 /* BaseViewController.m */; }; 25 | /* End PBXBuildFile section */ 26 | 27 | /* Begin PBXContainerItemProxy section */ 28 | 8C816A2A1FF09FC000392890 /* PBXContainerItemProxy */ = { 29 | isa = PBXContainerItemProxy; 30 | containerPortal = 8C816A091FF09FBF00392890 /* Project object */; 31 | proxyType = 1; 32 | remoteGlobalIDString = 8C816A101FF09FBF00392890; 33 | remoteInfo = JHCollectionViewLayout; 34 | }; 35 | 8C816A351FF09FC000392890 /* PBXContainerItemProxy */ = { 36 | isa = PBXContainerItemProxy; 37 | containerPortal = 8C816A091FF09FBF00392890 /* Project object */; 38 | proxyType = 1; 39 | remoteGlobalIDString = 8C816A101FF09FBF00392890; 40 | remoteInfo = JHCollectionViewLayout; 41 | }; 42 | /* End PBXContainerItemProxy section */ 43 | 44 | /* Begin PBXFileReference section */ 45 | 8C816A111FF09FBF00392890 /* JHCollectionViewLayout.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JHCollectionViewLayout.app; sourceTree = BUILT_PRODUCTS_DIR; }; 46 | 8C816A141FF09FBF00392890 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 47 | 8C816A151FF09FBF00392890 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 48 | 8C816A171FF09FBF00392890 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 49 | 8C816A181FF09FBF00392890 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 50 | 8C816A1B1FF09FBF00392890 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 51 | 8C816A1D1FF09FBF00392890 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 52 | 8C816A201FF09FBF00392890 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 53 | 8C816A221FF09FBF00392890 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 54 | 8C816A231FF09FBF00392890 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 55 | 8C816A291FF09FC000392890 /* JHCollectionViewLayoutTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = JHCollectionViewLayoutTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 56 | 8C816A2D1FF09FC000392890 /* JHCollectionViewLayoutTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JHCollectionViewLayoutTests.m; sourceTree = ""; }; 57 | 8C816A2F1FF09FC000392890 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 58 | 8C816A341FF09FC000392890 /* JHCollectionViewLayoutUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = JHCollectionViewLayoutUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 59 | 8C816A381FF09FC000392890 /* JHCollectionViewLayoutUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JHCollectionViewLayoutUITests.m; sourceTree = ""; }; 60 | 8C816A3A1FF09FC000392890 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 61 | 8C816A471FF0A03600392890 /* JHWaterfallCollectionLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JHWaterfallCollectionLayout.h; sourceTree = ""; }; 62 | 8C816A481FF0A03600392890 /* JHWaterfallCollectionLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JHWaterfallCollectionLayout.m; sourceTree = ""; }; 63 | 8C816A4B1FF0A10D00392890 /* WaterfallViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WaterfallViewController.h; sourceTree = ""; }; 64 | 8C816A4C1FF0A10D00392890 /* WaterfallViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WaterfallViewController.m; sourceTree = ""; }; 65 | 8C816A4E1FF0A15200392890 /* JHCollectionViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JHCollectionViewCell.m; sourceTree = ""; }; 66 | 8C816A4F1FF0A15200392890 /* JHCollectionViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = JHCollectionViewCell.xib; sourceTree = ""; }; 67 | 8C816A501FF0A15200392890 /* JHCollectionViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JHCollectionViewCell.h; sourceTree = ""; }; 68 | 8C816A531FF0A30E00392890 /* JHHorizontalPageFlowlayout.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JHHorizontalPageFlowlayout.h; sourceTree = ""; }; 69 | 8C816A541FF0A30E00392890 /* JHHorizontalPageFlowlayout.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JHHorizontalPageFlowlayout.m; sourceTree = ""; }; 70 | 8C816A561FF0A38100392890 /* HorizontalPageViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HorizontalPageViewController.h; sourceTree = ""; }; 71 | 8C816A571FF0A38100392890 /* HorizontalPageViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HorizontalPageViewController.m; sourceTree = ""; }; 72 | 8C816A591FF0AC2700392890 /* BaseViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BaseViewController.h; sourceTree = ""; }; 73 | 8C816A5A1FF0AC2700392890 /* BaseViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BaseViewController.m; sourceTree = ""; }; 74 | /* End PBXFileReference section */ 75 | 76 | /* Begin PBXFrameworksBuildPhase section */ 77 | 8C816A0E1FF09FBF00392890 /* Frameworks */ = { 78 | isa = PBXFrameworksBuildPhase; 79 | buildActionMask = 2147483647; 80 | files = ( 81 | ); 82 | runOnlyForDeploymentPostprocessing = 0; 83 | }; 84 | 8C816A261FF09FC000392890 /* Frameworks */ = { 85 | isa = PBXFrameworksBuildPhase; 86 | buildActionMask = 2147483647; 87 | files = ( 88 | ); 89 | runOnlyForDeploymentPostprocessing = 0; 90 | }; 91 | 8C816A311FF09FC000392890 /* Frameworks */ = { 92 | isa = PBXFrameworksBuildPhase; 93 | buildActionMask = 2147483647; 94 | files = ( 95 | ); 96 | runOnlyForDeploymentPostprocessing = 0; 97 | }; 98 | /* End PBXFrameworksBuildPhase section */ 99 | 100 | /* Begin PBXGroup section */ 101 | 8C816A081FF09FBF00392890 = { 102 | isa = PBXGroup; 103 | children = ( 104 | 8C816A131FF09FBF00392890 /* JHCollectionViewLayout */, 105 | 8C816A2C1FF09FC000392890 /* JHCollectionViewLayoutTests */, 106 | 8C816A371FF09FC000392890 /* JHCollectionViewLayoutUITests */, 107 | 8C816A121FF09FBF00392890 /* Products */, 108 | ); 109 | sourceTree = ""; 110 | }; 111 | 8C816A121FF09FBF00392890 /* Products */ = { 112 | isa = PBXGroup; 113 | children = ( 114 | 8C816A111FF09FBF00392890 /* JHCollectionViewLayout.app */, 115 | 8C816A291FF09FC000392890 /* JHCollectionViewLayoutTests.xctest */, 116 | 8C816A341FF09FC000392890 /* JHCollectionViewLayoutUITests.xctest */, 117 | ); 118 | name = Products; 119 | sourceTree = ""; 120 | }; 121 | 8C816A131FF09FBF00392890 /* JHCollectionViewLayout */ = { 122 | isa = PBXGroup; 123 | children = ( 124 | 8C816A4A1FF0A0B600392890 /* Demo */, 125 | 8C816A461FF0A02A00392890 /* Class */, 126 | 8C816A141FF09FBF00392890 /* AppDelegate.h */, 127 | 8C816A151FF09FBF00392890 /* AppDelegate.m */, 128 | 8C816A171FF09FBF00392890 /* ViewController.h */, 129 | 8C816A181FF09FBF00392890 /* ViewController.m */, 130 | 8C816A1A1FF09FBF00392890 /* Main.storyboard */, 131 | 8C816A1D1FF09FBF00392890 /* Assets.xcassets */, 132 | 8C816A1F1FF09FBF00392890 /* LaunchScreen.storyboard */, 133 | 8C816A221FF09FBF00392890 /* Info.plist */, 134 | 8C816A231FF09FBF00392890 /* main.m */, 135 | ); 136 | path = JHCollectionViewLayout; 137 | sourceTree = ""; 138 | }; 139 | 8C816A2C1FF09FC000392890 /* JHCollectionViewLayoutTests */ = { 140 | isa = PBXGroup; 141 | children = ( 142 | 8C816A2D1FF09FC000392890 /* JHCollectionViewLayoutTests.m */, 143 | 8C816A2F1FF09FC000392890 /* Info.plist */, 144 | ); 145 | path = JHCollectionViewLayoutTests; 146 | sourceTree = ""; 147 | }; 148 | 8C816A371FF09FC000392890 /* JHCollectionViewLayoutUITests */ = { 149 | isa = PBXGroup; 150 | children = ( 151 | 8C816A381FF09FC000392890 /* JHCollectionViewLayoutUITests.m */, 152 | 8C816A3A1FF09FC000392890 /* Info.plist */, 153 | ); 154 | path = JHCollectionViewLayoutUITests; 155 | sourceTree = ""; 156 | }; 157 | 8C816A461FF0A02A00392890 /* Class */ = { 158 | isa = PBXGroup; 159 | children = ( 160 | 8C816A471FF0A03600392890 /* JHWaterfallCollectionLayout.h */, 161 | 8C816A481FF0A03600392890 /* JHWaterfallCollectionLayout.m */, 162 | 8C816A531FF0A30E00392890 /* JHHorizontalPageFlowlayout.h */, 163 | 8C816A541FF0A30E00392890 /* JHHorizontalPageFlowlayout.m */, 164 | ); 165 | path = Class; 166 | sourceTree = ""; 167 | }; 168 | 8C816A4A1FF0A0B600392890 /* Demo */ = { 169 | isa = PBXGroup; 170 | children = ( 171 | 8C816A501FF0A15200392890 /* JHCollectionViewCell.h */, 172 | 8C816A4E1FF0A15200392890 /* JHCollectionViewCell.m */, 173 | 8C816A4F1FF0A15200392890 /* JHCollectionViewCell.xib */, 174 | 8C816A4B1FF0A10D00392890 /* WaterfallViewController.h */, 175 | 8C816A4C1FF0A10D00392890 /* WaterfallViewController.m */, 176 | 8C816A561FF0A38100392890 /* HorizontalPageViewController.h */, 177 | 8C816A571FF0A38100392890 /* HorizontalPageViewController.m */, 178 | 8C816A591FF0AC2700392890 /* BaseViewController.h */, 179 | 8C816A5A1FF0AC2700392890 /* BaseViewController.m */, 180 | ); 181 | path = Demo; 182 | sourceTree = ""; 183 | }; 184 | /* End PBXGroup section */ 185 | 186 | /* Begin PBXNativeTarget section */ 187 | 8C816A101FF09FBF00392890 /* JHCollectionViewLayout */ = { 188 | isa = PBXNativeTarget; 189 | buildConfigurationList = 8C816A3D1FF09FC000392890 /* Build configuration list for PBXNativeTarget "JHCollectionViewLayout" */; 190 | buildPhases = ( 191 | 8C816A0D1FF09FBF00392890 /* Sources */, 192 | 8C816A0E1FF09FBF00392890 /* Frameworks */, 193 | 8C816A0F1FF09FBF00392890 /* Resources */, 194 | ); 195 | buildRules = ( 196 | ); 197 | dependencies = ( 198 | ); 199 | name = JHCollectionViewLayout; 200 | productName = JHCollectionViewLayout; 201 | productReference = 8C816A111FF09FBF00392890 /* JHCollectionViewLayout.app */; 202 | productType = "com.apple.product-type.application"; 203 | }; 204 | 8C816A281FF09FC000392890 /* JHCollectionViewLayoutTests */ = { 205 | isa = PBXNativeTarget; 206 | buildConfigurationList = 8C816A401FF09FC000392890 /* Build configuration list for PBXNativeTarget "JHCollectionViewLayoutTests" */; 207 | buildPhases = ( 208 | 8C816A251FF09FC000392890 /* Sources */, 209 | 8C816A261FF09FC000392890 /* Frameworks */, 210 | 8C816A271FF09FC000392890 /* Resources */, 211 | ); 212 | buildRules = ( 213 | ); 214 | dependencies = ( 215 | 8C816A2B1FF09FC000392890 /* PBXTargetDependency */, 216 | ); 217 | name = JHCollectionViewLayoutTests; 218 | productName = JHCollectionViewLayoutTests; 219 | productReference = 8C816A291FF09FC000392890 /* JHCollectionViewLayoutTests.xctest */; 220 | productType = "com.apple.product-type.bundle.unit-test"; 221 | }; 222 | 8C816A331FF09FC000392890 /* JHCollectionViewLayoutUITests */ = { 223 | isa = PBXNativeTarget; 224 | buildConfigurationList = 8C816A431FF09FC000392890 /* Build configuration list for PBXNativeTarget "JHCollectionViewLayoutUITests" */; 225 | buildPhases = ( 226 | 8C816A301FF09FC000392890 /* Sources */, 227 | 8C816A311FF09FC000392890 /* Frameworks */, 228 | 8C816A321FF09FC000392890 /* Resources */, 229 | ); 230 | buildRules = ( 231 | ); 232 | dependencies = ( 233 | 8C816A361FF09FC000392890 /* PBXTargetDependency */, 234 | ); 235 | name = JHCollectionViewLayoutUITests; 236 | productName = JHCollectionViewLayoutUITests; 237 | productReference = 8C816A341FF09FC000392890 /* JHCollectionViewLayoutUITests.xctest */; 238 | productType = "com.apple.product-type.bundle.ui-testing"; 239 | }; 240 | /* End PBXNativeTarget section */ 241 | 242 | /* Begin PBXProject section */ 243 | 8C816A091FF09FBF00392890 /* Project object */ = { 244 | isa = PBXProject; 245 | attributes = { 246 | LastUpgradeCheck = 0920; 247 | ORGANIZATIONNAME = Jivan; 248 | TargetAttributes = { 249 | 8C816A101FF09FBF00392890 = { 250 | CreatedOnToolsVersion = 9.2; 251 | ProvisioningStyle = Automatic; 252 | }; 253 | 8C816A281FF09FC000392890 = { 254 | CreatedOnToolsVersion = 9.2; 255 | ProvisioningStyle = Automatic; 256 | TestTargetID = 8C816A101FF09FBF00392890; 257 | }; 258 | 8C816A331FF09FC000392890 = { 259 | CreatedOnToolsVersion = 9.2; 260 | ProvisioningStyle = Automatic; 261 | TestTargetID = 8C816A101FF09FBF00392890; 262 | }; 263 | }; 264 | }; 265 | buildConfigurationList = 8C816A0C1FF09FBF00392890 /* Build configuration list for PBXProject "JHCollectionViewLayout" */; 266 | compatibilityVersion = "Xcode 8.0"; 267 | developmentRegion = en; 268 | hasScannedForEncodings = 0; 269 | knownRegions = ( 270 | en, 271 | Base, 272 | ); 273 | mainGroup = 8C816A081FF09FBF00392890; 274 | productRefGroup = 8C816A121FF09FBF00392890 /* Products */; 275 | projectDirPath = ""; 276 | projectRoot = ""; 277 | targets = ( 278 | 8C816A101FF09FBF00392890 /* JHCollectionViewLayout */, 279 | 8C816A281FF09FC000392890 /* JHCollectionViewLayoutTests */, 280 | 8C816A331FF09FC000392890 /* JHCollectionViewLayoutUITests */, 281 | ); 282 | }; 283 | /* End PBXProject section */ 284 | 285 | /* Begin PBXResourcesBuildPhase section */ 286 | 8C816A0F1FF09FBF00392890 /* Resources */ = { 287 | isa = PBXResourcesBuildPhase; 288 | buildActionMask = 2147483647; 289 | files = ( 290 | 8C816A211FF09FBF00392890 /* LaunchScreen.storyboard in Resources */, 291 | 8C816A1E1FF09FBF00392890 /* Assets.xcassets in Resources */, 292 | 8C816A521FF0A15200392890 /* JHCollectionViewCell.xib in Resources */, 293 | 8C816A1C1FF09FBF00392890 /* Main.storyboard in Resources */, 294 | ); 295 | runOnlyForDeploymentPostprocessing = 0; 296 | }; 297 | 8C816A271FF09FC000392890 /* Resources */ = { 298 | isa = PBXResourcesBuildPhase; 299 | buildActionMask = 2147483647; 300 | files = ( 301 | ); 302 | runOnlyForDeploymentPostprocessing = 0; 303 | }; 304 | 8C816A321FF09FC000392890 /* Resources */ = { 305 | isa = PBXResourcesBuildPhase; 306 | buildActionMask = 2147483647; 307 | files = ( 308 | ); 309 | runOnlyForDeploymentPostprocessing = 0; 310 | }; 311 | /* End PBXResourcesBuildPhase section */ 312 | 313 | /* Begin PBXSourcesBuildPhase section */ 314 | 8C816A0D1FF09FBF00392890 /* Sources */ = { 315 | isa = PBXSourcesBuildPhase; 316 | buildActionMask = 2147483647; 317 | files = ( 318 | 8C816A511FF0A15200392890 /* JHCollectionViewCell.m in Sources */, 319 | 8C816A5B1FF0AC2700392890 /* BaseViewController.m in Sources */, 320 | 8C816A191FF09FBF00392890 /* ViewController.m in Sources */, 321 | 8C816A241FF09FBF00392890 /* main.m in Sources */, 322 | 8C816A551FF0A30E00392890 /* JHHorizontalPageFlowlayout.m in Sources */, 323 | 8C816A4D1FF0A10D00392890 /* WaterfallViewController.m in Sources */, 324 | 8C816A491FF0A03600392890 /* JHWaterfallCollectionLayout.m in Sources */, 325 | 8C816A161FF09FBF00392890 /* AppDelegate.m in Sources */, 326 | 8C816A581FF0A38100392890 /* HorizontalPageViewController.m in Sources */, 327 | ); 328 | runOnlyForDeploymentPostprocessing = 0; 329 | }; 330 | 8C816A251FF09FC000392890 /* Sources */ = { 331 | isa = PBXSourcesBuildPhase; 332 | buildActionMask = 2147483647; 333 | files = ( 334 | 8C816A2E1FF09FC000392890 /* JHCollectionViewLayoutTests.m in Sources */, 335 | ); 336 | runOnlyForDeploymentPostprocessing = 0; 337 | }; 338 | 8C816A301FF09FC000392890 /* Sources */ = { 339 | isa = PBXSourcesBuildPhase; 340 | buildActionMask = 2147483647; 341 | files = ( 342 | 8C816A391FF09FC000392890 /* JHCollectionViewLayoutUITests.m in Sources */, 343 | ); 344 | runOnlyForDeploymentPostprocessing = 0; 345 | }; 346 | /* End PBXSourcesBuildPhase section */ 347 | 348 | /* Begin PBXTargetDependency section */ 349 | 8C816A2B1FF09FC000392890 /* PBXTargetDependency */ = { 350 | isa = PBXTargetDependency; 351 | target = 8C816A101FF09FBF00392890 /* JHCollectionViewLayout */; 352 | targetProxy = 8C816A2A1FF09FC000392890 /* PBXContainerItemProxy */; 353 | }; 354 | 8C816A361FF09FC000392890 /* PBXTargetDependency */ = { 355 | isa = PBXTargetDependency; 356 | target = 8C816A101FF09FBF00392890 /* JHCollectionViewLayout */; 357 | targetProxy = 8C816A351FF09FC000392890 /* PBXContainerItemProxy */; 358 | }; 359 | /* End PBXTargetDependency section */ 360 | 361 | /* Begin PBXVariantGroup section */ 362 | 8C816A1A1FF09FBF00392890 /* Main.storyboard */ = { 363 | isa = PBXVariantGroup; 364 | children = ( 365 | 8C816A1B1FF09FBF00392890 /* Base */, 366 | ); 367 | name = Main.storyboard; 368 | sourceTree = ""; 369 | }; 370 | 8C816A1F1FF09FBF00392890 /* LaunchScreen.storyboard */ = { 371 | isa = PBXVariantGroup; 372 | children = ( 373 | 8C816A201FF09FBF00392890 /* Base */, 374 | ); 375 | name = LaunchScreen.storyboard; 376 | sourceTree = ""; 377 | }; 378 | /* End PBXVariantGroup section */ 379 | 380 | /* Begin XCBuildConfiguration section */ 381 | 8C816A3B1FF09FC000392890 /* Debug */ = { 382 | isa = XCBuildConfiguration; 383 | buildSettings = { 384 | ALWAYS_SEARCH_USER_PATHS = NO; 385 | CLANG_ANALYZER_NONNULL = YES; 386 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 387 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 388 | CLANG_CXX_LIBRARY = "libc++"; 389 | CLANG_ENABLE_MODULES = YES; 390 | CLANG_ENABLE_OBJC_ARC = YES; 391 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 392 | CLANG_WARN_BOOL_CONVERSION = YES; 393 | CLANG_WARN_COMMA = YES; 394 | CLANG_WARN_CONSTANT_CONVERSION = YES; 395 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 396 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 397 | CLANG_WARN_EMPTY_BODY = YES; 398 | CLANG_WARN_ENUM_CONVERSION = YES; 399 | CLANG_WARN_INFINITE_RECURSION = YES; 400 | CLANG_WARN_INT_CONVERSION = YES; 401 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 402 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 403 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 404 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 405 | CLANG_WARN_STRICT_PROTOTYPES = YES; 406 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 407 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 408 | CLANG_WARN_UNREACHABLE_CODE = YES; 409 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 410 | CODE_SIGN_IDENTITY = "iPhone Developer"; 411 | COPY_PHASE_STRIP = NO; 412 | DEBUG_INFORMATION_FORMAT = dwarf; 413 | ENABLE_STRICT_OBJC_MSGSEND = YES; 414 | ENABLE_TESTABILITY = YES; 415 | GCC_C_LANGUAGE_STANDARD = gnu11; 416 | GCC_DYNAMIC_NO_PIC = NO; 417 | GCC_NO_COMMON_BLOCKS = YES; 418 | GCC_OPTIMIZATION_LEVEL = 0; 419 | GCC_PREPROCESSOR_DEFINITIONS = ( 420 | "DEBUG=1", 421 | "$(inherited)", 422 | ); 423 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 424 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 425 | GCC_WARN_UNDECLARED_SELECTOR = YES; 426 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 427 | GCC_WARN_UNUSED_FUNCTION = YES; 428 | GCC_WARN_UNUSED_VARIABLE = YES; 429 | IPHONEOS_DEPLOYMENT_TARGET = 11.2; 430 | MTL_ENABLE_DEBUG_INFO = YES; 431 | ONLY_ACTIVE_ARCH = YES; 432 | SDKROOT = iphoneos; 433 | }; 434 | name = Debug; 435 | }; 436 | 8C816A3C1FF09FC000392890 /* Release */ = { 437 | isa = XCBuildConfiguration; 438 | buildSettings = { 439 | ALWAYS_SEARCH_USER_PATHS = NO; 440 | CLANG_ANALYZER_NONNULL = YES; 441 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 442 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 443 | CLANG_CXX_LIBRARY = "libc++"; 444 | CLANG_ENABLE_MODULES = YES; 445 | CLANG_ENABLE_OBJC_ARC = YES; 446 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 447 | CLANG_WARN_BOOL_CONVERSION = YES; 448 | CLANG_WARN_COMMA = YES; 449 | CLANG_WARN_CONSTANT_CONVERSION = YES; 450 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 451 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 452 | CLANG_WARN_EMPTY_BODY = YES; 453 | CLANG_WARN_ENUM_CONVERSION = YES; 454 | CLANG_WARN_INFINITE_RECURSION = YES; 455 | CLANG_WARN_INT_CONVERSION = YES; 456 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 457 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 458 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 459 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 460 | CLANG_WARN_STRICT_PROTOTYPES = YES; 461 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 462 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 463 | CLANG_WARN_UNREACHABLE_CODE = YES; 464 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 465 | CODE_SIGN_IDENTITY = "iPhone Developer"; 466 | COPY_PHASE_STRIP = NO; 467 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 468 | ENABLE_NS_ASSERTIONS = NO; 469 | ENABLE_STRICT_OBJC_MSGSEND = YES; 470 | GCC_C_LANGUAGE_STANDARD = gnu11; 471 | GCC_NO_COMMON_BLOCKS = YES; 472 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 473 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 474 | GCC_WARN_UNDECLARED_SELECTOR = YES; 475 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 476 | GCC_WARN_UNUSED_FUNCTION = YES; 477 | GCC_WARN_UNUSED_VARIABLE = YES; 478 | IPHONEOS_DEPLOYMENT_TARGET = 11.2; 479 | MTL_ENABLE_DEBUG_INFO = NO; 480 | SDKROOT = iphoneos; 481 | VALIDATE_PRODUCT = YES; 482 | }; 483 | name = Release; 484 | }; 485 | 8C816A3E1FF09FC000392890 /* Debug */ = { 486 | isa = XCBuildConfiguration; 487 | buildSettings = { 488 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 489 | CODE_SIGN_STYLE = Automatic; 490 | DEVELOPMENT_TEAM = 56EN3K39NQ; 491 | INFOPLIST_FILE = JHCollectionViewLayout/Info.plist; 492 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 493 | PRODUCT_BUNDLE_IDENTIFIER = Jivan.JHCollectionViewLayout; 494 | PRODUCT_NAME = "$(TARGET_NAME)"; 495 | TARGETED_DEVICE_FAMILY = "1,2"; 496 | }; 497 | name = Debug; 498 | }; 499 | 8C816A3F1FF09FC000392890 /* Release */ = { 500 | isa = XCBuildConfiguration; 501 | buildSettings = { 502 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 503 | CODE_SIGN_STYLE = Automatic; 504 | DEVELOPMENT_TEAM = 56EN3K39NQ; 505 | INFOPLIST_FILE = JHCollectionViewLayout/Info.plist; 506 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 507 | PRODUCT_BUNDLE_IDENTIFIER = Jivan.JHCollectionViewLayout; 508 | PRODUCT_NAME = "$(TARGET_NAME)"; 509 | TARGETED_DEVICE_FAMILY = "1,2"; 510 | }; 511 | name = Release; 512 | }; 513 | 8C816A411FF09FC000392890 /* Debug */ = { 514 | isa = XCBuildConfiguration; 515 | buildSettings = { 516 | BUNDLE_LOADER = "$(TEST_HOST)"; 517 | CODE_SIGN_STYLE = Automatic; 518 | INFOPLIST_FILE = JHCollectionViewLayoutTests/Info.plist; 519 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 520 | PRODUCT_BUNDLE_IDENTIFIER = Jivan.JHCollectionViewLayoutTests; 521 | PRODUCT_NAME = "$(TARGET_NAME)"; 522 | TARGETED_DEVICE_FAMILY = "1,2"; 523 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/JHCollectionViewLayout.app/JHCollectionViewLayout"; 524 | }; 525 | name = Debug; 526 | }; 527 | 8C816A421FF09FC000392890 /* Release */ = { 528 | isa = XCBuildConfiguration; 529 | buildSettings = { 530 | BUNDLE_LOADER = "$(TEST_HOST)"; 531 | CODE_SIGN_STYLE = Automatic; 532 | INFOPLIST_FILE = JHCollectionViewLayoutTests/Info.plist; 533 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 534 | PRODUCT_BUNDLE_IDENTIFIER = Jivan.JHCollectionViewLayoutTests; 535 | PRODUCT_NAME = "$(TARGET_NAME)"; 536 | TARGETED_DEVICE_FAMILY = "1,2"; 537 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/JHCollectionViewLayout.app/JHCollectionViewLayout"; 538 | }; 539 | name = Release; 540 | }; 541 | 8C816A441FF09FC000392890 /* Debug */ = { 542 | isa = XCBuildConfiguration; 543 | buildSettings = { 544 | CODE_SIGN_STYLE = Automatic; 545 | INFOPLIST_FILE = JHCollectionViewLayoutUITests/Info.plist; 546 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 547 | PRODUCT_BUNDLE_IDENTIFIER = Jivan.JHCollectionViewLayoutUITests; 548 | PRODUCT_NAME = "$(TARGET_NAME)"; 549 | TARGETED_DEVICE_FAMILY = "1,2"; 550 | TEST_TARGET_NAME = JHCollectionViewLayout; 551 | }; 552 | name = Debug; 553 | }; 554 | 8C816A451FF09FC000392890 /* Release */ = { 555 | isa = XCBuildConfiguration; 556 | buildSettings = { 557 | CODE_SIGN_STYLE = Automatic; 558 | INFOPLIST_FILE = JHCollectionViewLayoutUITests/Info.plist; 559 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 560 | PRODUCT_BUNDLE_IDENTIFIER = Jivan.JHCollectionViewLayoutUITests; 561 | PRODUCT_NAME = "$(TARGET_NAME)"; 562 | TARGETED_DEVICE_FAMILY = "1,2"; 563 | TEST_TARGET_NAME = JHCollectionViewLayout; 564 | }; 565 | name = Release; 566 | }; 567 | /* End XCBuildConfiguration section */ 568 | 569 | /* Begin XCConfigurationList section */ 570 | 8C816A0C1FF09FBF00392890 /* Build configuration list for PBXProject "JHCollectionViewLayout" */ = { 571 | isa = XCConfigurationList; 572 | buildConfigurations = ( 573 | 8C816A3B1FF09FC000392890 /* Debug */, 574 | 8C816A3C1FF09FC000392890 /* Release */, 575 | ); 576 | defaultConfigurationIsVisible = 0; 577 | defaultConfigurationName = Release; 578 | }; 579 | 8C816A3D1FF09FC000392890 /* Build configuration list for PBXNativeTarget "JHCollectionViewLayout" */ = { 580 | isa = XCConfigurationList; 581 | buildConfigurations = ( 582 | 8C816A3E1FF09FC000392890 /* Debug */, 583 | 8C816A3F1FF09FC000392890 /* Release */, 584 | ); 585 | defaultConfigurationIsVisible = 0; 586 | defaultConfigurationName = Release; 587 | }; 588 | 8C816A401FF09FC000392890 /* Build configuration list for PBXNativeTarget "JHCollectionViewLayoutTests" */ = { 589 | isa = XCConfigurationList; 590 | buildConfigurations = ( 591 | 8C816A411FF09FC000392890 /* Debug */, 592 | 8C816A421FF09FC000392890 /* Release */, 593 | ); 594 | defaultConfigurationIsVisible = 0; 595 | defaultConfigurationName = Release; 596 | }; 597 | 8C816A431FF09FC000392890 /* Build configuration list for PBXNativeTarget "JHCollectionViewLayoutUITests" */ = { 598 | isa = XCConfigurationList; 599 | buildConfigurations = ( 600 | 8C816A441FF09FC000392890 /* Debug */, 601 | 8C816A451FF09FC000392890 /* Release */, 602 | ); 603 | defaultConfigurationIsVisible = 0; 604 | defaultConfigurationName = Release; 605 | }; 606 | /* End XCConfigurationList section */ 607 | }; 608 | rootObject = 8C816A091FF09FBF00392890 /* Project object */; 609 | } 610 | -------------------------------------------------------------------------------- /JHCollectionViewLayout/JHCollectionViewLayout.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /JHCollectionViewLayout/JHCollectionViewLayout/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // JHCollectionViewLayout 4 | // 5 | // Created by Jivan on 2017/12/25. 6 | // Copyright © 2017年 Jivan. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /JHCollectionViewLayout/JHCollectionViewLayout/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // JHCollectionViewLayout 4 | // 5 | // Created by Jivan on 2017/12/25. 6 | // Copyright © 2017年 Jivan. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | 24 | - (void)applicationWillResignActive:(UIApplication *)application { 25 | // 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. 26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 27 | } 28 | 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application { 31 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | 36 | - (void)applicationWillEnterForeground:(UIApplication *)application { 37 | // 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. 38 | } 39 | 40 | 41 | - (void)applicationDidBecomeActive:(UIApplication *)application { 42 | // 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. 43 | } 44 | 45 | 46 | - (void)applicationWillTerminate:(UIApplication *)application { 47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 48 | } 49 | 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /JHCollectionViewLayout/JHCollectionViewLayout/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 | } -------------------------------------------------------------------------------- /JHCollectionViewLayout/JHCollectionViewLayout/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 | -------------------------------------------------------------------------------- /JHCollectionViewLayout/JHCollectionViewLayout/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /JHCollectionViewLayout/JHCollectionViewLayout/Class/JHHorizontalPageFlowlayout.h: -------------------------------------------------------------------------------- 1 | // 2 | // JHHorizontalPageFlowlayout.h 3 | // JHCollectionViewLayout 4 | // 5 | // Created by Jivan on 2017/12/25. 6 | // Copyright © 2017年 Jivan. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface JHHorizontalPageFlowlayout : UICollectionViewFlowLayout 12 | /** 列间距 */ 13 | @property (nonatomic, assign) CGFloat columnSpacing; 14 | /** 行间距 */ 15 | @property (nonatomic, assign) CGFloat rowSpacing; 16 | /** collectionView的内边距 */ 17 | @property (nonatomic, assign) UIEdgeInsets edgeInsets; 18 | 19 | /** 多少行 */ 20 | @property (nonatomic, assign) NSInteger rowCount; 21 | /** 每行展示多少个item */ 22 | @property (nonatomic, assign) NSInteger itemCountPerRow; 23 | 24 | /** 所有item的属性数组 */ 25 | @property (nonatomic, strong) NSMutableArray *attributesArrayM; 26 | 27 | /** 设置行列间距及collectionView的内边距 */ 28 | - (void)setColumnSpacing:(CGFloat)columnSpacing rowSpacing:(CGFloat)rowSpacing edgeInsets:(UIEdgeInsets)edgeInsets; 29 | /** 设置多少行及每行展示的item个数 */ 30 | - (void)setRowCount:(NSInteger)rowCount itemCountPerRow:(NSInteger)itemCountPerRow; 31 | 32 | #pragma mark - 构造方法 33 | /** 设置多少行及每行展示的item个数 */ 34 | + (instancetype)horizontalPageFlowlayoutWithRowCount:(NSInteger)rowCount itemCountPerRow:(NSInteger)itemCountPerRow; 35 | /** 设置多少行及每行展示的item个数 */ 36 | - (instancetype)initWithRowCount:(NSInteger)rowCount itemCountPerRow:(NSInteger)itemCountPerRow; 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /JHCollectionViewLayout/JHCollectionViewLayout/Class/JHHorizontalPageFlowlayout.m: -------------------------------------------------------------------------------- 1 | // 2 | // JHHorizontalPageFlowlayout.m 3 | // JHCollectionViewLayout 4 | // 5 | // Created by Jivan on 2017/12/25. 6 | // Copyright © 2017年 Jivan. All rights reserved. 7 | // 8 | 9 | #import "JHHorizontalPageFlowlayout.h" 10 | 11 | @implementation JHHorizontalPageFlowlayout 12 | 13 | #pragma mark - Public 14 | - (void)setColumnSpacing:(CGFloat)columnSpacing rowSpacing:(CGFloat)rowSpacing edgeInsets:(UIEdgeInsets)edgeInsets 15 | { 16 | self.columnSpacing = columnSpacing; 17 | self.rowSpacing = rowSpacing; 18 | self.edgeInsets = edgeInsets; 19 | } 20 | 21 | - (void)setRowCount:(NSInteger)rowCount itemCountPerRow:(NSInteger)itemCountPerRow 22 | { 23 | self.rowCount = rowCount; 24 | self.itemCountPerRow = itemCountPerRow; 25 | } 26 | 27 | #pragma mark - 构造方法 28 | + (instancetype)horizontalPageFlowlayoutWithRowCount:(NSInteger)rowCount itemCountPerRow:(NSInteger)itemCountPerRow 29 | { 30 | return [[self alloc] initWithRowCount:rowCount itemCountPerRow:itemCountPerRow]; 31 | } 32 | 33 | - (instancetype)initWithRowCount:(NSInteger)rowCount itemCountPerRow:(NSInteger)itemCountPerRow 34 | { 35 | self = [super init]; 36 | if (self) { 37 | self.rowCount = rowCount; 38 | self.itemCountPerRow = itemCountPerRow; 39 | } 40 | return self; 41 | } 42 | 43 | 44 | #pragma mark - 重写父类方法 45 | - (instancetype)init 46 | { 47 | self = [super init]; 48 | if (self) { 49 | [self setColumnSpacing:0 rowSpacing:0 edgeInsets:UIEdgeInsetsZero]; 50 | } 51 | return self; 52 | } 53 | 54 | /** 布局前做一些准备工作 */ 55 | - (void)prepareLayout 56 | { 57 | [super prepareLayout]; 58 | 59 | // 从collectionView中获取到有多少个item 60 | NSInteger itemTotalCount = [self.collectionView numberOfItemsInSection:0]; 61 | 62 | // 遍历出item的attributes,把它添加到管理它的属性数组中去 63 | for (int i = 0; i < itemTotalCount; i++) { 64 | NSIndexPath *indexpath = [NSIndexPath indexPathForItem:i inSection:0]; 65 | UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:indexpath]; 66 | [self.attributesArrayM addObject:attributes]; 67 | } 68 | } 69 | 70 | /** 计算collectionView的滚动范围 */ 71 | - (CGSize)collectionViewContentSize 72 | { 73 | // 计算出item的宽度 74 | CGFloat itemWidth = (self.collectionView.frame.size.width - self.edgeInsets.left - self.itemCountPerRow * self.columnSpacing) / self.itemCountPerRow; 75 | // 从collectionView中获取到有多少个item 76 | NSInteger itemTotalCount = [self.collectionView numberOfItemsInSection:0]; 77 | 78 | // 理论上每页展示的item数目 79 | NSInteger itemCount = self.rowCount * self.itemCountPerRow; 80 | // 余数(用于确定最后一页展示的item个数) 81 | NSInteger remainder = itemTotalCount % itemCount; 82 | // 除数(用于判断页数) 83 | NSInteger pageNumber = itemTotalCount / itemCount; 84 | // 总个数小于self.rowCount * self.itemCountPerRow 85 | if (itemTotalCount <= itemCount) { 86 | pageNumber = 1; 87 | }else { 88 | if (remainder == 0) { 89 | pageNumber = pageNumber; 90 | }else { 91 | // 余数不为0,除数加1 92 | pageNumber = pageNumber + 1; 93 | } 94 | } 95 | 96 | CGFloat width = 0; 97 | // 考虑特殊情况(当item的总个数不是self.rowCount * self.itemCountPerRow的整数倍,并且余数小于每行展示的个数的时候) 98 | if (pageNumber > 1 && remainder != 0 && remainder < self.itemCountPerRow) { 99 | width = self.edgeInsets.left + (pageNumber - 1) * self.itemCountPerRow * (itemWidth + self.columnSpacing) + remainder * itemWidth + (remainder - 1)*self.columnSpacing + self.edgeInsets.right; 100 | }else { 101 | width = self.edgeInsets.left + pageNumber * self.itemCountPerRow * (itemWidth + self.columnSpacing) - self.columnSpacing + self.edgeInsets.right; 102 | } 103 | 104 | // 只支持水平方向上的滚动 105 | return CGSizeMake(width, 0); 106 | } 107 | 108 | /** 设置每个item的属性(主要是frame) */ 109 | - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath 110 | { 111 | // item的宽高由行列间距和collectionView的内边距决定 112 | CGFloat itemWidth = (self.collectionView.frame.size.width - self.edgeInsets.left - self.itemCountPerRow * self.columnSpacing) / self.itemCountPerRow; 113 | CGFloat itemHeight = (self.collectionView.frame.size.height - self.edgeInsets.top - self.edgeInsets.bottom - (self.rowCount - 1) * self.rowSpacing) / self.rowCount; 114 | 115 | NSInteger item = indexPath.item; 116 | // 当前item所在的页 117 | NSInteger pageNumber = item / (self.rowCount * self.itemCountPerRow); 118 | NSInteger x = item % self.itemCountPerRow + pageNumber * self.itemCountPerRow; 119 | NSInteger y = item / self.itemCountPerRow - pageNumber * self.rowCount; 120 | 121 | // 计算出item的坐标 122 | CGFloat itemX = self.edgeInsets.left + (itemWidth + self.columnSpacing) * x; 123 | CGFloat itemY = self.edgeInsets.top + (itemHeight + self.rowSpacing) * y; 124 | 125 | UICollectionViewLayoutAttributes *attributes = [super layoutAttributesForItemAtIndexPath:indexPath]; 126 | // 每个item的frame 127 | attributes.frame = CGRectMake(itemX, itemY, itemWidth, itemHeight); 128 | 129 | return attributes; 130 | } 131 | 132 | /** 返回collectionView视图中所有视图的属性数组 */ 133 | - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect 134 | { 135 | 136 | return self.attributesArrayM; 137 | } 138 | 139 | 140 | #pragma mark - Lazy 141 | - (NSMutableArray *)attributesArrayM 142 | { 143 | if (!_attributesArrayM) { 144 | _attributesArrayM = [NSMutableArray array]; 145 | } 146 | return _attributesArrayM; 147 | } 148 | 149 | @end 150 | -------------------------------------------------------------------------------- /JHCollectionViewLayout/JHCollectionViewLayout/Class/JHWaterfallCollectionLayout.h: -------------------------------------------------------------------------------- 1 | // 2 | // JHWaterfallCollectionLayout.h 3 | // WaterfallCollection 4 | // 5 | // Created by Jivan on 2017/3/17. 6 | // Copyright © 2017年 Jivan. All rights reserved. 7 | // 8 | 9 | #import 10 | @class JHWaterfallCollectionLayout; 11 | 12 | @protocol WaterFlowLayoutDelegate 13 | 14 | @required 15 | //决定cell的高度,必须实现方法 16 | - (CGFloat)waterFlowLayout:(JHWaterfallCollectionLayout *)waterFlowLayout heightForRowAtIndex:(NSInteger)index itemWidth:(CGFloat)width; 17 | 18 | @optional 19 | //决定cell的列数 20 | - (NSInteger)cloumnCountInWaterFlowLayout:(JHWaterfallCollectionLayout *)waterFlowLayout; 21 | 22 | //决定cell 的列的距离 23 | - (CGFloat)columMarginInWaterFlowLayout:(JHWaterfallCollectionLayout *)waterFlowLayout; 24 | 25 | //决定cell 的行的距离 26 | - (CGFloat)rowMarginInWaterFlowLayout:(JHWaterfallCollectionLayout *)waterFlowLayout; 27 | 28 | //决定cell 的边缘距 29 | - (UIEdgeInsets)edgeInsetInWaterFlowLayout:(JHWaterfallCollectionLayout *)waterFlowLayout; 30 | 31 | @end 32 | 33 | @interface JHWaterfallCollectionLayout : UICollectionViewLayout 34 | /**代理*/ 35 | @property (nonatomic,assign) id delegate; 36 | 37 | - (NSInteger)columCount; 38 | - (CGFloat)columMargin; 39 | - (CGFloat)rowMargin; 40 | - (UIEdgeInsets)defaultEdgeInsets; 41 | 42 | @end 43 | 44 | -------------------------------------------------------------------------------- /JHCollectionViewLayout/JHCollectionViewLayout/Class/JHWaterfallCollectionLayout.m: -------------------------------------------------------------------------------- 1 | // 2 | // JHWaterfallCollectionLayout.m 3 | // WaterfallCollection 4 | // 5 | // Created by Jivan on 2017/3/17. 6 | // Copyright © 2017年 Jivan. All rights reserved. 7 | // 8 | 9 | #import "JHWaterfallCollectionLayout.h" 10 | 11 | @interface JHWaterfallCollectionLayout () 12 | /** 布局属性数组*/ 13 | @property (nonatomic,strong) NSMutableArray *attrsArray; 14 | 15 | /** 存放所有列的当前高度*/ 16 | @property (nonatomic,strong) NSMutableArray *columnHeight; 17 | 18 | @end 19 | 20 | /** 列数*/ 21 | static const CGFloat columCount = 3; 22 | /** 每一列间距*/ 23 | static const CGFloat columMargin = 10; 24 | /** 每一列间距*/ 25 | static const CGFloat rowMargin = 10; 26 | /** 边缘间距*/ 27 | static const UIEdgeInsets defaultEdgeInsets = {10,10,10,10}; 28 | 29 | 30 | @implementation JHWaterfallCollectionLayout 31 | 32 | - (NSInteger)columCount{ 33 | 34 | if ([self.delegate respondsToSelector:@selector(cloumnCountInWaterFlowLayout:)]) { 35 | return [self.delegate cloumnCountInWaterFlowLayout:self]; 36 | } 37 | else{ 38 | return columCount; 39 | } 40 | } 41 | 42 | - (CGFloat)columMargin{ 43 | 44 | if ([self.delegate respondsToSelector:@selector(columMarginInWaterFlowLayout:)]) { 45 | return [self.delegate columMarginInWaterFlowLayout:self]; 46 | } 47 | else{ 48 | return columMargin; 49 | } 50 | } 51 | 52 | - (CGFloat)rowMargin{ 53 | 54 | if ([self.delegate respondsToSelector:@selector(rowMarginInWaterFlowLayout:)]) { 55 | return [self.delegate rowMarginInWaterFlowLayout:self]; 56 | } 57 | else{ 58 | return rowMargin; 59 | } 60 | } 61 | 62 | - (UIEdgeInsets)defaultEdgeInsets{ 63 | 64 | if ([self.delegate respondsToSelector:@selector(edgeInsetInWaterFlowLayout:)]) { 65 | return [self.delegate edgeInsetInWaterFlowLayout:self]; 66 | } 67 | else{ 68 | return defaultEdgeInsets; 69 | } 70 | } 71 | 72 | 73 | //懒加载 attrsArray, columnHeight 74 | 75 | - (NSMutableArray *)attrsArray 76 | { 77 | if (!_attrsArray) { 78 | 79 | _attrsArray = [NSMutableArray array]; 80 | } 81 | return _attrsArray; 82 | } 83 | 84 | - (NSMutableArray *)columnHeight 85 | { 86 | if (!_columnHeight) { 87 | 88 | _columnHeight = [NSMutableArray array]; 89 | } 90 | return _columnHeight; 91 | } 92 | 93 | //重写prepareLayout方法 94 | 95 | /** 初始化*/ 96 | - (void)prepareLayout 97 | { 98 | [super prepareLayout]; 99 | 100 | //如果刷新布局就会重新调用prepareLayout这个方法,所以要先把高度数组清空 101 | [self.columnHeight removeAllObjects]; 102 | for (int i = 0; i < self.columCount; i++) { 103 | 104 | [self.columnHeight addObject:@(self.defaultEdgeInsets.top)]; 105 | } 106 | 107 | NSInteger count = [self.collectionView numberOfItemsInSection:0]; 108 | 109 | [self.attrsArray removeAllObjects]; 110 | for (NSInteger i = 0; i < count; i++) { 111 | 112 | NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:0]; 113 | //获取indexPath 对应cell 的布局属性 114 | UICollectionViewLayoutAttributes *attr = [self layoutAttributesForItemAtIndexPath:indexPath]; 115 | [self.attrsArray addObject:attr]; 116 | } 117 | } 118 | //该方法返回对应cell上的布局属性.我们可以在这个方法中设置cell 的布局样式.在prepareLayout方法中,我们根据这个方法,传入对应的IndexPath从而获取到布局属性attr,然后添加到数组中. 119 | 120 | /** 121 | * 返回indexPath 位置cell对应的布局属性 122 | */ 123 | - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath 124 | { 125 | UICollectionViewLayoutAttributes *attr = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath]; 126 | 127 | //使用for循环,找出高度最短的那一列 128 | //最短高度的列 129 | NSInteger destColumn = 0; 130 | CGFloat minColumnHeight = [self.columnHeight[0] doubleValue]; 131 | 132 | for (NSInteger i = 1; i < self.columCount; i++) { 133 | 134 | CGFloat columnHeight =[self.columnHeight[i] doubleValue]; 135 | if (minColumnHeight > columnHeight) { 136 | 137 | minColumnHeight = columnHeight; 138 | destColumn = i; 139 | } 140 | } 141 | 142 | CGFloat w = (self.collectionView.frame.size.width - self.defaultEdgeInsets.left - self.defaultEdgeInsets.right - (self.columCount - 1) * self.columMargin )/self.columCount; 143 | 144 | //(使用代理在外部决定cell 的高度,下面会介绍) 145 | CGFloat h = [self.delegate waterFlowLayout:self heightForRowAtIndex:indexPath.item itemWidth:w]; 146 | 147 | CGFloat x = self.defaultEdgeInsets.left + destColumn*(w + self.columMargin); 148 | CGFloat y = minColumnHeight ; 149 | 150 | if (y != self.defaultEdgeInsets.top) { 151 | 152 | y += self.rowMargin; 153 | } 154 | 155 | attr.frame = CGRectMake(x,y,w,h); 156 | 157 | self.columnHeight[destColumn] = @(y+ h); 158 | return attr; 159 | } 160 | //重写layoutAttributesForElementsInRect:方法 161 | 162 | /** 163 | * 决定cell 的排布 164 | */ 165 | - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect 166 | { 167 | return self.attrsArray; 168 | } 169 | //决定collectionView的可滚动范围 170 | 171 | - (CGSize)collectionViewContentSize 172 | { 173 | 174 | CGFloat maxHeight = [self.columnHeight[0] doubleValue]; 175 | for (int i = 1; i < self.columCount; i++) { 176 | 177 | CGFloat value = [self.columnHeight[i] doubleValue]; 178 | if (maxHeight < value) { 179 | 180 | maxHeight = value; 181 | } 182 | } 183 | return CGSizeMake(0, maxHeight+self.defaultEdgeInsets.bottom); 184 | } 185 | 186 | 187 | 188 | @end 189 | -------------------------------------------------------------------------------- /JHCollectionViewLayout/JHCollectionViewLayout/Demo/BaseViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // BaseViewController.h 3 | // JHCollectionViewLayout 4 | // 5 | // Created by Jivan on 2017/12/25. 6 | // Copyright © 2017年 Jivan. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface BaseViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /JHCollectionViewLayout/JHCollectionViewLayout/Demo/BaseViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // BaseViewController.m 3 | // JHCollectionViewLayout 4 | // 5 | // Created by Jivan on 2017/12/25. 6 | // Copyright © 2017年 Jivan. All rights reserved. 7 | // 8 | 9 | #import "BaseViewController.h" 10 | 11 | @interface BaseViewController () 12 | 13 | @end 14 | 15 | @implementation BaseViewController 16 | 17 | 18 | - (void)viewDidLoad { 19 | [super viewDidLoad]; 20 | // Do any additional setup after loading the view. 21 | UIButton *back = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, 30, 30)]; 22 | [back setTitle:@"返回" forState:UIControlStateNormal]; 23 | [back addTarget:self action:@selector(back) forControlEvents:UIControlEventTouchDown]; 24 | [back setTitleColor:[UIColor blueColor] forState:UIControlStateNormal]; 25 | UIBarButtonItem *item = [[UIBarButtonItem alloc]initWithCustomView:back]; 26 | self.navigationItem.leftBarButtonItem = item ; 27 | } 28 | 29 | -(void)back 30 | { 31 | [self dismissViewControllerAnimated:YES completion:nil]; 32 | } 33 | 34 | 35 | - (void)didReceiveMemoryWarning { 36 | [super didReceiveMemoryWarning]; 37 | // Dispose of any resources that can be recreated. 38 | } 39 | 40 | 41 | 42 | 43 | @end 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /JHCollectionViewLayout/JHCollectionViewLayout/Demo/HorizontalPageViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // HorizontalPageViewController.h 3 | // JHCollectionViewLayout 4 | // 5 | // Created by Jivan on 2017/12/25. 6 | // Copyright © 2017年 Jivan. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "BaseViewController.h" 11 | 12 | @interface HorizontalPageViewController : BaseViewController 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /JHCollectionViewLayout/JHCollectionViewLayout/Demo/HorizontalPageViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // HorizontalPageViewController.m 3 | // JHCollectionViewLayout 4 | // 5 | // Created by Jivan on 2017/12/25. 6 | // Copyright © 2017年 Jivan. All rights reserved. 7 | // 8 | 9 | #import "HorizontalPageViewController.h" 10 | #import "JHHorizontalPageFlowlayout.h" 11 | #import "JHCollectionViewCell.h" 12 | 13 | #define MAIN_SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width 14 | 15 | @interface HorizontalPageViewController () 16 | 17 | @property (strong,nonatomic) UICollectionView* collectionView ; 18 | 19 | @end 20 | 21 | @implementation HorizontalPageViewController 22 | 23 | - (void)viewDidLoad { 24 | [super viewDidLoad]; 25 | // Do any additional setup after loading the view. 26 | self.view.backgroundColor = [UIColor whiteColor]; 27 | 28 | [self.collectionView registerNib:[UINib nibWithNibName:NSStringFromClass([JHCollectionViewCell class]) bundle:nil] forCellWithReuseIdentifier:NSStringFromClass([JHCollectionViewCell class])]; 29 | 30 | } 31 | -(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section 32 | { 33 | return 20 ; 34 | } 35 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath 36 | { 37 | 38 | UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass([JHCollectionViewCell class]) forIndexPath:indexPath]; 39 | cell.contentView.backgroundColor = [UIColor colorWithRed:(arc4random()%251)/255.0 green:(arc4random()%251)/255.0 blue:(arc4random()%251)/255.0 alpha:1]; 40 | return cell; 41 | } 42 | 43 | #pragma mark - Lazy 44 | - (UICollectionView *)collectionView 45 | { 46 | if (!_collectionView) { 47 | 48 | /** -----1.使用苹果提供的的UICollectionViewFlowLayout布局----- */ 49 | // UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; 50 | 51 | /** -----2.使用自定义的的HorizontalPageFlowlayout布局----- */ 52 | JHHorizontalPageFlowlayout *layout = [[JHHorizontalPageFlowlayout alloc] initWithRowCount:1 itemCountPerRow:5]; 53 | [layout setColumnSpacing:0 rowSpacing:0 edgeInsets:UIEdgeInsetsMake(0, 0, 0, 0)]; 54 | 55 | layout.scrollDirection = UICollectionViewScrollDirectionHorizontal; 56 | 57 | _collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 64,MAIN_SCREEN_WIDTH,MAIN_SCREEN_WIDTH/5.00) collectionViewLayout:layout]; 58 | _collectionView.center = self.view.center ; 59 | _collectionView.bounces = YES; 60 | _collectionView.pagingEnabled = YES; 61 | _collectionView.dataSource = self; 62 | _collectionView.delegate = self; 63 | _collectionView.showsHorizontalScrollIndicator = NO ; 64 | _collectionView.backgroundColor = [UIColor whiteColor]; 65 | 66 | [self.view addSubview:_collectionView]; 67 | } 68 | 69 | return _collectionView; 70 | } 71 | 72 | 73 | - (void)didReceiveMemoryWarning { 74 | [super didReceiveMemoryWarning]; 75 | // Dispose of any resources that can be recreated. 76 | } 77 | 78 | 79 | @end 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /JHCollectionViewLayout/JHCollectionViewLayout/Demo/JHCollectionViewCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // JHCollectionViewCell.h 3 | // WaterfallCollection 4 | // 5 | // Created by Jivan on 2017/3/17. 6 | // Copyright © 2017年 Jivan. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface JHCollectionViewCell : UICollectionViewCell 12 | 13 | @property (strong, nonatomic) UIImageView *topImage; 14 | @property (strong, nonatomic) UILabel *botlabel; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /JHCollectionViewLayout/JHCollectionViewLayout/Demo/JHCollectionViewCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // JHCollectionViewCell.m 3 | // WaterfallCollection 4 | // 5 | // Created by Jivan on 2017/3/17. 6 | // Copyright © 2017年 Jivan. All rights reserved. 7 | // 8 | 9 | #import "JHCollectionViewCell.h" 10 | 11 | @implementation JHCollectionViewCell 12 | 13 | - (id)initWithFrame:(CGRect)frame 14 | { 15 | self = [super initWithFrame:frame]; 16 | if (self) 17 | { 18 | 19 | self.contentView.backgroundColor = [UIColor colorWithRed:(arc4random()%251)/255.0 green:(arc4random()%251)/255.0 blue:(arc4random()%251)/255.0 alpha:1]; 20 | } 21 | 22 | return self; 23 | } 24 | 25 | - (void)awakeFromNib { 26 | [super awakeFromNib]; 27 | // Initialization code 28 | } 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /JHCollectionViewLayout/JHCollectionViewLayout/Demo/JHCollectionViewCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /JHCollectionViewLayout/JHCollectionViewLayout/Demo/WaterfallViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // WaterfallViewController.h 3 | // JHCollectionViewLayout 4 | // 5 | // Created by Jivan on 2017/12/25. 6 | // Copyright © 2017年 Jivan. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "BaseViewController.h" 11 | @interface WaterfallViewController : BaseViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /JHCollectionViewLayout/JHCollectionViewLayout/Demo/WaterfallViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // WaterfallViewController.m 3 | // JHCollectionViewLayout 4 | // 5 | // Created by Jivan on 2017/12/25. 6 | // Copyright © 2017年 Jivan. All rights reserved. 7 | // 8 | 9 | #import "WaterfallViewController.h" 10 | #import "JHCollectionViewCell.h" 11 | #import "JHWaterfallCollectionLayout.h" 12 | 13 | @interface WaterfallViewController () 14 | { 15 | UICollectionView *mainCollectionView; 16 | } 17 | 18 | @property (nonatomic,strong) NSMutableArray* heightArr ; 19 | 20 | @end 21 | 22 | @implementation WaterfallViewController 23 | 24 | - (void)viewDidLoad { 25 | [super viewDidLoad]; 26 | // Do any additional setup after loading the view. 27 | self.view.backgroundColor = [UIColor whiteColor]; 28 | 29 | JHWaterfallCollectionLayout* layout = [[JHWaterfallCollectionLayout alloc]init]; 30 | layout.delegate = self ; 31 | 32 | //2.初始化collectionView 33 | mainCollectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:layout]; 34 | 35 | [self.view addSubview:mainCollectionView]; 36 | mainCollectionView.backgroundColor = [UIColor clearColor]; 37 | 38 | //3.注册collectionViewCell 39 | //注意,此处的ReuseIdentifier 必须和 cellForItemAtIndexPath 方法中 一致 均为 cellId 40 | [mainCollectionView registerClass:[JHCollectionViewCell class] forCellWithReuseIdentifier:@"cellId"]; 41 | 42 | //4.设置代理 43 | mainCollectionView.delegate = self; 44 | mainCollectionView.dataSource = self; 45 | } 46 | #pragma mark - WaterFlowLayoutDelegate 47 | - (CGFloat)waterFlowLayout:(JHWaterfallCollectionLayout *)waterFlowLayout heightForRowAtIndex:(NSInteger)index itemWidth:(CGFloat)width 48 | { 49 | 50 | return [self.heightArr[index] floatValue]; 51 | 52 | 53 | } 54 | -(NSArray *)heightArr{ 55 | if(!_heightArr){ 56 | //随机生成高度 57 | NSMutableArray *arr = [NSMutableArray array]; 58 | for (int i = 0; i< 20; i++) { 59 | 60 | [arr addObject:@(arc4random()%100+100)]; 61 | } 62 | _heightArr = [arr copy]; 63 | } 64 | return _heightArr; 65 | } 66 | 67 | //决定cell的列数 68 | - (NSInteger)cloumnCountInWaterFlowLayout:(JHWaterfallCollectionLayout *)waterFlowLayout 69 | { 70 | return 2 ; 71 | } 72 | //决定cell 的列的距离 73 | - (CGFloat)columMarginInWaterFlowLayout:(JHWaterfallCollectionLayout *)waterFlowLayout 74 | { 75 | return 3 ; 76 | } 77 | 78 | //决定cell 的行的距离 79 | - (CGFloat)rowMarginInWaterFlowLayout:(JHWaterfallCollectionLayout *)waterFlowLayout 80 | { 81 | return 3 ; 82 | } 83 | 84 | //决定cell 的边缘距 85 | - (UIEdgeInsets)edgeInsetInWaterFlowLayout:(JHWaterfallCollectionLayout *)waterFlowLayout 86 | { 87 | return UIEdgeInsetsMake(10, 10, 10, 10); 88 | } 89 | 90 | #pragma mark collectionView代理方法 91 | //返回section个数 92 | - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView 93 | { 94 | return 1; 95 | } 96 | 97 | //每个section的item个数 98 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section 99 | { 100 | return 10; 101 | } 102 | 103 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath 104 | { 105 | 106 | JHCollectionViewCell *cell = (JHCollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:@"cellId" forIndexPath:indexPath]; 107 | 108 | return cell; 109 | } 110 | 111 | 112 | - (void)didReceiveMemoryWarning { 113 | [super didReceiveMemoryWarning]; 114 | // Dispose of any resources that can be recreated. 115 | } 116 | 117 | @end 118 | -------------------------------------------------------------------------------- /JHCollectionViewLayout/JHCollectionViewLayout/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 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 | -------------------------------------------------------------------------------- /JHCollectionViewLayout/JHCollectionViewLayout/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // JHCollectionViewLayout 4 | // 5 | // Created by Jivan on 2017/12/25. 6 | // Copyright © 2017年 Jivan. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /JHCollectionViewLayout/JHCollectionViewLayout/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // JHCollectionViewLayout 4 | // 5 | // Created by Jivan on 2017/12/25. 6 | // Copyright © 2017年 Jivan. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "WaterfallViewController.h" 11 | #import "HorizontalPageViewController.h" 12 | 13 | @interface ViewController () 14 | 15 | @property (nonatomic,strong) UITableView *tableView; 16 | @property (nonatomic,strong) NSArray *titles; 17 | @property (nonatomic,strong) NSMutableArray *dataSource; 18 | 19 | @end 20 | 21 | static NSString *cellReuserId = @"cellID"; 22 | 23 | @implementation ViewController 24 | 25 | - (void)viewDidLoad { 26 | [super viewDidLoad]; 27 | // Do any additional setup after loading the view, typically from a nib. 28 | 29 | self.titles = @[@"瀑布流",@"横向布局"]; 30 | 31 | WaterfallViewController * waterfall = [[WaterfallViewController alloc]init]; 32 | waterfall.title = @"瀑布流Demo"; 33 | [self.dataSource addObject:waterfall]; 34 | 35 | HorizontalPageViewController * horizontalPage = [[HorizontalPageViewController alloc]init]; 36 | horizontalPage.title = @"横向布局Demo"; 37 | [self.dataSource addObject:horizontalPage]; 38 | 39 | 40 | [self.tableView setHidden:NO]; 41 | 42 | } 43 | 44 | 45 | - (void)didReceiveMemoryWarning { 46 | [super didReceiveMemoryWarning]; 47 | // Dispose of any resources that can be recreated. 48 | } 49 | 50 | -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 51 | { 52 | return self.dataSource.count ; 53 | } 54 | 55 | -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 56 | { 57 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellReuserId]; 58 | 59 | if (!cell) { 60 | cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier: cellReuserId]; 61 | } 62 | cell.textLabel.text = self.titles[indexPath.row]; 63 | 64 | return cell ; 65 | } 66 | 67 | 68 | -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 69 | { 70 | UIViewController * vc = self.dataSource[indexPath.row]; 71 | UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:vc]; 72 | [self presentViewController:nav animated:YES completion:nil]; 73 | } 74 | -(UITableView *)tableView 75 | { 76 | if (!_tableView) { 77 | 78 | _tableView = [[UITableView alloc]initWithFrame: [UIScreen mainScreen].bounds]; 79 | _tableView.delegate = self ; 80 | _tableView.dataSource = self; 81 | 82 | [self.view addSubview:_tableView]; 83 | } 84 | 85 | return _tableView ; 86 | } 87 | 88 | -(NSArray *)titles 89 | { 90 | if (!_titles) { 91 | 92 | _titles = [NSArray array]; 93 | } 94 | return _titles ; 95 | } 96 | 97 | -(NSMutableArray *)dataSource 98 | { 99 | if (!_dataSource) { 100 | 101 | _dataSource = [NSMutableArray array]; 102 | } 103 | return _dataSource ; 104 | } 105 | 106 | 107 | 108 | @end 109 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /JHCollectionViewLayout/JHCollectionViewLayout/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // JHCollectionViewLayout 4 | // 5 | // Created by Jivan on 2017/12/25. 6 | // Copyright © 2017年 Jivan. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /JHCollectionViewLayout/JHCollectionViewLayoutTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /JHCollectionViewLayout/JHCollectionViewLayoutTests/JHCollectionViewLayoutTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // JHCollectionViewLayoutTests.m 3 | // JHCollectionViewLayoutTests 4 | // 5 | // Created by Jivan on 2017/12/25. 6 | // Copyright © 2017年 Jivan. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface JHCollectionViewLayoutTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation JHCollectionViewLayoutTests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | } 21 | 22 | - (void)tearDown { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | [super tearDown]; 25 | } 26 | 27 | - (void)testExample { 28 | // This is an example of a functional test case. 29 | // Use XCTAssert and related functions to verify your tests produce the correct results. 30 | } 31 | 32 | - (void)testPerformanceExample { 33 | // This is an example of a performance test case. 34 | [self measureBlock:^{ 35 | // Put the code you want to measure the time of here. 36 | }]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /JHCollectionViewLayout/JHCollectionViewLayoutUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /JHCollectionViewLayout/JHCollectionViewLayoutUITests/JHCollectionViewLayoutUITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // JHCollectionViewLayoutUITests.m 3 | // JHCollectionViewLayoutUITests 4 | // 5 | // Created by Jivan on 2017/12/25. 6 | // Copyright © 2017年 Jivan. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface JHCollectionViewLayoutUITests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation JHCollectionViewLayoutUITests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | 22 | // In UI tests it is usually best to stop immediately when a failure occurs. 23 | self.continueAfterFailure = NO; 24 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 25 | [[[XCUIApplication alloc] init] launch]; 26 | 27 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 28 | } 29 | 30 | - (void)tearDown { 31 | // Put teardown code here. This method is called after the invocation of each test method in the class. 32 | [super tearDown]; 33 | } 34 | 35 | - (void)testExample { 36 | // Use recording to get started writing UI tests. 37 | // Use XCTAssert and related functions to verify your tests produce the correct results. 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Jivan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JHCollectionViewLayout 2 | collectionView的横向布局和瀑布流 3 | --------------------------------------------------------------------------------