├── .gitignore ├── IGListKitDemoSwift.xcodeproj ├── project.pbxproj └── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── IGListKitDemoSwift.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── IGListKitDemoSwift ├── AnyCodable │ ├── AnyCodable.swift │ ├── AnyDecodable.swift │ └── AnyEncodable.swift ├── AppDelegate.swift ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── Contents.json │ ├── arrow_down.imageset │ │ ├── Contents.json │ │ └── arrow_down@2x.png │ ├── comment.imageset │ │ ├── Contents.json │ │ └── comment.png │ ├── praise.imageset │ │ ├── Contents.json │ │ └── praise.png │ └── praise_selected.imageset │ │ ├── Contents.json │ │ └── praise_selected.png ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Cell │ ├── AdCell.swift │ ├── CommentCell.swift │ ├── CommentCell.xib │ ├── ContentCell.swift │ ├── ContentCell.xib │ ├── FavorCell.swift │ ├── FavorCell.xib │ ├── ImageCell.swift │ ├── ImageCell.xib │ ├── ImageCollectionCell.swift │ ├── ImageCollectionCell.xib │ ├── UserInfoCell.swift │ └── UserInfoCell.xib ├── CellModel │ ├── CommentCellModel.swift │ ├── FavorCellModel.swift │ ├── ImagesCollectionCellModel.swift │ └── UserInfoCellModel.swift ├── Extensions.swift ├── Info.plist ├── JsonTool.swift ├── Model │ ├── Ad.swift │ ├── Comment.swift │ ├── Feed.swift │ └── ListModel.swift ├── SectionController │ ├── AdSectionController.swift │ ├── CommentSectionController.swift │ ├── ContentSectionController.swift │ ├── FavorSectionController.swift │ ├── FeedBindingSectionController.swift │ ├── FeedSectionController.swift │ ├── ImageSectionController.swift │ └── UserInfoSectionController.swift ├── ViewController.swift ├── ViewController │ ├── BaseListViewController.swift │ ├── FifthListViewController.swift │ ├── FirstListViewController.swift │ ├── ForthListViewController.swift │ ├── SecondListViewController.swift │ ├── SeventhListViewController.swift │ ├── SixthListViewController.swift │ └── ThirdListViewController.swift └── data │ ├── data1.json │ ├── data2.json │ ├── data3.json │ ├── data4.json │ └── data5.json ├── Podfile └── Podfile.lock /.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/**/*.png 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 | -------------------------------------------------------------------------------- /IGListKitDemoSwift.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 8400DEDB2112056D009D751C /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8400DEDA2112056D009D751C /* AppDelegate.swift */; }; 11 | 8400DEDD2112056D009D751C /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8400DEDC2112056D009D751C /* ViewController.swift */; }; 12 | 8400DEE02112056D009D751C /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8400DEDE2112056D009D751C /* Main.storyboard */; }; 13 | 8400DEE22112056E009D751C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8400DEE12112056E009D751C /* Assets.xcassets */; }; 14 | 8400DEE52112056E009D751C /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8400DEE32112056E009D751C /* LaunchScreen.storyboard */; }; 15 | 84113220216782D700096D3D /* data2.json in Resources */ = {isa = PBXBuildFile; fileRef = 8411321F216782D700096D3D /* data2.json */; }; 16 | 841132222167914000096D3D /* FavorSectionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841132212167914000096D3D /* FavorSectionController.swift */; }; 17 | 841132252167B2B000096D3D /* ImageCollectionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841132232167B2B000096D3D /* ImageCollectionCell.swift */; }; 18 | 841132262167B2B000096D3D /* ImageCollectionCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 841132242167B2B000096D3D /* ImageCollectionCell.xib */; }; 19 | 84113229216852B600096D3D /* ImageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84113227216852B600096D3D /* ImageCell.swift */; }; 20 | 8411322A216852B600096D3D /* ImageCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 84113228216852B600096D3D /* ImageCell.xib */; }; 21 | 8411322C216853A000096D3D /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8411322B216853A000096D3D /* Extensions.swift */; }; 22 | 8411322E2168575900096D3D /* ImageSectionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8411322D2168575900096D3D /* ImageSectionController.swift */; }; 23 | 8411323021685B4400096D3D /* data3.json in Resources */ = {isa = PBXBuildFile; fileRef = 8411322F21685B4400096D3D /* data3.json */; }; 24 | 8411323221688A5D00096D3D /* ImagesCollectionCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8411323121688A5D00096D3D /* ImagesCollectionCellModel.swift */; }; 25 | 841132342168E47100096D3D /* data4.json in Resources */ = {isa = PBXBuildFile; fileRef = 841132332168E47100096D3D /* data4.json */; }; 26 | 841132372168E4EF00096D3D /* CommentCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841132352168E4EF00096D3D /* CommentCell.swift */; }; 27 | 841132382168E4EF00096D3D /* CommentCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 841132362168E4EF00096D3D /* CommentCell.xib */; }; 28 | 8411323A2168E56500096D3D /* CommentCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841132392168E56500096D3D /* CommentCellModel.swift */; }; 29 | 8411323C2168E57200096D3D /* Comment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8411323B2168E57200096D3D /* Comment.swift */; }; 30 | 8411323E2168F90200096D3D /* CommentSectionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8411323D2168F90200096D3D /* CommentSectionController.swift */; }; 31 | 84113240216903B900096D3D /* data5.json in Resources */ = {isa = PBXBuildFile; fileRef = 8411323F216903B900096D3D /* data5.json */; }; 32 | 841132422169052500096D3D /* Ad.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841132412169052500096D3D /* Ad.swift */; }; 33 | 841132442169058A00096D3D /* AdCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841132432169058A00096D3D /* AdCell.swift */; }; 34 | 841132462169079900096D3D /* AdSectionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841132452169079900096D3D /* AdSectionController.swift */; }; 35 | 841132482169085E00096D3D /* ListModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841132472169085E00096D3D /* ListModel.swift */; }; 36 | 84681094215FBB8000433E5B /* ContentCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84681092215FBB8000433E5B /* ContentCell.swift */; }; 37 | 84681095215FBB8000433E5B /* ContentCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 84681093215FBB8000433E5B /* ContentCell.xib */; }; 38 | 84681097215FBD0500433E5B /* ContentSectionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84681096215FBD0500433E5B /* ContentSectionController.swift */; }; 39 | 8468109A215FD0C900433E5B /* FavorCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84681098215FD0C900433E5B /* FavorCell.swift */; }; 40 | 8468109B215FD0C900433E5B /* FavorCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 84681099215FD0C900433E5B /* FavorCell.xib */; }; 41 | 8468109D215FD1AC00433E5B /* FavorCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8468109C215FD1AC00433E5B /* FavorCellModel.swift */; }; 42 | 8481A79A214AB0F3000D2FEE /* FirstListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8481A799214AB0F3000D2FEE /* FirstListViewController.swift */; }; 43 | 8481A79C214AB106000D2FEE /* SecondListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8481A79B214AB106000D2FEE /* SecondListViewController.swift */; }; 44 | 8481A79E214AB114000D2FEE /* ThirdListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8481A79D214AB114000D2FEE /* ThirdListViewController.swift */; }; 45 | 8481A7A0214AB134000D2FEE /* ForthListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8481A79F214AB134000D2FEE /* ForthListViewController.swift */; }; 46 | 8481A7A2214AB154000D2FEE /* FifthListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8481A7A1214AB154000D2FEE /* FifthListViewController.swift */; }; 47 | 84BDE421214AAEAE00532BF7 /* BaseListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84BDE420214AAEAE00532BF7 /* BaseListViewController.swift */; }; 48 | 84C4E78A217243F1007EB895 /* SixthListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C4E789217243F1007EB895 /* SixthListViewController.swift */; }; 49 | 84C4E78C2172445C007EB895 /* FeedSectionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84C4E78B2172445C007EB895 /* FeedSectionController.swift */; }; 50 | 84E1D888215A7735005AC6AC /* data1.json in Resources */ = {isa = PBXBuildFile; fileRef = 84E1D887215A7735005AC6AC /* data1.json */; }; 51 | 84E1D88B215A7884005AC6AC /* Feed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E1D88A215A7884005AC6AC /* Feed.swift */; }; 52 | 84E1D88D215A7B75005AC6AC /* JsonTool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E1D88C215A7B75005AC6AC /* JsonTool.swift */; }; 53 | 84E1D890215A80B5005AC6AC /* UserInfoSectionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E1D88F215A80B5005AC6AC /* UserInfoSectionController.swift */; }; 54 | 84E1D894215A817F005AC6AC /* UserInfoCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E1D892215A817F005AC6AC /* UserInfoCell.swift */; }; 55 | 84E1D895215A817F005AC6AC /* UserInfoCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 84E1D893215A817F005AC6AC /* UserInfoCell.xib */; }; 56 | 84E1D898215A8421005AC6AC /* UserInfoCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E1D897215A8421005AC6AC /* UserInfoCellModel.swift */; }; 57 | 84EAB95121AA72C6001AB01A /* FeedBindingSectionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84EAB95021AA72C6001AB01A /* FeedBindingSectionController.swift */; }; 58 | 84EAB95321AA7AE0001AB01A /* SeventhListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84EAB95221AA7AE0001AB01A /* SeventhListViewController.swift */; }; 59 | 84FFB110216BA4920007D6FE /* AnyDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84FFB10D216BA4920007D6FE /* AnyDecodable.swift */; }; 60 | 84FFB111216BA4920007D6FE /* AnyCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84FFB10E216BA4920007D6FE /* AnyCodable.swift */; }; 61 | 84FFB112216BA4920007D6FE /* AnyEncodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84FFB10F216BA4920007D6FE /* AnyEncodable.swift */; }; 62 | DC10661D0FC7E65BB04706E4 /* Pods_IGListKitDemoSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8045177567850F9CE3E779F6 /* Pods_IGListKitDemoSwift.framework */; }; 63 | /* End PBXBuildFile section */ 64 | 65 | /* Begin PBXFileReference section */ 66 | 2C5CF904450BF56E3D35D66B /* Pods-IGListKitDemoSwift.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-IGListKitDemoSwift.debug.xcconfig"; path = "Pods/Target Support Files/Pods-IGListKitDemoSwift/Pods-IGListKitDemoSwift.debug.xcconfig"; sourceTree = ""; }; 67 | 8045177567850F9CE3E779F6 /* Pods_IGListKitDemoSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_IGListKitDemoSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 68 | 8400DED72112056D009D751C /* IGListKitDemoSwift.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = IGListKitDemoSwift.app; sourceTree = BUILT_PRODUCTS_DIR; }; 69 | 8400DEDA2112056D009D751C /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 70 | 8400DEDC2112056D009D751C /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 71 | 8400DEDF2112056D009D751C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 72 | 8400DEE12112056E009D751C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 73 | 8400DEE42112056E009D751C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 74 | 8400DEE62112056E009D751C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 75 | 8411321F216782D700096D3D /* data2.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = data2.json; sourceTree = ""; }; 76 | 841132212167914000096D3D /* FavorSectionController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavorSectionController.swift; sourceTree = ""; }; 77 | 841132232167B2B000096D3D /* ImageCollectionCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageCollectionCell.swift; sourceTree = ""; }; 78 | 841132242167B2B000096D3D /* ImageCollectionCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ImageCollectionCell.xib; sourceTree = ""; }; 79 | 84113227216852B600096D3D /* ImageCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageCell.swift; sourceTree = ""; }; 80 | 84113228216852B600096D3D /* ImageCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ImageCell.xib; sourceTree = ""; }; 81 | 8411322B216853A000096D3D /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = ""; }; 82 | 8411322D2168575900096D3D /* ImageSectionController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageSectionController.swift; sourceTree = ""; }; 83 | 8411322F21685B4400096D3D /* data3.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = data3.json; sourceTree = ""; }; 84 | 8411323121688A5D00096D3D /* ImagesCollectionCellModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagesCollectionCellModel.swift; sourceTree = ""; }; 85 | 841132332168E47100096D3D /* data4.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = data4.json; sourceTree = ""; }; 86 | 841132352168E4EF00096D3D /* CommentCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommentCell.swift; sourceTree = ""; }; 87 | 841132362168E4EF00096D3D /* CommentCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = CommentCell.xib; sourceTree = ""; }; 88 | 841132392168E56500096D3D /* CommentCellModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommentCellModel.swift; sourceTree = ""; }; 89 | 8411323B2168E57200096D3D /* Comment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Comment.swift; sourceTree = ""; }; 90 | 8411323D2168F90200096D3D /* CommentSectionController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommentSectionController.swift; sourceTree = ""; }; 91 | 8411323F216903B900096D3D /* data5.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = data5.json; sourceTree = ""; }; 92 | 841132412169052500096D3D /* Ad.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Ad.swift; sourceTree = ""; }; 93 | 841132432169058A00096D3D /* AdCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdCell.swift; sourceTree = ""; }; 94 | 841132452169079900096D3D /* AdSectionController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdSectionController.swift; sourceTree = ""; }; 95 | 841132472169085E00096D3D /* ListModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListModel.swift; sourceTree = ""; }; 96 | 84681092215FBB8000433E5B /* ContentCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentCell.swift; sourceTree = ""; }; 97 | 84681093215FBB8000433E5B /* ContentCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ContentCell.xib; sourceTree = ""; }; 98 | 84681096215FBD0500433E5B /* ContentSectionController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentSectionController.swift; sourceTree = ""; }; 99 | 84681098215FD0C900433E5B /* FavorCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavorCell.swift; sourceTree = ""; }; 100 | 84681099215FD0C900433E5B /* FavorCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = FavorCell.xib; sourceTree = ""; }; 101 | 8468109C215FD1AC00433E5B /* FavorCellModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavorCellModel.swift; sourceTree = ""; }; 102 | 8481A799214AB0F3000D2FEE /* FirstListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirstListViewController.swift; sourceTree = ""; }; 103 | 8481A79B214AB106000D2FEE /* SecondListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecondListViewController.swift; sourceTree = ""; }; 104 | 8481A79D214AB114000D2FEE /* ThirdListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThirdListViewController.swift; sourceTree = ""; }; 105 | 8481A79F214AB134000D2FEE /* ForthListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForthListViewController.swift; sourceTree = ""; }; 106 | 8481A7A1214AB154000D2FEE /* FifthListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FifthListViewController.swift; sourceTree = ""; }; 107 | 84BDE420214AAEAE00532BF7 /* BaseListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseListViewController.swift; sourceTree = ""; }; 108 | 84C4E789217243F1007EB895 /* SixthListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SixthListViewController.swift; sourceTree = ""; }; 109 | 84C4E78B2172445C007EB895 /* FeedSectionController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedSectionController.swift; sourceTree = ""; }; 110 | 84E1D887215A7735005AC6AC /* data1.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = data1.json; sourceTree = ""; }; 111 | 84E1D88A215A7884005AC6AC /* Feed.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Feed.swift; sourceTree = ""; }; 112 | 84E1D88C215A7B75005AC6AC /* JsonTool.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JsonTool.swift; sourceTree = ""; }; 113 | 84E1D88F215A80B5005AC6AC /* UserInfoSectionController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserInfoSectionController.swift; sourceTree = ""; }; 114 | 84E1D892215A817F005AC6AC /* UserInfoCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserInfoCell.swift; sourceTree = ""; }; 115 | 84E1D893215A817F005AC6AC /* UserInfoCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = UserInfoCell.xib; sourceTree = ""; }; 116 | 84E1D897215A8421005AC6AC /* UserInfoCellModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserInfoCellModel.swift; sourceTree = ""; }; 117 | 84EAB95021AA72C6001AB01A /* FeedBindingSectionController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedBindingSectionController.swift; sourceTree = ""; }; 118 | 84EAB95221AA7AE0001AB01A /* SeventhListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeventhListViewController.swift; sourceTree = ""; }; 119 | 84FFB10D216BA4920007D6FE /* AnyDecodable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyDecodable.swift; sourceTree = ""; }; 120 | 84FFB10E216BA4920007D6FE /* AnyCodable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyCodable.swift; sourceTree = ""; }; 121 | 84FFB10F216BA4920007D6FE /* AnyEncodable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyEncodable.swift; sourceTree = ""; }; 122 | 9DD1BC46992C3C01A94D603D /* Pods-IGListKitDemoSwift.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-IGListKitDemoSwift.release.xcconfig"; path = "Pods/Target Support Files/Pods-IGListKitDemoSwift/Pods-IGListKitDemoSwift.release.xcconfig"; sourceTree = ""; }; 123 | /* End PBXFileReference section */ 124 | 125 | /* Begin PBXFrameworksBuildPhase section */ 126 | 8400DED42112056D009D751C /* Frameworks */ = { 127 | isa = PBXFrameworksBuildPhase; 128 | buildActionMask = 2147483647; 129 | files = ( 130 | DC10661D0FC7E65BB04706E4 /* Pods_IGListKitDemoSwift.framework in Frameworks */, 131 | ); 132 | runOnlyForDeploymentPostprocessing = 0; 133 | }; 134 | /* End PBXFrameworksBuildPhase section */ 135 | 136 | /* Begin PBXGroup section */ 137 | 8400DECE2112056D009D751C = { 138 | isa = PBXGroup; 139 | children = ( 140 | 8400DED92112056D009D751C /* IGListKitDemoSwift */, 141 | 8400DED82112056D009D751C /* Products */, 142 | B03E3B4751BC4C1EC904266E /* Pods */, 143 | B83BB868388DFDB230F49425 /* Frameworks */, 144 | ); 145 | sourceTree = ""; 146 | }; 147 | 8400DED82112056D009D751C /* Products */ = { 148 | isa = PBXGroup; 149 | children = ( 150 | 8400DED72112056D009D751C /* IGListKitDemoSwift.app */, 151 | ); 152 | name = Products; 153 | sourceTree = ""; 154 | }; 155 | 8400DED92112056D009D751C /* IGListKitDemoSwift */ = { 156 | isa = PBXGroup; 157 | children = ( 158 | 84E1D896215A83FF005AC6AC /* CellModel */, 159 | 84E1D891215A815B005AC6AC /* Cell */, 160 | 84E1D88E215A803A005AC6AC /* SectionController */, 161 | 84E1D88C215A7B75005AC6AC /* JsonTool.swift */, 162 | 84E1D889215A773B005AC6AC /* Model */, 163 | 84E1D886215A7728005AC6AC /* data */, 164 | 84BDE422214AAEBA00532BF7 /* ViewController */, 165 | 84FFB10C216BA4920007D6FE /* AnyCodable */, 166 | 8400DEDA2112056D009D751C /* AppDelegate.swift */, 167 | 8400DEDC2112056D009D751C /* ViewController.swift */, 168 | 8400DEDE2112056D009D751C /* Main.storyboard */, 169 | 8400DEE12112056E009D751C /* Assets.xcassets */, 170 | 8400DEE32112056E009D751C /* LaunchScreen.storyboard */, 171 | 8400DEE62112056E009D751C /* Info.plist */, 172 | 8411322B216853A000096D3D /* Extensions.swift */, 173 | ); 174 | path = IGListKitDemoSwift; 175 | sourceTree = ""; 176 | }; 177 | 84BDE422214AAEBA00532BF7 /* ViewController */ = { 178 | isa = PBXGroup; 179 | children = ( 180 | 84BDE420214AAEAE00532BF7 /* BaseListViewController.swift */, 181 | 8481A799214AB0F3000D2FEE /* FirstListViewController.swift */, 182 | 8481A79B214AB106000D2FEE /* SecondListViewController.swift */, 183 | 8481A79D214AB114000D2FEE /* ThirdListViewController.swift */, 184 | 8481A79F214AB134000D2FEE /* ForthListViewController.swift */, 185 | 8481A7A1214AB154000D2FEE /* FifthListViewController.swift */, 186 | 84C4E789217243F1007EB895 /* SixthListViewController.swift */, 187 | 84EAB95221AA7AE0001AB01A /* SeventhListViewController.swift */, 188 | ); 189 | path = ViewController; 190 | sourceTree = ""; 191 | }; 192 | 84E1D886215A7728005AC6AC /* data */ = { 193 | isa = PBXGroup; 194 | children = ( 195 | 84E1D887215A7735005AC6AC /* data1.json */, 196 | 8411321F216782D700096D3D /* data2.json */, 197 | 8411322F21685B4400096D3D /* data3.json */, 198 | 841132332168E47100096D3D /* data4.json */, 199 | 8411323F216903B900096D3D /* data5.json */, 200 | ); 201 | path = data; 202 | sourceTree = ""; 203 | }; 204 | 84E1D889215A773B005AC6AC /* Model */ = { 205 | isa = PBXGroup; 206 | children = ( 207 | 84E1D88A215A7884005AC6AC /* Feed.swift */, 208 | 8411323B2168E57200096D3D /* Comment.swift */, 209 | 841132412169052500096D3D /* Ad.swift */, 210 | 841132472169085E00096D3D /* ListModel.swift */, 211 | ); 212 | path = Model; 213 | sourceTree = ""; 214 | }; 215 | 84E1D88E215A803A005AC6AC /* SectionController */ = { 216 | isa = PBXGroup; 217 | children = ( 218 | 84E1D88F215A80B5005AC6AC /* UserInfoSectionController.swift */, 219 | 84681096215FBD0500433E5B /* ContentSectionController.swift */, 220 | 841132212167914000096D3D /* FavorSectionController.swift */, 221 | 8411322D2168575900096D3D /* ImageSectionController.swift */, 222 | 8411323D2168F90200096D3D /* CommentSectionController.swift */, 223 | 841132452169079900096D3D /* AdSectionController.swift */, 224 | 84C4E78B2172445C007EB895 /* FeedSectionController.swift */, 225 | 84EAB95021AA72C6001AB01A /* FeedBindingSectionController.swift */, 226 | ); 227 | path = SectionController; 228 | sourceTree = ""; 229 | }; 230 | 84E1D891215A815B005AC6AC /* Cell */ = { 231 | isa = PBXGroup; 232 | children = ( 233 | 84E1D892215A817F005AC6AC /* UserInfoCell.swift */, 234 | 84E1D893215A817F005AC6AC /* UserInfoCell.xib */, 235 | 84681092215FBB8000433E5B /* ContentCell.swift */, 236 | 84681093215FBB8000433E5B /* ContentCell.xib */, 237 | 84681098215FD0C900433E5B /* FavorCell.swift */, 238 | 84681099215FD0C900433E5B /* FavorCell.xib */, 239 | 841132232167B2B000096D3D /* ImageCollectionCell.swift */, 240 | 841132242167B2B000096D3D /* ImageCollectionCell.xib */, 241 | 84113227216852B600096D3D /* ImageCell.swift */, 242 | 84113228216852B600096D3D /* ImageCell.xib */, 243 | 841132352168E4EF00096D3D /* CommentCell.swift */, 244 | 841132362168E4EF00096D3D /* CommentCell.xib */, 245 | 841132432169058A00096D3D /* AdCell.swift */, 246 | ); 247 | path = Cell; 248 | sourceTree = ""; 249 | }; 250 | 84E1D896215A83FF005AC6AC /* CellModel */ = { 251 | isa = PBXGroup; 252 | children = ( 253 | 84E1D897215A8421005AC6AC /* UserInfoCellModel.swift */, 254 | 8468109C215FD1AC00433E5B /* FavorCellModel.swift */, 255 | 8411323121688A5D00096D3D /* ImagesCollectionCellModel.swift */, 256 | 841132392168E56500096D3D /* CommentCellModel.swift */, 257 | ); 258 | path = CellModel; 259 | sourceTree = ""; 260 | }; 261 | 84FFB10C216BA4920007D6FE /* AnyCodable */ = { 262 | isa = PBXGroup; 263 | children = ( 264 | 84FFB10D216BA4920007D6FE /* AnyDecodable.swift */, 265 | 84FFB10E216BA4920007D6FE /* AnyCodable.swift */, 266 | 84FFB10F216BA4920007D6FE /* AnyEncodable.swift */, 267 | ); 268 | path = AnyCodable; 269 | sourceTree = ""; 270 | }; 271 | B03E3B4751BC4C1EC904266E /* Pods */ = { 272 | isa = PBXGroup; 273 | children = ( 274 | 2C5CF904450BF56E3D35D66B /* Pods-IGListKitDemoSwift.debug.xcconfig */, 275 | 9DD1BC46992C3C01A94D603D /* Pods-IGListKitDemoSwift.release.xcconfig */, 276 | ); 277 | name = Pods; 278 | sourceTree = ""; 279 | }; 280 | B83BB868388DFDB230F49425 /* Frameworks */ = { 281 | isa = PBXGroup; 282 | children = ( 283 | 8045177567850F9CE3E779F6 /* Pods_IGListKitDemoSwift.framework */, 284 | ); 285 | name = Frameworks; 286 | sourceTree = ""; 287 | }; 288 | /* End PBXGroup section */ 289 | 290 | /* Begin PBXNativeTarget section */ 291 | 8400DED62112056D009D751C /* IGListKitDemoSwift */ = { 292 | isa = PBXNativeTarget; 293 | buildConfigurationList = 8400DEE92112056E009D751C /* Build configuration list for PBXNativeTarget "IGListKitDemoSwift" */; 294 | buildPhases = ( 295 | CAC1F6565FCBE57FD838BDD0 /* [CP] Check Pods Manifest.lock */, 296 | 8400DED32112056D009D751C /* Sources */, 297 | 8400DED42112056D009D751C /* Frameworks */, 298 | 8400DED52112056D009D751C /* Resources */, 299 | 365706A2C8CC7F6F4A799A61 /* [CP] Embed Pods Frameworks */, 300 | ); 301 | buildRules = ( 302 | ); 303 | dependencies = ( 304 | ); 305 | name = IGListKitDemoSwift; 306 | productName = IGListKitDemoSwift; 307 | productReference = 8400DED72112056D009D751C /* IGListKitDemoSwift.app */; 308 | productType = "com.apple.product-type.application"; 309 | }; 310 | /* End PBXNativeTarget section */ 311 | 312 | /* Begin PBXProject section */ 313 | 8400DECF2112056D009D751C /* Project object */ = { 314 | isa = PBXProject; 315 | attributes = { 316 | LastSwiftUpdateCheck = 0940; 317 | LastUpgradeCheck = 0940; 318 | ORGANIZATIONNAME = bruce; 319 | TargetAttributes = { 320 | 8400DED62112056D009D751C = { 321 | CreatedOnToolsVersion = 9.4.1; 322 | LastSwiftMigration = 1000; 323 | }; 324 | }; 325 | }; 326 | buildConfigurationList = 8400DED22112056D009D751C /* Build configuration list for PBXProject "IGListKitDemoSwift" */; 327 | compatibilityVersion = "Xcode 9.3"; 328 | developmentRegion = en; 329 | hasScannedForEncodings = 0; 330 | knownRegions = ( 331 | en, 332 | Base, 333 | ); 334 | mainGroup = 8400DECE2112056D009D751C; 335 | productRefGroup = 8400DED82112056D009D751C /* Products */; 336 | projectDirPath = ""; 337 | projectRoot = ""; 338 | targets = ( 339 | 8400DED62112056D009D751C /* IGListKitDemoSwift */, 340 | ); 341 | }; 342 | /* End PBXProject section */ 343 | 344 | /* Begin PBXResourcesBuildPhase section */ 345 | 8400DED52112056D009D751C /* Resources */ = { 346 | isa = PBXResourcesBuildPhase; 347 | buildActionMask = 2147483647; 348 | files = ( 349 | 8400DEE52112056E009D751C /* LaunchScreen.storyboard in Resources */, 350 | 84E1D888215A7735005AC6AC /* data1.json in Resources */, 351 | 8400DEE22112056E009D751C /* Assets.xcassets in Resources */, 352 | 8411322A216852B600096D3D /* ImageCell.xib in Resources */, 353 | 84E1D895215A817F005AC6AC /* UserInfoCell.xib in Resources */, 354 | 8400DEE02112056D009D751C /* Main.storyboard in Resources */, 355 | 84681095215FBB8000433E5B /* ContentCell.xib in Resources */, 356 | 84113240216903B900096D3D /* data5.json in Resources */, 357 | 841132262167B2B000096D3D /* ImageCollectionCell.xib in Resources */, 358 | 841132342168E47100096D3D /* data4.json in Resources */, 359 | 8468109B215FD0C900433E5B /* FavorCell.xib in Resources */, 360 | 8411323021685B4400096D3D /* data3.json in Resources */, 361 | 841132382168E4EF00096D3D /* CommentCell.xib in Resources */, 362 | 84113220216782D700096D3D /* data2.json in Resources */, 363 | ); 364 | runOnlyForDeploymentPostprocessing = 0; 365 | }; 366 | /* End PBXResourcesBuildPhase section */ 367 | 368 | /* Begin PBXShellScriptBuildPhase section */ 369 | 365706A2C8CC7F6F4A799A61 /* [CP] Embed Pods Frameworks */ = { 370 | isa = PBXShellScriptBuildPhase; 371 | buildActionMask = 2147483647; 372 | files = ( 373 | ); 374 | inputPaths = ( 375 | "${SRCROOT}/Pods/Target Support Files/Pods-IGListKitDemoSwift/Pods-IGListKitDemoSwift-frameworks.sh", 376 | "${BUILT_PRODUCTS_DIR}/IGListKit/IGListKit.framework", 377 | ); 378 | name = "[CP] Embed Pods Frameworks"; 379 | outputPaths = ( 380 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/IGListKit.framework", 381 | ); 382 | runOnlyForDeploymentPostprocessing = 0; 383 | shellPath = /bin/sh; 384 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-IGListKitDemoSwift/Pods-IGListKitDemoSwift-frameworks.sh\"\n"; 385 | showEnvVarsInLog = 0; 386 | }; 387 | CAC1F6565FCBE57FD838BDD0 /* [CP] Check Pods Manifest.lock */ = { 388 | isa = PBXShellScriptBuildPhase; 389 | buildActionMask = 2147483647; 390 | files = ( 391 | ); 392 | inputPaths = ( 393 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 394 | "${PODS_ROOT}/Manifest.lock", 395 | ); 396 | name = "[CP] Check Pods Manifest.lock"; 397 | outputPaths = ( 398 | "$(DERIVED_FILE_DIR)/Pods-IGListKitDemoSwift-checkManifestLockResult.txt", 399 | ); 400 | runOnlyForDeploymentPostprocessing = 0; 401 | shellPath = /bin/sh; 402 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 403 | showEnvVarsInLog = 0; 404 | }; 405 | /* End PBXShellScriptBuildPhase section */ 406 | 407 | /* Begin PBXSourcesBuildPhase section */ 408 | 8400DED32112056D009D751C /* Sources */ = { 409 | isa = PBXSourcesBuildPhase; 410 | buildActionMask = 2147483647; 411 | files = ( 412 | 841132252167B2B000096D3D /* ImageCollectionCell.swift in Sources */, 413 | 841132482169085E00096D3D /* ListModel.swift in Sources */, 414 | 8481A7A0214AB134000D2FEE /* ForthListViewController.swift in Sources */, 415 | 84681094215FBB8000433E5B /* ContentCell.swift in Sources */, 416 | 84EAB95121AA72C6001AB01A /* FeedBindingSectionController.swift in Sources */, 417 | 84E1D88B215A7884005AC6AC /* Feed.swift in Sources */, 418 | 8481A79C214AB106000D2FEE /* SecondListViewController.swift in Sources */, 419 | 84681097215FBD0500433E5B /* ContentSectionController.swift in Sources */, 420 | 8400DEDD2112056D009D751C /* ViewController.swift in Sources */, 421 | 84FFB110216BA4920007D6FE /* AnyDecodable.swift in Sources */, 422 | 84EAB95321AA7AE0001AB01A /* SeventhListViewController.swift in Sources */, 423 | 841132222167914000096D3D /* FavorSectionController.swift in Sources */, 424 | 841132462169079900096D3D /* AdSectionController.swift in Sources */, 425 | 84E1D898215A8421005AC6AC /* UserInfoCellModel.swift in Sources */, 426 | 8411323E2168F90200096D3D /* CommentSectionController.swift in Sources */, 427 | 84113229216852B600096D3D /* ImageCell.swift in Sources */, 428 | 84C4E78A217243F1007EB895 /* SixthListViewController.swift in Sources */, 429 | 84C4E78C2172445C007EB895 /* FeedSectionController.swift in Sources */, 430 | 841132442169058A00096D3D /* AdCell.swift in Sources */, 431 | 8468109D215FD1AC00433E5B /* FavorCellModel.swift in Sources */, 432 | 84BDE421214AAEAE00532BF7 /* BaseListViewController.swift in Sources */, 433 | 8468109A215FD0C900433E5B /* FavorCell.swift in Sources */, 434 | 8411322E2168575900096D3D /* ImageSectionController.swift in Sources */, 435 | 8411322C216853A000096D3D /* Extensions.swift in Sources */, 436 | 841132422169052500096D3D /* Ad.swift in Sources */, 437 | 8481A7A2214AB154000D2FEE /* FifthListViewController.swift in Sources */, 438 | 8411323221688A5D00096D3D /* ImagesCollectionCellModel.swift in Sources */, 439 | 8400DEDB2112056D009D751C /* AppDelegate.swift in Sources */, 440 | 8411323A2168E56500096D3D /* CommentCellModel.swift in Sources */, 441 | 8481A79E214AB114000D2FEE /* ThirdListViewController.swift in Sources */, 442 | 84E1D894215A817F005AC6AC /* UserInfoCell.swift in Sources */, 443 | 8411323C2168E57200096D3D /* Comment.swift in Sources */, 444 | 84FFB112216BA4920007D6FE /* AnyEncodable.swift in Sources */, 445 | 8481A79A214AB0F3000D2FEE /* FirstListViewController.swift in Sources */, 446 | 84FFB111216BA4920007D6FE /* AnyCodable.swift in Sources */, 447 | 84E1D890215A80B5005AC6AC /* UserInfoSectionController.swift in Sources */, 448 | 84E1D88D215A7B75005AC6AC /* JsonTool.swift in Sources */, 449 | 841132372168E4EF00096D3D /* CommentCell.swift in Sources */, 450 | ); 451 | runOnlyForDeploymentPostprocessing = 0; 452 | }; 453 | /* End PBXSourcesBuildPhase section */ 454 | 455 | /* Begin PBXVariantGroup section */ 456 | 8400DEDE2112056D009D751C /* Main.storyboard */ = { 457 | isa = PBXVariantGroup; 458 | children = ( 459 | 8400DEDF2112056D009D751C /* Base */, 460 | ); 461 | name = Main.storyboard; 462 | sourceTree = ""; 463 | }; 464 | 8400DEE32112056E009D751C /* LaunchScreen.storyboard */ = { 465 | isa = PBXVariantGroup; 466 | children = ( 467 | 8400DEE42112056E009D751C /* Base */, 468 | ); 469 | name = LaunchScreen.storyboard; 470 | sourceTree = ""; 471 | }; 472 | /* End PBXVariantGroup section */ 473 | 474 | /* Begin XCBuildConfiguration section */ 475 | 8400DEE72112056E009D751C /* Debug */ = { 476 | isa = XCBuildConfiguration; 477 | buildSettings = { 478 | ALWAYS_SEARCH_USER_PATHS = NO; 479 | CLANG_ANALYZER_NONNULL = YES; 480 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 481 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 482 | CLANG_CXX_LIBRARY = "libc++"; 483 | CLANG_ENABLE_MODULES = YES; 484 | CLANG_ENABLE_OBJC_ARC = YES; 485 | CLANG_ENABLE_OBJC_WEAK = YES; 486 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 487 | CLANG_WARN_BOOL_CONVERSION = YES; 488 | CLANG_WARN_COMMA = YES; 489 | CLANG_WARN_CONSTANT_CONVERSION = YES; 490 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 491 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 492 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 493 | CLANG_WARN_EMPTY_BODY = YES; 494 | CLANG_WARN_ENUM_CONVERSION = YES; 495 | CLANG_WARN_INFINITE_RECURSION = YES; 496 | CLANG_WARN_INT_CONVERSION = YES; 497 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 498 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 499 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 500 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 501 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 502 | CLANG_WARN_STRICT_PROTOTYPES = YES; 503 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 504 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 505 | CLANG_WARN_UNREACHABLE_CODE = YES; 506 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 507 | CODE_SIGN_IDENTITY = "iPhone Developer"; 508 | COPY_PHASE_STRIP = NO; 509 | DEBUG_INFORMATION_FORMAT = dwarf; 510 | ENABLE_STRICT_OBJC_MSGSEND = YES; 511 | ENABLE_TESTABILITY = YES; 512 | GCC_C_LANGUAGE_STANDARD = gnu11; 513 | GCC_DYNAMIC_NO_PIC = NO; 514 | GCC_NO_COMMON_BLOCKS = YES; 515 | GCC_OPTIMIZATION_LEVEL = 0; 516 | GCC_PREPROCESSOR_DEFINITIONS = ( 517 | "DEBUG=1", 518 | "$(inherited)", 519 | ); 520 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 521 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 522 | GCC_WARN_UNDECLARED_SELECTOR = YES; 523 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 524 | GCC_WARN_UNUSED_FUNCTION = YES; 525 | GCC_WARN_UNUSED_VARIABLE = YES; 526 | IPHONEOS_DEPLOYMENT_TARGET = 11.4; 527 | MTL_ENABLE_DEBUG_INFO = YES; 528 | ONLY_ACTIVE_ARCH = YES; 529 | SDKROOT = iphoneos; 530 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 531 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 532 | }; 533 | name = Debug; 534 | }; 535 | 8400DEE82112056E009D751C /* Release */ = { 536 | isa = XCBuildConfiguration; 537 | buildSettings = { 538 | ALWAYS_SEARCH_USER_PATHS = NO; 539 | CLANG_ANALYZER_NONNULL = YES; 540 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 541 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 542 | CLANG_CXX_LIBRARY = "libc++"; 543 | CLANG_ENABLE_MODULES = YES; 544 | CLANG_ENABLE_OBJC_ARC = YES; 545 | CLANG_ENABLE_OBJC_WEAK = YES; 546 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 547 | CLANG_WARN_BOOL_CONVERSION = YES; 548 | CLANG_WARN_COMMA = YES; 549 | CLANG_WARN_CONSTANT_CONVERSION = YES; 550 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 551 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 552 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 553 | CLANG_WARN_EMPTY_BODY = YES; 554 | CLANG_WARN_ENUM_CONVERSION = YES; 555 | CLANG_WARN_INFINITE_RECURSION = YES; 556 | CLANG_WARN_INT_CONVERSION = YES; 557 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 558 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 559 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 560 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 561 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 562 | CLANG_WARN_STRICT_PROTOTYPES = YES; 563 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 564 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 565 | CLANG_WARN_UNREACHABLE_CODE = YES; 566 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 567 | CODE_SIGN_IDENTITY = "iPhone Developer"; 568 | COPY_PHASE_STRIP = NO; 569 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 570 | ENABLE_NS_ASSERTIONS = NO; 571 | ENABLE_STRICT_OBJC_MSGSEND = YES; 572 | GCC_C_LANGUAGE_STANDARD = gnu11; 573 | GCC_NO_COMMON_BLOCKS = YES; 574 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 575 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 576 | GCC_WARN_UNDECLARED_SELECTOR = YES; 577 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 578 | GCC_WARN_UNUSED_FUNCTION = YES; 579 | GCC_WARN_UNUSED_VARIABLE = YES; 580 | IPHONEOS_DEPLOYMENT_TARGET = 11.4; 581 | MTL_ENABLE_DEBUG_INFO = NO; 582 | SDKROOT = iphoneos; 583 | SWIFT_COMPILATION_MODE = wholemodule; 584 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 585 | VALIDATE_PRODUCT = YES; 586 | }; 587 | name = Release; 588 | }; 589 | 8400DEEA2112056E009D751C /* Debug */ = { 590 | isa = XCBuildConfiguration; 591 | baseConfigurationReference = 2C5CF904450BF56E3D35D66B /* Pods-IGListKitDemoSwift.debug.xcconfig */; 592 | buildSettings = { 593 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 594 | CODE_SIGN_STYLE = Automatic; 595 | DEVELOPMENT_TEAM = NS27ZB8WPD; 596 | INFOPLIST_FILE = IGListKitDemoSwift/Info.plist; 597 | LD_RUNPATH_SEARCH_PATHS = ( 598 | "$(inherited)", 599 | "@executable_path/Frameworks", 600 | ); 601 | PRODUCT_BUNDLE_IDENTIFIER = com.bruce.IGListKitDemoSwift; 602 | PRODUCT_NAME = "$(TARGET_NAME)"; 603 | SWIFT_VERSION = 4.2; 604 | TARGETED_DEVICE_FAMILY = "1,2"; 605 | }; 606 | name = Debug; 607 | }; 608 | 8400DEEB2112056E009D751C /* Release */ = { 609 | isa = XCBuildConfiguration; 610 | baseConfigurationReference = 9DD1BC46992C3C01A94D603D /* Pods-IGListKitDemoSwift.release.xcconfig */; 611 | buildSettings = { 612 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 613 | CODE_SIGN_STYLE = Automatic; 614 | DEVELOPMENT_TEAM = NS27ZB8WPD; 615 | INFOPLIST_FILE = IGListKitDemoSwift/Info.plist; 616 | LD_RUNPATH_SEARCH_PATHS = ( 617 | "$(inherited)", 618 | "@executable_path/Frameworks", 619 | ); 620 | PRODUCT_BUNDLE_IDENTIFIER = com.bruce.IGListKitDemoSwift; 621 | PRODUCT_NAME = "$(TARGET_NAME)"; 622 | SWIFT_VERSION = 4.2; 623 | TARGETED_DEVICE_FAMILY = "1,2"; 624 | }; 625 | name = Release; 626 | }; 627 | /* End XCBuildConfiguration section */ 628 | 629 | /* Begin XCConfigurationList section */ 630 | 8400DED22112056D009D751C /* Build configuration list for PBXProject "IGListKitDemoSwift" */ = { 631 | isa = XCConfigurationList; 632 | buildConfigurations = ( 633 | 8400DEE72112056E009D751C /* Debug */, 634 | 8400DEE82112056E009D751C /* Release */, 635 | ); 636 | defaultConfigurationIsVisible = 0; 637 | defaultConfigurationName = Release; 638 | }; 639 | 8400DEE92112056E009D751C /* Build configuration list for PBXNativeTarget "IGListKitDemoSwift" */ = { 640 | isa = XCConfigurationList; 641 | buildConfigurations = ( 642 | 8400DEEA2112056E009D751C /* Debug */, 643 | 8400DEEB2112056E009D751C /* Release */, 644 | ); 645 | defaultConfigurationIsVisible = 0; 646 | defaultConfigurationName = Release; 647 | }; 648 | /* End XCConfigurationList section */ 649 | }; 650 | rootObject = 8400DECF2112056D009D751C /* Project object */; 651 | } 652 | -------------------------------------------------------------------------------- /IGListKitDemoSwift.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /IGListKitDemoSwift.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /IGListKitDemoSwift.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /IGListKitDemoSwift.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/AnyCodable/AnyCodable.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /** 4 | A type-erased `Codable` value. 5 | 6 | The `AnyCodable` type forwards encoding and decoding responsibilities 7 | to an underlying value, hiding its specific underlying type. 8 | 9 | You can encode or decode mixed-type values in dictionaries 10 | and other collections that require `Encodable` or `Decodable` conformance 11 | by declaring their contained type to be `AnyCodable`. 12 | 13 | - SeeAlso: `AnyEncodable` 14 | - SeeAlso: `AnyDecodable` 15 | */ 16 | public struct AnyCodable: Codable { 17 | public let value: Any 18 | 19 | public init(_ value: T?) { 20 | self.value = value ?? () 21 | } 22 | } 23 | 24 | extension AnyCodable: _AnyEncodable, _AnyDecodable {} 25 | 26 | extension AnyCodable: Equatable { 27 | public static func ==(lhs: AnyCodable, rhs: AnyCodable) -> Bool { 28 | switch (lhs.value, rhs.value) { 29 | case is (Void, Void): 30 | return true 31 | case let (lhs as Bool, rhs as Bool): 32 | return lhs == rhs 33 | case let (lhs as Int, rhs as Int): 34 | return lhs == rhs 35 | case let (lhs as Int8, rhs as Int8): 36 | return lhs == rhs 37 | case let (lhs as Int16, rhs as Int16): 38 | return lhs == rhs 39 | case let (lhs as Int32, rhs as Int32): 40 | return lhs == rhs 41 | case let (lhs as Int64, rhs as Int64): 42 | return lhs == rhs 43 | case let (lhs as UInt, rhs as UInt): 44 | return lhs == rhs 45 | case let (lhs as UInt8, rhs as UInt8): 46 | return lhs == rhs 47 | case let (lhs as UInt16, rhs as UInt16): 48 | return lhs == rhs 49 | case let (lhs as UInt32, rhs as UInt32): 50 | return lhs == rhs 51 | case let (lhs as UInt64, rhs as UInt64): 52 | return lhs == rhs 53 | case let (lhs as Float, rhs as Float): 54 | return lhs == rhs 55 | case let (lhs as Double, rhs as Double): 56 | return lhs == rhs 57 | case let (lhs as String, rhs as String): 58 | return lhs == rhs 59 | case (let lhs as [String: AnyCodable], let rhs as [String: AnyCodable]): 60 | return lhs == rhs 61 | case (let lhs as [AnyCodable], let rhs as [AnyCodable]): 62 | return lhs == rhs 63 | default: 64 | return false 65 | } 66 | } 67 | } 68 | 69 | extension AnyCodable: CustomStringConvertible { 70 | public var description: String { 71 | switch value { 72 | case is Void: 73 | return String(describing: nil as Any?) 74 | case let value as CustomStringConvertible: 75 | return value.description 76 | default: 77 | return String(describing: value) 78 | } 79 | } 80 | } 81 | 82 | extension AnyCodable: CustomDebugStringConvertible { 83 | public var debugDescription: String { 84 | switch value { 85 | case let value as CustomDebugStringConvertible: 86 | return "AnyCodable(\(value.debugDescription))" 87 | default: 88 | return "AnyCodable(\(self.description))" 89 | } 90 | } 91 | } 92 | 93 | extension AnyCodable: ExpressibleByNilLiteral, ExpressibleByBooleanLiteral, ExpressibleByIntegerLiteral, ExpressibleByFloatLiteral, ExpressibleByStringLiteral, ExpressibleByArrayLiteral, ExpressibleByDictionaryLiteral {} 94 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/AnyCodable/AnyDecodable.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /** 4 | A type-erased `Decodable` value. 5 | 6 | The `AnyDecodable` type forwards decoding responsibilities 7 | to an underlying value, hiding its specific underlying type. 8 | 9 | You can decode mixed-type values in dictionaries 10 | and other collections that require `Decodable` conformance 11 | by declaring their contained type to be `AnyDecodable`: 12 | 13 | let json = """ 14 | { 15 | "boolean": true, 16 | "integer": 1, 17 | "double": 3.14159265358979323846, 18 | "string": "string", 19 | "array": [1, 2, 3], 20 | "nested": { 21 | "a": "alpha", 22 | "b": "bravo", 23 | "c": "charlie" 24 | } 25 | } 26 | """.data(using: .utf8)! 27 | 28 | let decoder = JSONDecoder() 29 | let dictionary = try! decoder.decode([String: AnyCodable].self, from: json) 30 | */ 31 | public struct AnyDecodable: Decodable { 32 | public let value: Any 33 | 34 | public init(_ value: T?) { 35 | self.value = value ?? () 36 | } 37 | } 38 | 39 | protocol _AnyDecodable { 40 | var value: Any { get } 41 | init(_ value: T?) 42 | } 43 | 44 | extension AnyDecodable: _AnyDecodable {} 45 | 46 | extension _AnyDecodable { 47 | public init(from decoder: Decoder) throws { 48 | let container = try decoder.singleValueContainer() 49 | 50 | if container.decodeNil() { 51 | self.init(()) 52 | } else if let bool = try? container.decode(Bool.self) { 53 | self.init(bool) 54 | } else if let int = try? container.decode(Int.self) { 55 | self.init(int) 56 | } else if let uint = try? container.decode(UInt.self) { 57 | self.init(uint) 58 | } else if let double = try? container.decode(Double.self) { 59 | self.init(double) 60 | } else if let string = try? container.decode(String.self) { 61 | self.init(string) 62 | } else if let array = try? container.decode([AnyCodable].self) { 63 | self.init(array.map { $0.value }) 64 | } else if let dictionary = try? container.decode([String: AnyCodable].self) { 65 | self.init(dictionary.mapValues { $0.value }) 66 | } else { 67 | throw DecodingError.dataCorruptedError(in: container, debugDescription: "AnyCodable value cannot be decoded") 68 | } 69 | } 70 | } 71 | 72 | extension AnyDecodable: Equatable { 73 | public static func ==(lhs: AnyDecodable, rhs: AnyDecodable) -> Bool { 74 | switch (lhs.value, rhs.value) { 75 | case is (Void, Void): 76 | return true 77 | case let (lhs as Bool, rhs as Bool): 78 | return lhs == rhs 79 | case let (lhs as Int, rhs as Int): 80 | return lhs == rhs 81 | case let (lhs as Int8, rhs as Int8): 82 | return lhs == rhs 83 | case let (lhs as Int16, rhs as Int16): 84 | return lhs == rhs 85 | case let (lhs as Int32, rhs as Int32): 86 | return lhs == rhs 87 | case let (lhs as Int64, rhs as Int64): 88 | return lhs == rhs 89 | case let (lhs as UInt, rhs as UInt): 90 | return lhs == rhs 91 | case let (lhs as UInt8, rhs as UInt8): 92 | return lhs == rhs 93 | case let (lhs as UInt16, rhs as UInt16): 94 | return lhs == rhs 95 | case let (lhs as UInt32, rhs as UInt32): 96 | return lhs == rhs 97 | case let (lhs as UInt64, rhs as UInt64): 98 | return lhs == rhs 99 | case let (lhs as Float, rhs as Float): 100 | return lhs == rhs 101 | case let (lhs as Double, rhs as Double): 102 | return lhs == rhs 103 | case let (lhs as String, rhs as String): 104 | return lhs == rhs 105 | case (let lhs as [String: AnyDecodable], let rhs as [String: AnyDecodable]): 106 | return lhs == rhs 107 | case (let lhs as [AnyDecodable], let rhs as [AnyDecodable]): 108 | return lhs == rhs 109 | default: 110 | return false 111 | } 112 | } 113 | } 114 | 115 | extension AnyDecodable: CustomStringConvertible { 116 | public var description: String { 117 | switch value { 118 | case is Void: 119 | return String(describing: nil as Any?) 120 | case let value as CustomStringConvertible: 121 | return value.description 122 | default: 123 | return String(describing: value) 124 | } 125 | } 126 | } 127 | 128 | extension AnyDecodable: CustomDebugStringConvertible { 129 | public var debugDescription: String { 130 | switch value { 131 | case let value as CustomDebugStringConvertible: 132 | return "AnyDecodable(\(value.debugDescription))" 133 | default: 134 | return "AnyDecodable(\(self.description))" 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/AnyCodable/AnyEncodable.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /** 4 | A type-erased `Encodable` value. 5 | 6 | The `AnyEncodable` type forwards encoding responsibilities 7 | to an underlying value, hiding its specific underlying type. 8 | 9 | You can encode mixed-type values in dictionaries 10 | and other collections that require `Encodable` conformance 11 | by declaring their contained type to be `AnyEncodable`: 12 | 13 | let dictionary: [String: AnyEncodable] = [ 14 | "boolean": true, 15 | "integer": 1, 16 | "double": 3.14159265358979323846, 17 | "string": "string", 18 | "array": [1, 2, 3], 19 | "nested": [ 20 | "a": "alpha", 21 | "b": "bravo", 22 | "c": "charlie" 23 | ] 24 | ] 25 | 26 | let encoder = JSONEncoder() 27 | let json = try! encoder.encode(dictionary) 28 | */ 29 | public struct AnyEncodable: Encodable { 30 | public let value: Any 31 | 32 | public init(_ value: T?) { 33 | self.value = value ?? () 34 | } 35 | } 36 | 37 | protocol _AnyEncodable { 38 | var value: Any { get } 39 | init(_ value: T?) 40 | } 41 | 42 | 43 | extension AnyEncodable: _AnyEncodable {} 44 | 45 | // MARK: - Encodable 46 | 47 | extension _AnyEncodable { 48 | public func encode(to encoder: Encoder) throws { 49 | var container = encoder.singleValueContainer() 50 | 51 | switch self.value { 52 | case is Void: 53 | try container.encodeNil() 54 | case let bool as Bool: 55 | try container.encode(bool) 56 | case let int as Int: 57 | try container.encode(int) 58 | case let int8 as Int8: 59 | try container.encode(int8) 60 | case let int16 as Int16: 61 | try container.encode(int16) 62 | case let int32 as Int32: 63 | try container.encode(int32) 64 | case let int64 as Int64: 65 | try container.encode(int64) 66 | case let uint as UInt: 67 | try container.encode(uint) 68 | case let uint8 as UInt8: 69 | try container.encode(uint8) 70 | case let uint16 as UInt16: 71 | try container.encode(uint16) 72 | case let uint32 as UInt32: 73 | try container.encode(uint32) 74 | case let uint64 as UInt64: 75 | try container.encode(uint64) 76 | case let float as Float: 77 | try container.encode(float) 78 | case let double as Double: 79 | try container.encode(double) 80 | case let string as String: 81 | try container.encode(string) 82 | case let date as Date: 83 | try container.encode(date) 84 | case let url as URL: 85 | try container.encode(url) 86 | case let array as [Any?]: 87 | try container.encode(array.map { AnyCodable($0) }) 88 | case let dictionary as [String: Any?]: 89 | try container.encode(dictionary.mapValues { AnyCodable($0) }) 90 | default: 91 | let context = EncodingError.Context(codingPath: container.codingPath, debugDescription: "AnyCodable value cannot be encoded") 92 | throw EncodingError.invalidValue(self.value, context) 93 | } 94 | } 95 | } 96 | 97 | extension AnyEncodable: Equatable { 98 | public static func ==(lhs: AnyEncodable, rhs: AnyEncodable) -> Bool { 99 | switch (lhs.value, rhs.value) { 100 | case is (Void, Void): 101 | return true 102 | case let (lhs as Bool, rhs as Bool): 103 | return lhs == rhs 104 | case let (lhs as Int, rhs as Int): 105 | return lhs == rhs 106 | case let (lhs as Int8, rhs as Int8): 107 | return lhs == rhs 108 | case let (lhs as Int16, rhs as Int16): 109 | return lhs == rhs 110 | case let (lhs as Int32, rhs as Int32): 111 | return lhs == rhs 112 | case let (lhs as Int64, rhs as Int64): 113 | return lhs == rhs 114 | case let (lhs as UInt, rhs as UInt): 115 | return lhs == rhs 116 | case let (lhs as UInt8, rhs as UInt8): 117 | return lhs == rhs 118 | case let (lhs as UInt16, rhs as UInt16): 119 | return lhs == rhs 120 | case let (lhs as UInt32, rhs as UInt32): 121 | return lhs == rhs 122 | case let (lhs as UInt64, rhs as UInt64): 123 | return lhs == rhs 124 | case let (lhs as Float, rhs as Float): 125 | return lhs == rhs 126 | case let (lhs as Double, rhs as Double): 127 | return lhs == rhs 128 | case let (lhs as String, rhs as String): 129 | return lhs == rhs 130 | case (let lhs as [String: AnyEncodable], let rhs as [String: AnyEncodable]): 131 | return lhs == rhs 132 | case (let lhs as [AnyEncodable], let rhs as [AnyEncodable]): 133 | return lhs == rhs 134 | default: 135 | return false 136 | } 137 | } 138 | } 139 | 140 | extension AnyEncodable: CustomStringConvertible { 141 | public var description: String { 142 | switch value { 143 | case is Void: 144 | return String(describing: nil as Any?) 145 | case let value as CustomStringConvertible: 146 | return value.description 147 | default: 148 | return String(describing: value) 149 | } 150 | } 151 | } 152 | 153 | extension AnyEncodable: CustomDebugStringConvertible { 154 | public var debugDescription: String { 155 | switch value { 156 | case let value as CustomDebugStringConvertible: 157 | return "AnyEncodable(\(value.debugDescription))" 158 | default: 159 | return "AnyEncodable(\(self.description))" 160 | } 161 | } 162 | } 163 | 164 | extension AnyEncodable: ExpressibleByNilLiteral, ExpressibleByBooleanLiteral, ExpressibleByIntegerLiteral, ExpressibleByFloatLiteral, ExpressibleByStringLiteral, ExpressibleByArrayLiteral, ExpressibleByDictionaryLiteral {} 165 | 166 | extension _AnyEncodable { 167 | public init(nilLiteral: ()) { 168 | self.init(nil as Any?) 169 | } 170 | 171 | public init(booleanLiteral value: Bool) { 172 | self.init(value) 173 | } 174 | 175 | public init(integerLiteral value: Int) { 176 | self.init(value) 177 | } 178 | 179 | public init(floatLiteral value: Double) { 180 | self.init(value) 181 | } 182 | 183 | public init(extendedGraphemeClusterLiteral value: String) { 184 | self.init(value) 185 | } 186 | 187 | public init(stringLiteral value: String) { 188 | self.init(value) 189 | } 190 | 191 | public init(arrayLiteral elements: Any...) { 192 | self.init(elements) 193 | } 194 | 195 | public init(dictionaryLiteral elements: (AnyHashable, Any)...) { 196 | self.init(Dictionary(elements, uniquingKeysWith: { (first, _) in first })) 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // IGListKitDemoSwift 4 | // 5 | // Created by gxy on 2018/8/1. 6 | // Copyright © 2018年 bruce. 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: [UIApplication.LaunchOptionsKey: 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 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/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 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /IGListKitDemoSwift/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /IGListKitDemoSwift/Assets.xcassets/arrow_down.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "arrow_down@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /IGListKitDemoSwift/Assets.xcassets/arrow_down.imageset/arrow_down@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bruce-pac/IGListKitDemoSwift/7c9216db78d4c810edd76078e57b86e1ad746a76/IGListKitDemoSwift/Assets.xcassets/arrow_down.imageset/arrow_down@2x.png -------------------------------------------------------------------------------- /IGListKitDemoSwift/Assets.xcassets/comment.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "comment.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /IGListKitDemoSwift/Assets.xcassets/comment.imageset/comment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bruce-pac/IGListKitDemoSwift/7c9216db78d4c810edd76078e57b86e1ad746a76/IGListKitDemoSwift/Assets.xcassets/comment.imageset/comment.png -------------------------------------------------------------------------------- /IGListKitDemoSwift/Assets.xcassets/praise.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "praise.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /IGListKitDemoSwift/Assets.xcassets/praise.imageset/praise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bruce-pac/IGListKitDemoSwift/7c9216db78d4c810edd76078e57b86e1ad746a76/IGListKitDemoSwift/Assets.xcassets/praise.imageset/praise.png -------------------------------------------------------------------------------- /IGListKitDemoSwift/Assets.xcassets/praise_selected.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "praise_selected.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /IGListKitDemoSwift/Assets.xcassets/praise_selected.imageset/praise_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bruce-pac/IGListKitDemoSwift/7c9216db78d4c810edd76078e57b86e1ad746a76/IGListKitDemoSwift/Assets.xcassets/praise_selected.imageset/praise_selected.png -------------------------------------------------------------------------------- /IGListKitDemoSwift/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 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/Cell/AdCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AdCell.swift 3 | // IGListKitDemoSwift 4 | // 5 | // Created by gxy on 2018/10/6. 6 | // Copyright © 2018年 bruce. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class AdCell: UICollectionViewCell { 12 | private let label: UILabel = { 13 | let label = UILabel(frame: .zero) 14 | label.textAlignment = NSTextAlignment.center 15 | label.autoresizingMask = [.flexibleWidth,.flexibleHeight] 16 | return label 17 | }() 18 | 19 | var adTitle: String = "" { 20 | didSet { 21 | label.text = adTitle 22 | } 23 | } 24 | 25 | override init(frame: CGRect) { 26 | super.init(frame: frame) 27 | contentView.addSubview(label) 28 | } 29 | 30 | override func layoutSubviews() { 31 | super.layoutSubviews() 32 | label.frame = contentView.bounds 33 | } 34 | 35 | required init?(coder aDecoder: NSCoder) { 36 | fatalError("init(coder:) has not been implemented") 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/Cell/CommentCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CommentCell.swift 3 | // IGListKitDemoSwift 4 | // 5 | // Created by gxy on 2018/10/6. 6 | // Copyright © 2018年 bruce. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import IGListKit 11 | 12 | class CommentCell: UICollectionViewCell { 13 | @IBOutlet weak var textLabel: UILabel! 14 | 15 | var viewModel: CommentCellModel? 16 | 17 | 18 | public var onClickDelete: ((CommentCell) -> Void)? 19 | 20 | override func awakeFromNib() { 21 | super.awakeFromNib() 22 | // Initialization code 23 | } 24 | @IBAction private func onClickDelete(_ sender: Any) { 25 | onClickDelete?(self) 26 | } 27 | } 28 | 29 | extension CommentCell: ListBindable { 30 | func bindViewModel(_ viewModel: Any) { 31 | guard let viewModel = viewModel as? CommentCellModel else { return } 32 | self.viewModel = viewModel 33 | textLabel.attributedText = viewModel.commentStr 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/Cell/CommentCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 28 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/Cell/ContentCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentCell.swift 3 | // IGListKitDemoSwift 4 | // 5 | // Created by gxy on 2018/9/29. 6 | // Copyright © 2018年 bruce. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import IGListKit 11 | 12 | class ContentCell: UICollectionViewCell { 13 | @IBOutlet weak var label: UILabel! 14 | 15 | override func awakeFromNib() { 16 | super.awakeFromNib() 17 | // Initialization code 18 | } 19 | static func lineHeight() -> CGFloat { 20 | return UIFont.systemFont(ofSize: 16).lineHeight 21 | } 22 | static func height(for text: NSString,limitwidth: CGFloat) -> CGFloat { 23 | let font = UIFont.systemFont(ofSize: 16) 24 | let size: CGSize = CGSize(width: limitwidth - 20, height: CGFloat.greatestFiniteMagnitude) 25 | let rect = text.boundingRect(with: size, options: [.usesFontLeading,.usesLineFragmentOrigin], attributes: [NSAttributedString.Key.font:font], context: nil) 26 | return ceil(rect.height) 27 | } 28 | } 29 | 30 | extension ContentCell: ListBindable { 31 | func bindViewModel(_ viewModel: Any) { 32 | guard let vm = viewModel as? String else { return } 33 | self.label.text = vm 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/Cell/ContentCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/Cell/FavorCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FavorCell.swift 3 | // IGListKitDemoSwift 4 | // 5 | // Created by gxy on 2018/9/29. 6 | // Copyright © 2018年 bruce. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import IGListKit 11 | 12 | class FavorCell: UICollectionViewCell { 13 | @IBOutlet weak var favorBtn: UIButton! 14 | @IBOutlet weak var nameLabel: UILabel! 15 | 16 | var favorOperation: ((FavorCell) -> Void)? 17 | 18 | var viewModel: FavorCellModel? 19 | 20 | override func awakeFromNib() { 21 | super.awakeFromNib() 22 | // Initialization code 23 | } 24 | 25 | @IBAction func onClickFavor(_ sender: Any) { 26 | self.favorOperation!(self) 27 | } 28 | 29 | } 30 | 31 | extension FavorCell: ListBindable { 32 | func bindViewModel(_ viewModel: Any) { 33 | guard let viewModel = viewModel as? FavorCellModel else { return } 34 | self.viewModel = viewModel 35 | self.favorBtn.isSelected = viewModel.isFavor 36 | self.nameLabel.text = viewModel.favorNum 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/Cell/FavorCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 30 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/Cell/ImageCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ImageCell.swift 3 | // IGListKitDemoSwift 4 | // 5 | // Created by gxy on 2018/10/6. 6 | // Copyright © 2018年 bruce. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ImageCell: UICollectionViewCell { 12 | @IBOutlet weak var imageView: UIImageView! 13 | 14 | var image: UIImage! = UIImage.image(with: UIColor.gray) { 15 | didSet { 16 | imageView.image = image 17 | } 18 | } 19 | 20 | override func awakeFromNib() { 21 | super.awakeFromNib() 22 | // Initialization code 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/Cell/ImageCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/Cell/ImageCollectionCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ImageCollectionCell.swift 3 | // IGListKitDemoSwift 4 | // 5 | // Created by gxy on 2018/10/5. 6 | // Copyright © 2018年 bruce. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import IGListKit 11 | 12 | class ImageCollectionCell: UICollectionViewCell { 13 | 14 | let padding: CGFloat = 10 15 | 16 | @IBOutlet weak var collectionView: UICollectionView! 17 | 18 | var viewModel: ImagesCollectionCellModel! 19 | 20 | override func awakeFromNib() { 21 | super.awakeFromNib() 22 | collectionView.register(UINib(nibName: ImageCell.cellIdentifier, bundle: nil), forCellWithReuseIdentifier: ImageCell.cellIdentifier) 23 | } 24 | 25 | } 26 | 27 | extension ImageCollectionCell: ListBindable { 28 | func bindViewModel(_ viewModel: Any) { 29 | guard let viewModel = viewModel as? ImagesCollectionCellModel else { return } 30 | self.viewModel = viewModel 31 | collectionView.reloadData() 32 | } 33 | } 34 | 35 | extension ImageCollectionCell: UICollectionViewDataSource { 36 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 37 | return (self.viewModel?.images.count)! 38 | } 39 | 40 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 41 | guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ImageCell.cellIdentifier, for: indexPath) as? ImageCell else { fatalError() } 42 | cell.image = self.viewModel?.images[indexPath.item] 43 | return cell 44 | } 45 | } 46 | 47 | extension ImageCollectionCell: UICollectionViewDelegateFlowLayout { 48 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { 49 | let width: CGFloat = (collectionView.bounds.width - padding * 2) / 3 50 | return CGSize(width: width, height: width) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/Cell/ImageCollectionCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/Cell/UserInfoCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserInfoCell.swift 3 | // IGListKitDemoSwift 4 | // 5 | // Created by gxy on 2018/9/25. 6 | // Copyright © 2018年 bruce. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import IGListKit 11 | 12 | class UserInfoCell: UICollectionViewCell { 13 | 14 | @IBOutlet weak var avatarView: UIImageView! 15 | @IBOutlet weak var nameLabel: UILabel! 16 | public var onClickArrow: ((UserInfoCell) -> Void)? 17 | override func awakeFromNib() { 18 | super.awakeFromNib() 19 | self.avatarView.layer.cornerRadius = 12 20 | } 21 | 22 | @IBAction private func onClickArrow(_ sender: Any) { 23 | onClickArrow?(self) 24 | } 25 | 26 | } 27 | 28 | extension UserInfoCell: ListBindable { 29 | func bindViewModel(_ viewModel: Any) { 30 | guard let viewModel = viewModel as? UserInfoCellModel else { return } 31 | self.avatarView.backgroundColor = UIColor.purple 32 | self.nameLabel.text = viewModel.userName 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/Cell/UserInfoCell.xib: -------------------------------------------------------------------------------- 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 | 35 | 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 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/CellModel/CommentCellModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CommentCellModel.swift 3 | // IGListKitDemoSwift 4 | // 5 | // Created by gxy on 2018/10/6. 6 | // Copyright © 2018年 bruce. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import IGListKit 11 | 12 | class CommentCellModel: NSObject { 13 | private(set) var commentStr: NSAttributedString! 14 | 15 | var comment: Comment! { 16 | didSet { 17 | let str: String = comment.person + "回复了:" + comment.comment 18 | let attr: NSMutableAttributedString = NSMutableAttributedString(string: str) 19 | let nsrange = NSRange(location: 0, length: comment.person.count) 20 | attr.addAttributes([NSAttributedString.Key.foregroundColor: UIColor.green], range: nsrange) 21 | commentStr = attr 22 | } 23 | } 24 | } 25 | 26 | extension CommentCellModel: ListDiffable { 27 | func diffIdentifier() -> NSObjectProtocol { 28 | return self 29 | } 30 | func isEqual(toDiffableObject object: ListDiffable?) -> Bool { 31 | if self === object { 32 | return true 33 | } 34 | guard let obj = object as? CommentCellModel else { return false } 35 | return self.commentStr == obj.commentStr 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/CellModel/FavorCellModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FavorCellModel.swift 3 | // IGListKitDemoSwift 4 | // 5 | // Created by gxy on 2018/9/29. 6 | // Copyright © 2018年 bruce. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import IGListKit 11 | 12 | class FavorCellModel: NSObject { 13 | private(set) var isFavor: Bool = false 14 | private(set) var favorNum: String = "" 15 | 16 | var feed: Feed! { 17 | didSet { 18 | isFavor = feed.isFavor 19 | favorNum = "\(feed.favor!)个👍" 20 | } 21 | } 22 | } 23 | 24 | extension FavorCellModel: ListDiffable { 25 | func diffIdentifier() -> NSObjectProtocol { 26 | return NSNumber(value: (self.feed?.feedId)!) 27 | } 28 | func isEqual(toDiffableObject object: ListDiffable?) -> Bool { 29 | if self === object { 30 | return true 31 | } 32 | guard let obj = object as? FavorCellModel else { return false } 33 | return (self.isFavor == obj.isFavor) && (self.favorNum == obj.favorNum) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/CellModel/ImagesCollectionCellModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ImagesCollectionCellModel.swift 3 | // IGListKitDemoSwift 4 | // 5 | // Created by gxy on 2018/10/6. 6 | // Copyright © 2018年 bruce. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import IGListKit 11 | 12 | class ImagesCollectionCellModel: NSObject { 13 | private(set) var images: [UIImage] = [] 14 | var imageNames: [String] = [] { 15 | didSet { 16 | let a: [UIImage] = imageNames.map { (color) -> UIImage in 17 | var image: UIImage? 18 | switch color { 19 | case "red": 20 | image = UIImage.image(with: UIColor.red) 21 | case "blue": 22 | image = UIImage.image(with: UIColor.blue) 23 | case "yellow": 24 | image = UIImage.image(with: UIColor.yellow) 25 | case "green": 26 | image = UIImage.image(with: UIColor.green) 27 | default: 28 | image = UIImage.image(with: UIColor.gray) 29 | } 30 | return image! 31 | } 32 | images = a 33 | } 34 | } 35 | } 36 | 37 | extension ImagesCollectionCellModel: ListDiffable { 38 | func diffIdentifier() -> NSObjectProtocol { 39 | return self 40 | } 41 | func isEqual(toDiffableObject object: ListDiffable?) -> Bool { 42 | if self === object { 43 | return true 44 | } 45 | guard let obj = object as? ImagesCollectionCellModel else { return false } 46 | return self.imageNames == obj.imageNames 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/CellModel/UserInfoCellModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserInfoCellModel.swift 3 | // IGListKitDemoSwift 4 | // 5 | // Created by gxy on 2018/9/25. 6 | // Copyright © 2018年 bruce. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import IGListKit 11 | 12 | class UserInfoCellModel { 13 | var avatar: URL? 14 | var userName: String = "" 15 | init(avatar: URL?, userName: String) { 16 | self.avatar = avatar 17 | self.userName = userName 18 | } 19 | } 20 | 21 | extension UserInfoCellModel: ListDiffable { 22 | func diffIdentifier() -> NSObjectProtocol { 23 | return userName as NSObjectProtocol 24 | } 25 | func isEqual(toDiffableObject object: ListDiffable?) -> Bool { 26 | if self === object { 27 | return true 28 | } 29 | guard let obj = object as? UserInfoCellModel else { return false } 30 | return self.userName == obj.userName 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Extensions.swift 3 | // IGListKitDemoSwift 4 | // 5 | // Created by gxy on 2018/10/6. 6 | // Copyright © 2018年 bruce. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UIImage { 12 | static func image(with color: UIColor,size: CGSize = CGSize(width: 1, height: 1)) -> UIImage? { 13 | let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height) 14 | UIGraphicsBeginImageContext(size) 15 | let context = UIGraphicsGetCurrentContext() 16 | context?.setFillColor(color.cgColor) 17 | context?.fill(rect) 18 | let image = UIGraphicsGetImageFromCurrentImageContext() 19 | UIGraphicsEndImageContext() 20 | return image 21 | } 22 | } 23 | 24 | extension UICollectionViewCell { 25 | static var cellIdentifier: String { 26 | get { 27 | let a = NSStringFromClass(self) 28 | let className = a.split(separator: ".").last 29 | return String(className!) 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/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 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/JsonTool.swift: -------------------------------------------------------------------------------- 1 | // 2 | // JsonTool.swift 3 | // JsonTest 4 | // 5 | // Created by gxy on 2018/7/29. 6 | // Copyright © 2018年 Dinghaotech. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class JsonTool { 12 | open class func decode(_: T.Type, jsonfileName json: String, from bundle: Bundle! = Bundle.main) throws -> T where T: Decodable { 13 | let url = bundle.url(forResource: json, withExtension: "json") 14 | var data = Data() 15 | if let gUrl = url { data = try Data(contentsOf: gUrl) } 16 | let decode = JSONDecoder() 17 | let items = try decode.decode(T.self, from: data) 18 | return items 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/Model/Ad.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Ad.swift 3 | // IGListKitDemoSwift 4 | // 5 | // Created by gxy on 2018/10/6. 6 | // Copyright © 2018年 bruce. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import IGListKit 11 | 12 | class Ad: Codable { 13 | var adTitle: String = "" 14 | var adUrl: String = "" 15 | } 16 | 17 | extension Ad: ListDiffable { 18 | func diffIdentifier() -> NSObjectProtocol { 19 | return adTitle as NSObjectProtocol 20 | } 21 | func isEqual(toDiffableObject object: ListDiffable?) -> Bool { 22 | guard self !== object else { return true } 23 | guard let object = object as? Ad else { return false } 24 | return adTitle == object.adTitle 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/Model/Comment.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Comment.swift 3 | // IGListKitDemoSwift 4 | // 5 | // Created by gxy on 2018/10/6. 6 | // Copyright © 2018年 bruce. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class Comment: Codable { 12 | var comment: String = "" 13 | var person: String = "" 14 | } 15 | 16 | extension Comment: Equatable { 17 | static func == (lhs: Comment, rhs: Comment) -> Bool { 18 | return (lhs.comment == rhs.comment) && (lhs.person == rhs.person) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/Model/Feed.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Feed.swift 3 | // IGListKitDemoSwift 4 | // 5 | // Created by gxy on 2018/9/25. 6 | // Copyright © 2018年 bruce. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import IGListKit 11 | 12 | final class Feed: Codable { 13 | var feedId: UInt 14 | var avatar: String = "" 15 | var userName: String = "" 16 | var content: String? = "" 17 | var isFavor: Bool! = false 18 | var favor: UInt! 19 | var images: [String]! = [] 20 | var comments: [Comment]? 21 | 22 | } 23 | 24 | extension Feed: ListDiffable { 25 | func diffIdentifier() -> NSObjectProtocol { 26 | return feedId as NSObjectProtocol 27 | } 28 | func isEqual(toDiffableObject object: ListDiffable?) -> Bool { 29 | guard self !== object else { return true } 30 | guard let object = object as? Feed else { return false } 31 | return feedId == object.feedId 32 | } 33 | } 34 | 35 | extension Feed: Equatable { 36 | static func == (lhs: Feed, rhs: Feed) -> Bool { 37 | return lhs.isEqual(toDiffableObject: rhs) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/Model/ListModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ListModel.swift 3 | // IGListKitDemoSwift 4 | // 5 | // Created by gxy on 2018/10/6. 6 | // Copyright © 2018年 bruce. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import IGListKit 11 | 12 | typealias DecodableListDiffable = Decodable & ListDiffable 13 | 14 | enum DataType { 15 | case ad(ListModel) 16 | case feed(ListModel) 17 | func value() -> DecodableListDiffable { 18 | switch self { 19 | case let .ad(r): 20 | return r.data 21 | case let .feed(r): 22 | return r.data 23 | } 24 | } 25 | } 26 | 27 | extension DataType: Decodable where T: Decodable, U: Decodable { 28 | init(from decoder: Decoder) throws { 29 | if let value = try? ListModel(from: decoder) { 30 | self = .ad(value) 31 | }else if let value = try? ListModel(from: decoder){ 32 | self = .feed(value) 33 | }else{ 34 | let context = DecodingError.Context( 35 | codingPath: decoder.codingPath, 36 | debugDescription: 37 | "Cannot decode \(T.self) or \(U.self)" 38 | ) 39 | throw DecodingError.dataCorrupted(context) 40 | } 41 | } 42 | } 43 | 44 | class ListModel: Decodable { 45 | var data: T! 46 | } 47 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/SectionController/AdSectionController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AdSectionController.swift 3 | // IGListKitDemoSwift 4 | // 5 | // Created by gxy on 2018/10/6. 6 | // Copyright © 2018年 bruce. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import IGListKit 11 | 12 | class AdSectionController: ListSectionController { 13 | 14 | var object: Ad! 15 | 16 | override func numberOfItems() -> Int { 17 | return 1 18 | } 19 | override func sizeForItem(at index: Int) -> CGSize { 20 | let width: CGFloat! = collectionContext?.containerSize(for: self).width 21 | return CGSize(width: width, height: 100) 22 | } 23 | override func cellForItem(at index: Int) -> UICollectionViewCell { 24 | guard let cell = collectionContext?.dequeueReusableCell(of: AdCell.self, for: self, at: index) as? AdCell else { fatalError() } 25 | cell.adTitle = object.adTitle 26 | return cell 27 | } 28 | override func didUpdate(to object: Any) { 29 | self.object = object as? Ad 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/SectionController/CommentSectionController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CommentSectionController.swift 3 | // IGListKitDemoSwift 4 | // 5 | // Created by gxy on 2018/10/6. 6 | // Copyright © 2018年 bruce. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import IGListKit 11 | 12 | class CommentSectionController: ListSectionController { 13 | 14 | var object: Feed! 15 | lazy var viewModels: [CommentCellModel] = { 16 | let vms: [CommentCellModel] = object.comments?.map({ (comment) -> CommentCellModel in 17 | let vm = CommentCellModel() 18 | vm.comment = comment 19 | return vm 20 | }) ?? [] 21 | return vms 22 | }() 23 | 24 | override func numberOfItems() -> Int { 25 | return viewModels.count 26 | } 27 | 28 | override func sizeForItem(at index: Int) -> CGSize { 29 | let width: CGFloat! = collectionContext?.containerSize(for: self).width 30 | return CGSize(width: width, height: 44) 31 | } 32 | 33 | override func cellForItem(at index: Int) -> UICollectionViewCell { 34 | guard let cell = collectionContext?.dequeueReusableCell(withNibName: CommentCell.cellIdentifier, bundle: nil, for: self, at: index) as? CommentCell else { fatalError() } 35 | cell.bindViewModel(viewModels[index]) 36 | cell.onClickDelete = {[weak self] (deleteCell) in 37 | guard let self = self else { 38 | return 39 | } 40 | self.collectionContext?.performBatch(animated: true, updates: { (batch) in 41 | let deleteIndex: Int! = self.collectionContext?.index(for: deleteCell, sectionController: self) 42 | self.viewModels.remove(at: deleteIndex) 43 | batch.delete(in: self, at: IndexSet(integer: deleteIndex)) 44 | }, completion: nil) 45 | } 46 | return cell 47 | } 48 | 49 | override func didUpdate(to object: Any) { 50 | self.object = object as? Feed 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/SectionController/ContentSectionController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentSectionController.swift 3 | // IGListKitDemoSwift 4 | // 5 | // Created by gxy on 2018/9/29. 6 | // Copyright © 2018年 bruce. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import IGListKit 11 | 12 | class ContentSectionController: ListSectionController { 13 | var object: Feed! 14 | var expanded: Bool = false 15 | 16 | override func numberOfItems() -> Int { 17 | if object.content?.isEmpty ?? true { 18 | return 0 19 | } 20 | return 1 21 | } 22 | 23 | override func sizeForItem(at index: Int) -> CGSize { 24 | guard let content = object.content else { return CGSize.zero } 25 | let width: CGFloat! = collectionContext?.containerSize(for: self).width 26 | let height = expanded ? ContentCell.height(for: content as NSString, limitwidth: width) : ContentCell.lineHeight() 27 | return CGSize(width: width, height: height + 5) 28 | } 29 | 30 | override func cellForItem(at index: Int) -> UICollectionViewCell { 31 | guard let cell = collectionContext?.dequeueReusableCell(withNibName: ContentCell.cellIdentifier, bundle: nil, for: self, at: index) as? ContentCell else { fatalError() } 32 | cell.bindViewModel(object.content as Any) 33 | return cell 34 | } 35 | 36 | override func didUpdate(to object: Any) { 37 | self.object = object as? Feed 38 | } 39 | 40 | override func didSelectItem(at index: Int) { 41 | expanded.toggle() 42 | UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.4, initialSpringVelocity: 0.6, options: [], animations: { 43 | self.collectionContext?.invalidateLayout(for: self, completion: nil) 44 | }, completion: nil) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/SectionController/FavorSectionController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FavorSectionController.swift 3 | // IGListKitDemoSwift 4 | // 5 | // Created by gxy on 2018/10/5. 6 | // Copyright © 2018年 bruce. All rights reserved. 7 | // 8 | 9 | import IGListKit 10 | 11 | class FavorSectionController: ListSectionController { 12 | 13 | var object: Feed! 14 | lazy var viewModel: FavorCellModel = { 15 | let vm = FavorCellModel() 16 | vm.feed = object 17 | return vm 18 | }() 19 | 20 | override func numberOfItems() -> Int { 21 | return 1 22 | } 23 | 24 | override func sizeForItem(at index: Int) -> CGSize { 25 | let width: CGFloat! = collectionContext?.containerSize(for: self).width 26 | return CGSize(width: width, height: 65) 27 | } 28 | override func cellForItem(at index: Int) -> UICollectionViewCell { 29 | guard let cell = collectionContext?.dequeueReusableCell(withNibName: FavorCell.cellIdentifier, bundle: nil, for: self, at: index) as? FavorCell else { fatalError() } 30 | cell.bindViewModel(viewModel as Any) 31 | cell.favorOperation = {[weak self] cell in 32 | guard let self = self else { return } 33 | self.object.isFavor.toggle() 34 | let origin: UInt! = self.object.favor 35 | self.object.favor = self.object.isFavor ? (origin + 1) : (origin - 1) 36 | self.viewModel.feed = self.object 37 | self.collectionContext?.performBatch(animated: true, updates: { (batch) in 38 | batch.reload(in: self, at: IndexSet(integer: 0)) 39 | }, completion: nil) 40 | } 41 | return cell 42 | } 43 | 44 | override func didUpdate(to object: Any) { 45 | self.object = object as? Feed 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/SectionController/FeedBindingSectionController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FeedBindingSectionController.swift 3 | // IGListKitDemoSwift 4 | // 5 | // Created by gxy on 2018/11/25. 6 | // Copyright © 2018年 bruce. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import IGListKit 11 | 12 | class FeedBindingSectionController: ListBindingSectionController,ListBindingSectionControllerDataSource,ListBindingSectionControllerSelectionDelegate { 13 | 14 | var comments: [Comment]? = [] 15 | 16 | var expanded: Bool = false 17 | let padding: CGFloat = 10 18 | 19 | override init() { 20 | super.init() 21 | dataSource = self 22 | selectionDelegate = self 23 | } 24 | 25 | override func didUpdate(to object: Any) { 26 | guard let obj = object as? Feed else { fatalError() } 27 | comments = obj.comments 28 | super.didUpdate(to: object) 29 | } 30 | 31 | func sectionController(_ sectionController: ListBindingSectionController, didSelectItemAt index: Int, viewModel: Any) { 32 | switch viewModel { 33 | case is String: 34 | expanded.toggle() 35 | UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.4, initialSpringVelocity: 0.6, options: [], animations: { 36 | self.collectionContext?.invalidateLayout(for: self, completion: nil) 37 | }, completion: nil) 38 | default: 39 | return 40 | } 41 | } 42 | 43 | func sectionController(_ sectionController: ListBindingSectionController, viewModelsFor object: Any) -> [ListDiffable] { 44 | guard let obj = object as? Feed else { return [] } 45 | var vms: [ListDiffable] = [] 46 | let userInfo = UserInfoCellModel(avatar: URL(string: obj.avatar), userName: obj.userName) 47 | vms.append(userInfo) 48 | if let content = obj.content { 49 | vms.append(content as ListDiffable) 50 | } 51 | if obj.images.count != 0 { 52 | let vm = ImagesCollectionCellModel() 53 | vm.imageNames = obj.images 54 | vms.append(vm) 55 | } 56 | let favor = FavorCellModel() 57 | favor.feed = obj 58 | vms.append(favor) 59 | 60 | let comments: [CommentCellModel] = self.comments?.map({ (comment) -> CommentCellModel in 61 | let vm = CommentCellModel() 62 | vm.comment = comment 63 | return vm 64 | }) ?? [] 65 | vms.append(contentsOf: comments) 66 | return vms 67 | } 68 | 69 | func sectionController(_ sectionController: ListBindingSectionController, cellForViewModel viewModel: Any, at index: Int) -> UICollectionViewCell & ListBindable { 70 | switch viewModel { 71 | case is UserInfoCellModel: 72 | return userInfoCell(at: index) 73 | case is String: 74 | guard let cell = collectionContext?.dequeueReusableCell(withNibName: ContentCell.cellIdentifier, bundle: nil, for: self, at: index) as? ContentCell else { fatalError() } 75 | return cell 76 | case is ImagesCollectionCellModel: 77 | guard let cell = collectionContext?.dequeueReusableCell(withNibName: ImageCollectionCell.cellIdentifier, bundle: nil, for: self, at: index) as? ImageCollectionCell else { fatalError() } 78 | return cell 79 | case is FavorCellModel: 80 | return favorCell(at: index) 81 | case is CommentCellModel: 82 | return commentCell(at: index) 83 | default: 84 | fatalError() 85 | } 86 | } 87 | 88 | func sectionController(_ sectionController: ListBindingSectionController, sizeForViewModel viewModel: Any, at index: Int) -> CGSize { 89 | let width: CGFloat! = collectionContext?.containerSize(for: self).width 90 | guard let object = self.object as? Feed else { fatalError() } 91 | 92 | switch viewModel { 93 | case is UserInfoCellModel: 94 | return CGSize(width: width, height: 30) 95 | case is String: 96 | let content: String = viewModel as! String 97 | let height = expanded ? ContentCell.height(for: content as NSString, limitwidth: width) : ContentCell.lineHeight() 98 | return CGSize(width: width, height: height + 5) 99 | case is ImagesCollectionCellModel: 100 | let itemWidth: CGFloat = (width - padding * 2) / 3 101 | let row: Int = (object.images.count - 1) / 3 + 1 102 | let h: CGFloat = CGFloat(row) * itemWidth + CGFloat(row - 1) * padding 103 | return CGSize(width: width, height: h) 104 | case is FavorCellModel: 105 | return CGSize(width: width, height: 65) 106 | case is CommentCellModel: 107 | return CGSize(width: width, height: 44) 108 | default: 109 | fatalError() 110 | } 111 | } 112 | 113 | // MARK: cell 114 | func userInfoCell(at index: Int) -> UserInfoCell { 115 | guard let cell = collectionContext?.dequeueReusableCell(withNibName: "UserInfoCell", bundle: nil, for: self, at: index) as? UserInfoCell else { fatalError() } 116 | cell.onClickArrow = {[weak self] cell in 117 | guard let self = self else { return } 118 | let actionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) 119 | actionSheet.addAction(UIAlertAction(title: "share", style: .default, handler: nil)) 120 | actionSheet.addAction(UIAlertAction(title: "cancel", style: .cancel, handler: nil)) 121 | actionSheet.addAction(UIAlertAction(title: "delete", style: .default, handler: { (action) in 122 | NotificationCenter.default.post(name: Notification.Name.custom.delete, object: self.object) 123 | })) 124 | self.viewController?.present(actionSheet, animated: true, completion: nil) 125 | } 126 | return cell 127 | } 128 | 129 | func favorCell(at index: Int) -> FavorCell { 130 | guard let cell = collectionContext?.dequeueReusableCell(withNibName: FavorCell.cellIdentifier, bundle: nil, for: self, at: index) as? FavorCell else { fatalError() } 131 | cell.favorOperation = {[weak self] cell in 132 | guard let self = self else { return } 133 | guard let object = self.object as? Feed else { fatalError() } 134 | object.isFavor.toggle() 135 | let origin: UInt! = object.favor 136 | object.favor = object.isFavor ? (origin + 1) : (origin - 1) 137 | self.update(animated: true, completion: nil) 138 | } 139 | return cell 140 | } 141 | 142 | func commentCell(at index: Int) -> CommentCell { 143 | guard let cell = collectionContext?.dequeueReusableCell(withNibName: CommentCell.cellIdentifier, bundle: nil, for: self, at: index) as? CommentCell else { fatalError() } 144 | cell.onClickDelete = {[weak self] (deleteCell) in 145 | guard let self = self else { 146 | return 147 | } 148 | let deleteComment: Comment = (deleteCell.viewModel?.comment)! 149 | self.comments?.removeAll(where: { (c) -> Bool in 150 | let f = c == deleteComment 151 | return f 152 | }) 153 | self.update(animated: true, completion: nil) 154 | } 155 | return cell 156 | } 157 | 158 | } 159 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/SectionController/FeedSectionController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FeedSectionController.swift 3 | // IGListKitDemoSwift 4 | // 5 | // Created by gxy on 2018/10/13. 6 | // Copyright © 2018年 bruce. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import IGListKit 11 | 12 | 13 | 14 | class FeedSectionController: ListSectionController { 15 | var object: Feed! 16 | var hasContent: Bool = false 17 | var hasImage: Bool = false 18 | var hasComment: Bool = false 19 | 20 | var expanded: Bool = false 21 | let padding: CGFloat = 10 22 | 23 | lazy var viewModels: [Any] = { 24 | var vms: [Any] = [] 25 | let userInfo = UserInfoCellModel(avatar: URL(string: object.avatar), userName: object.userName) 26 | vms.append(userInfo) 27 | if let content = object.content { 28 | hasContent = true 29 | vms.append(content) 30 | } 31 | if object.images.count != 0 { 32 | hasImage = true 33 | let vm = ImagesCollectionCellModel() 34 | vm.imageNames = object.images 35 | vms.append(vm) 36 | } 37 | let favor = FavorCellModel() 38 | favor.feed = object 39 | vms.append(favor) 40 | 41 | let comments: [CommentCellModel] = object.comments?.map({ (comment) -> CommentCellModel in 42 | let vm = CommentCellModel() 43 | vm.comment = comment 44 | return vm 45 | }) ?? [] 46 | hasComment = comments.count > 0 47 | vms.append(contentsOf: comments) 48 | return vms 49 | }() 50 | 51 | // MARK: override 52 | 53 | override func numberOfItems() -> Int { 54 | return viewModels.count 55 | } 56 | 57 | override func sizeForItem(at index: Int) -> CGSize { 58 | let width: CGFloat! = collectionContext?.containerSize(for: self).width 59 | switch index { 60 | case 0: 61 | return CGSize(width: width, height: 30) 62 | case 1: 63 | return sizeForItemAtIndex1(width: width) 64 | case 2: 65 | return sizeForItemAtIndex2(width: width) 66 | case 3: 67 | return sizeForItemAtIndex3(width: width) 68 | default: 69 | return CGSize(width: width, height: 44) 70 | } 71 | } 72 | 73 | override func cellForItem(at index: Int) -> UICollectionViewCell { 74 | switch index { 75 | case 0: 76 | return userInfoCell(at: index) 77 | case 1: 78 | return cellForItemAtIndex1(at: index) 79 | case 2: 80 | return cellForItemAtIndex2(at: index) 81 | case 3: 82 | return cellForItemAtIndex3(at: index) 83 | default: 84 | return commentCell(at: index) 85 | } 86 | } 87 | 88 | override func didUpdate(to object: Any) { 89 | self.object = object as? Feed 90 | self.inset = UIEdgeInsets(top: 5, left: 0, bottom: 0, right: 0) 91 | } 92 | 93 | override func didSelectItem(at index: Int) { 94 | if let _ = collectionContext?.cellForItem(at: index, sectionController: self) as? ContentCell { 95 | expanded.toggle() 96 | UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.4, initialSpringVelocity: 0.6, options: [], animations: { 97 | self.collectionContext?.invalidateLayout(for: self, completion: nil) 98 | }, completion: nil) 99 | } 100 | } 101 | 102 | // MARK: size 103 | func sizeForItemAtIndex1(width: CGFloat) -> CGSize { 104 | if hasContent { 105 | guard let content = viewModels[1] as? String else { 106 | fatalError() 107 | } 108 | let height = expanded ? ContentCell.height(for: content as NSString, limitwidth: width) : ContentCell.lineHeight() 109 | return CGSize(width: width, height: height + 5) 110 | } 111 | if hasImage { 112 | let itemWidth: CGFloat = (width - padding * 2) / 3 113 | let row: Int = (object.images.count - 1) / 3 + 1 114 | let h: CGFloat = CGFloat(row) * itemWidth + CGFloat(row - 1) * padding 115 | return CGSize(width: width, height: h) 116 | } 117 | return CGSize(width: width, height: 65) 118 | } 119 | 120 | func sizeForItemAtIndex2(width: CGFloat) -> CGSize { 121 | if hasContent && hasImage { 122 | let itemWidth: CGFloat = (width - padding * 2) / 3 123 | let row: Int = (object.images.count - 1) / 3 + 1 124 | let h: CGFloat = CGFloat(row) * itemWidth + CGFloat(row - 1) * padding 125 | return CGSize(width: width, height: h) 126 | } 127 | if hasContent || hasImage { 128 | return CGSize(width: width, height: 65) 129 | } 130 | if hasComment { 131 | return CGSize(width: width, height: 44) 132 | } 133 | return .zero 134 | } 135 | 136 | func sizeForItemAtIndex3(width: CGFloat) -> CGSize { 137 | if hasContent && hasImage { 138 | return CGSize(width: width, height: 65) 139 | } 140 | if hasComment { 141 | return CGSize(width: width, height: 44) 142 | } 143 | return .zero 144 | } 145 | 146 | // MARK: cell 147 | func userInfoCell(at index: Int) -> UserInfoCell { 148 | guard let cell = collectionContext?.dequeueReusableCell(withNibName: "UserInfoCell", bundle: nil, for: self, at: index) as? UserInfoCell else { fatalError() } 149 | cell.bindViewModel(viewModels[index] as Any) 150 | cell.onClickArrow = {[weak self] cell in 151 | guard let self = self else { return } 152 | let actionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) 153 | actionSheet.addAction(UIAlertAction(title: "share", style: .default, handler: nil)) 154 | actionSheet.addAction(UIAlertAction(title: "cancel", style: .cancel, handler: nil)) 155 | actionSheet.addAction(UIAlertAction(title: "delete", style: .default, handler: { (action) in 156 | NotificationCenter.default.post(name: Notification.Name.custom.delete, object: self.object) 157 | })) 158 | self.viewController?.present(actionSheet, animated: true, completion: nil) 159 | } 160 | return cell 161 | } 162 | 163 | func favorCell(at index: Int) -> FavorCell { 164 | guard let cell = collectionContext?.dequeueReusableCell(withNibName: FavorCell.cellIdentifier, bundle: nil, for: self, at: index) as? FavorCell else { fatalError() } 165 | cell.bindViewModel(viewModels[index] as Any) 166 | cell.favorOperation = {[weak self] cell in 167 | guard let self = self else { return } 168 | self.object.isFavor.toggle() 169 | let origin: UInt! = self.object.favor 170 | self.object.favor = self.object.isFavor ? (origin + 1) : (origin - 1) 171 | guard let favor = self.viewModels[index] as? FavorCellModel else { fatalError() } 172 | favor.feed = self.object 173 | self.collectionContext?.performBatch(animated: true, updates: { (batch) in 174 | batch.reload(in: self, at: IndexSet(integer: index)) 175 | }, completion: nil) 176 | } 177 | return cell 178 | } 179 | 180 | func commentCell(at index: Int) -> CommentCell { 181 | guard let cell = collectionContext?.dequeueReusableCell(withNibName: CommentCell.cellIdentifier, bundle: nil, for: self, at: index) as? CommentCell else { fatalError() } 182 | cell.bindViewModel(viewModels[index]) 183 | cell.onClickDelete = {[weak self] (deleteCell) in 184 | guard let self = self else { 185 | return 186 | } 187 | self.collectionContext?.performBatch(animated: true, updates: { (batch) in 188 | let deleteIndex: Int! = self.collectionContext?.index(for: deleteCell, sectionController: self) 189 | self.viewModels.remove(at: deleteIndex) 190 | batch.delete(in: self, at: IndexSet(integer: deleteIndex)) 191 | }, completion: nil) 192 | } 193 | return cell 194 | } 195 | 196 | func cellForItemAtIndex1(at index: Int) -> UICollectionViewCell { 197 | if hasContent { 198 | guard let cell = collectionContext?.dequeueReusableCell(withNibName: ContentCell.cellIdentifier, bundle: nil, for: self, at: index) as? ContentCell else { fatalError() } 199 | cell.bindViewModel(viewModels[index] as Any) 200 | return cell 201 | } 202 | if hasImage { 203 | guard let cell = collectionContext?.dequeueReusableCell(withNibName: ImageCollectionCell.cellIdentifier, bundle: nil, for: self, at: index) as? ImageCollectionCell else { fatalError() } 204 | cell.bindViewModel(viewModels[index]) 205 | return cell 206 | } 207 | return favorCell(at: index) 208 | } 209 | 210 | func cellForItemAtIndex2(at index: Int) -> UICollectionViewCell { 211 | if hasContent && hasImage { 212 | guard let cell = collectionContext?.dequeueReusableCell(withNibName: ImageCollectionCell.cellIdentifier, bundle: nil, for: self, at: index) as? ImageCollectionCell else { fatalError() } 213 | cell.bindViewModel(viewModels[index]) 214 | return cell 215 | } 216 | if hasContent || hasImage { 217 | return favorCell(at: index) 218 | } 219 | if hasComment { 220 | return commentCell(at: index) 221 | } 222 | fatalError() 223 | } 224 | 225 | func cellForItemAtIndex3(at index: Int) -> UICollectionViewCell { 226 | if hasContent && hasImage { 227 | return favorCell(at: index) 228 | } 229 | if hasComment { 230 | return commentCell(at: index) 231 | } 232 | fatalError() 233 | } 234 | 235 | } 236 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/SectionController/ImageSectionController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ImageSectionController.swift 3 | // IGListKitDemoSwift 4 | // 5 | // Created by gxy on 2018/10/6. 6 | // Copyright © 2018年 bruce. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import IGListKit 11 | 12 | class ImageSectionController: ListSectionController { 13 | 14 | let padding: CGFloat = 10 15 | 16 | var object: Feed! 17 | lazy var viewModel: ImagesCollectionCellModel = { 18 | let vm = ImagesCollectionCellModel() 19 | vm.imageNames = object.images 20 | return vm 21 | }() 22 | 23 | override func numberOfItems() -> Int { 24 | if object.images.count == 0 { 25 | return 0 26 | } 27 | return 1 28 | } 29 | 30 | override func sizeForItem(at index: Int) -> CGSize { 31 | let width: CGFloat! = collectionContext?.containerSize(for: self).width 32 | let itemWidth: CGFloat = (width - padding * 2) / 3 33 | let row: Int = (object.images.count - 1) / 3 + 1 34 | let h: CGFloat = CGFloat(row) * itemWidth + CGFloat(row - 1) * padding 35 | return CGSize(width: width, height: h) 36 | } 37 | 38 | override func cellForItem(at index: Int) -> UICollectionViewCell { 39 | guard let cell = collectionContext?.dequeueReusableCell(withNibName: ImageCollectionCell.cellIdentifier, bundle: nil, for: self, at: index) as? ImageCollectionCell else { fatalError() } 40 | cell.bindViewModel(viewModel) 41 | return cell 42 | } 43 | 44 | override func didUpdate(to object: Any) { 45 | self.object = object as? Feed 46 | } 47 | } 48 | 49 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/SectionController/UserInfoSectionController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserInfoSectionController.swift 3 | // IGListKitDemoSwift 4 | // 5 | // Created by gxy on 2018/9/25. 6 | // Copyright © 2018年 bruce. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import IGListKit 11 | 12 | final class UserInfoSectionController: ListSectionController { 13 | 14 | var object: Feed! 15 | lazy var viewModel: UserInfoCellModel = { 16 | let model = UserInfoCellModel(avatar: URL(string: object.avatar), userName: object.userName) 17 | return model 18 | }() 19 | 20 | 21 | override func numberOfItems() -> Int { 22 | return 1 23 | } 24 | 25 | override func sizeForItem(at index: Int) -> CGSize { 26 | let width: CGFloat! = collectionContext?.containerSize(for: self).width 27 | return CGSize(width: width, height: 30) 28 | } 29 | 30 | override func cellForItem(at index: Int) -> UICollectionViewCell { 31 | guard let cell = collectionContext?.dequeueReusableCell(withNibName: UserInfoCell.cellIdentifier, bundle: nil, for: self, at: index) as? UserInfoCell else { fatalError() } 32 | cell.bindViewModel(viewModel as Any) 33 | cell.onClickArrow = {[weak self] cell in 34 | guard let self = self else { return } 35 | let actionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) 36 | actionSheet.addAction(UIAlertAction(title: "share", style: .default, handler: nil)) 37 | actionSheet.addAction(UIAlertAction(title: "cancel", style: .cancel, handler: nil)) 38 | actionSheet.addAction(UIAlertAction(title: "delete", style: .default, handler: { (action) in 39 | NotificationCenter.default.post(name: Notification.Name.custom.delete, object: self.object) 40 | })) 41 | self.viewController?.present(actionSheet, animated: true, completion: nil) 42 | } 43 | return cell 44 | } 45 | 46 | override func didUpdate(to object: Any) { 47 | self.object = object as? Feed 48 | } 49 | } 50 | 51 | extension Notification.Name { 52 | struct custom { 53 | static let delete = Notification.Name("delete") 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // IGListKitDemoSwift 4 | // 5 | // Created by gxy on 2018/8/1. 6 | // Copyright © 2018年 bruce. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ViewController: UITableViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | // Do any additional setup after loading the view, typically from a nib. 16 | } 17 | 18 | override func didReceiveMemoryWarning() { 19 | super.didReceiveMemoryWarning() 20 | // Dispose of any resources that can be recreated. 21 | } 22 | 23 | override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 24 | switch indexPath.row { 25 | case 0: 26 | self.navigationController?.pushViewController(FirstListViewController(), animated: true) 27 | case 1: 28 | self.navigationController?.pushViewController(SecondListViewController(), animated: true) 29 | case 2: 30 | self.navigationController?.pushViewController(ThirdListViewController(), animated: true) 31 | case 3: 32 | self.navigationController?.pushViewController(ForthListViewController(), animated: true) 33 | case 4: 34 | self.navigationController?.pushViewController(FifthListViewController(), animated: true) 35 | case 5: 36 | self.navigationController?.pushViewController(SixthListViewController(), animated: true) 37 | case 6: 38 | self.navigationController?.pushViewController(SeventhListViewController(), animated: true) 39 | default: 40 | fatalError() 41 | } 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/ViewController/BaseListViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BaseListViewController.swift 3 | // IGListKitDemoSwift 4 | // 5 | // Created by gxy on 2018/9/13. 6 | // Copyright © 2018年 bruce. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import IGListKit 11 | 12 | class BaseListViewController: UIViewController { 13 | 14 | var objects: [ListDiffable] = [ListDiffable]() 15 | 16 | let collectionView: UICollectionView = { 17 | let flow = UICollectionViewFlowLayout() 18 | let collectionView = UICollectionView(frame: CGRect.zero, collectionViewLayout: flow) 19 | collectionView.backgroundColor = UIColor.groupTableViewBackground 20 | return collectionView 21 | }() 22 | lazy var adapter: ListAdapter = { 23 | let adapter = ListAdapter(updater: ListAdapterUpdater(), viewController: self) 24 | return adapter 25 | }() 26 | 27 | 28 | override func viewDidLoad() { 29 | super.viewDidLoad() 30 | view.addSubview(collectionView) 31 | adapter.collectionView = collectionView 32 | adapter.dataSource = self 33 | } 34 | 35 | override func viewDidLayoutSubviews() { 36 | super.viewDidLayoutSubviews() 37 | collectionView.frame = view.bounds 38 | } 39 | 40 | } 41 | 42 | extension BaseListViewController : ListAdapterDataSource { 43 | func objects(for listAdapter: ListAdapter) -> [ListDiffable] { 44 | return objects 45 | } 46 | 47 | func listAdapter(_ listAdapter: ListAdapter, sectionControllerFor object: Any) -> ListSectionController { 48 | return ListSectionController() 49 | } 50 | 51 | func emptyView(for listAdapter: ListAdapter) -> UIView? { 52 | return nil 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/ViewController/FifthListViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FifthListViewController.swift 3 | // IGListKitDemoSwift 4 | // 5 | // Created by gxy on 2018/9/13. 6 | // Copyright © 2018年 bruce. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import IGListKit 11 | 12 | class FifthListViewController: BaseListViewController { 13 | 14 | var token: NSObjectProtocol? 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | do { 18 | let data = try JsonTool.decode([DataType].self, jsonfileName: "data5") 19 | let result = data.map { (data) -> ListDiffable in 20 | return data.value() 21 | } 22 | 23 | self.objects.append(contentsOf: result) 24 | adapter.performUpdates(animated: true, completion: nil) 25 | } catch { 26 | print("decode failure") 27 | } 28 | token = NotificationCenter.default.addObserver(forName: Notification.Name.custom.delete, object: nil, queue: OperationQueue.main) {[weak self] (noti) in 29 | guard let object = noti.object as? Feed,let self = self else { 30 | return 31 | } 32 | self.objects.removeAll { (element) -> Bool in 33 | guard let ele = element as? Feed else { 34 | return false 35 | } 36 | return ele == object 37 | } 38 | self.adapter.performUpdates(animated: true, completion: nil) 39 | } 40 | } 41 | 42 | override func listAdapter(_ listAdapter: ListAdapter, sectionControllerFor object: Any) -> ListSectionController { 43 | switch object { 44 | case is Feed: 45 | let stack = ListStackedSectionController(sectionControllers: 46 | [UserInfoSectionController(), 47 | ContentSectionController(), 48 | ImageSectionController(), 49 | FavorSectionController(), 50 | CommentSectionController()]) 51 | stack.inset = UIEdgeInsets(top: 5, left: 0, bottom: 0, right: 0) 52 | return stack 53 | case is Ad: 54 | return AdSectionController() 55 | default: 56 | fatalError() 57 | } 58 | } 59 | 60 | override func didReceiveMemoryWarning() { 61 | super.didReceiveMemoryWarning() 62 | // Dispose of any resources that can be recreated. 63 | } 64 | 65 | 66 | /* 67 | // MARK: - Navigation 68 | 69 | // In a storyboard-based application, you will often want to do a little preparation before navigation 70 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 71 | // Get the new view controller using segue.destinationViewController. 72 | // Pass the selected object to the new view controller. 73 | } 74 | */ 75 | 76 | } 77 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/ViewController/FirstListViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FirstListViewController.swift 3 | // IGListKitDemoSwift 4 | // 5 | // Created by gxy on 2018/9/13. 6 | // Copyright © 2018年 bruce. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import IGListKit 11 | 12 | class FirstListViewController: BaseListViewController { 13 | 14 | override func viewDidLoad() { 15 | super.viewDidLoad() 16 | do { 17 | let data = try JsonTool.decode([Feed].self, jsonfileName: "data1") 18 | self.objects.append(contentsOf: data) 19 | adapter.performUpdates(animated: true, completion: nil) 20 | } catch { 21 | print("decode failure") 22 | } 23 | } 24 | 25 | override func listAdapter(_ listAdapter: ListAdapter, sectionControllerFor object: Any) -> ListSectionController { 26 | let stack = ListStackedSectionController(sectionControllers: [UserInfoSectionController(),ContentSectionController()]) 27 | stack.inset = UIEdgeInsets(top: 5, left: 0, bottom: 0, right: 0) 28 | return stack 29 | } 30 | 31 | override func didReceiveMemoryWarning() { 32 | super.didReceiveMemoryWarning() 33 | // Dispose of any resources that can be recreated. 34 | } 35 | 36 | 37 | /* 38 | // MARK: - Navigation 39 | 40 | // In a storyboard-based application, you will often want to do a little preparation before navigation 41 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 42 | // Get the new view controller using segue.destinationViewController. 43 | // Pass the selected object to the new view controller. 44 | } 45 | */ 46 | 47 | } 48 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/ViewController/ForthListViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ForthListViewController.swift 3 | // IGListKitDemoSwift 4 | // 5 | // Created by gxy on 2018/9/13. 6 | // Copyright © 2018年 bruce. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import IGListKit 11 | 12 | class ForthListViewController: BaseListViewController { 13 | 14 | override func viewDidLoad() { 15 | super.viewDidLoad() 16 | do { 17 | let data = try JsonTool.decode([Feed].self, jsonfileName: "data4") 18 | self.objects.append(contentsOf: data) 19 | adapter.performUpdates(animated: true, completion: nil) 20 | } catch { 21 | print("decode failure") 22 | } 23 | } 24 | 25 | override func listAdapter(_ listAdapter: ListAdapter, sectionControllerFor object: Any) -> ListSectionController { 26 | let stack = ListStackedSectionController(sectionControllers: 27 | [UserInfoSectionController(), 28 | ContentSectionController(), 29 | ImageSectionController(), 30 | FavorSectionController(), 31 | CommentSectionController()]) 32 | stack.inset = UIEdgeInsets(top: 5, left: 0, bottom: 0, right: 0) 33 | return stack 34 | } 35 | 36 | override func didReceiveMemoryWarning() { 37 | super.didReceiveMemoryWarning() 38 | // Dispose of any resources that can be recreated. 39 | } 40 | 41 | 42 | /* 43 | // MARK: - Navigation 44 | 45 | // In a storyboard-based application, you will often want to do a little preparation before navigation 46 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 47 | // Get the new view controller using segue.destinationViewController. 48 | // Pass the selected object to the new view controller. 49 | } 50 | */ 51 | 52 | } 53 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/ViewController/SecondListViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SecondListViewController.swift 3 | // IGListKitDemoSwift 4 | // 5 | // Created by gxy on 2018/9/13. 6 | // Copyright © 2018年 bruce. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import IGListKit 11 | 12 | class SecondListViewController: BaseListViewController { 13 | 14 | override func viewDidLoad() { 15 | super.viewDidLoad() 16 | do { 17 | let data = try JsonTool.decode([Feed].self, jsonfileName: "data2") 18 | self.objects.append(contentsOf: data) 19 | adapter.performUpdates(animated: true, completion: nil) 20 | } catch { 21 | print("decode failure") 22 | } 23 | } 24 | 25 | override func listAdapter(_ listAdapter: ListAdapter, sectionControllerFor object: Any) -> ListSectionController { 26 | let stack = ListStackedSectionController(sectionControllers: [UserInfoSectionController(),ContentSectionController(),FavorSectionController()]) 27 | stack.inset = UIEdgeInsets(top: 5, left: 0, bottom: 0, right: 0) 28 | return stack 29 | } 30 | 31 | override func didReceiveMemoryWarning() { 32 | super.didReceiveMemoryWarning() 33 | // Dispose of any resources that can be recreated. 34 | } 35 | 36 | 37 | /* 38 | // MARK: - Navigation 39 | 40 | // In a storyboard-based application, you will often want to do a little preparation before navigation 41 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 42 | // Get the new view controller using segue.destinationViewController. 43 | // Pass the selected object to the new view controller. 44 | } 45 | */ 46 | 47 | } 48 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/ViewController/SeventhListViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SeventhListViewController.swift 3 | // IGListKitDemoSwift 4 | // 5 | // Created by gxy on 2018/11/25. 6 | // Copyright © 2018年 bruce. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import IGListKit 11 | 12 | class SeventhListViewController: BaseListViewController { 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | do { 16 | let data = try JsonTool.decode([Feed].self, jsonfileName: "data4") 17 | self.objects.append(contentsOf: data) 18 | adapter.performUpdates(animated: true, completion: nil) 19 | } catch { 20 | print("decode failure") 21 | } 22 | } 23 | 24 | override func listAdapter(_ listAdapter: ListAdapter, sectionControllerFor object: Any) -> ListSectionController { 25 | let stack = FeedBindingSectionController() 26 | stack.inset = UIEdgeInsets(top: 5, left: 0, bottom: 0, right: 0) 27 | return stack 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/ViewController/SixthListViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SixthListViewController.swift 3 | // IGListKitDemoSwift 4 | // 5 | // Created by gxy on 2018/10/13. 6 | // Copyright © 2018年 bruce. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import IGListKit 11 | 12 | class SixthListViewController: BaseListViewController { 13 | 14 | var token: NSObjectProtocol? 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | do { 18 | let data = try JsonTool.decode([Feed].self, jsonfileName: "data4") 19 | self.objects.append(contentsOf: data) 20 | adapter.performUpdates(animated: true, completion: nil) 21 | } catch { 22 | print("decode failure") 23 | } 24 | token = NotificationCenter.default.addObserver(forName: Notification.Name.custom.delete, object: nil, queue: OperationQueue.main) {[weak self] (noti) in 25 | guard let object = noti.object as? Feed,let self = self else { 26 | return 27 | } 28 | self.objects.removeAll { (element) -> Bool in 29 | guard let ele = element as? Feed else { 30 | return false 31 | } 32 | return ele == object 33 | } 34 | self.adapter.performUpdates(animated: true, completion: nil) 35 | } 36 | 37 | } 38 | 39 | override func listAdapter(_ listAdapter: ListAdapter, sectionControllerFor object: Any) -> ListSectionController { 40 | switch object { 41 | case is Feed: 42 | return FeedSectionController() 43 | default: 44 | fatalError() 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/ViewController/ThirdListViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ThirdListViewController.swift 3 | // IGListKitDemoSwift 4 | // 5 | // Created by gxy on 2018/9/13. 6 | // Copyright © 2018年 bruce. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import IGListKit 11 | 12 | class ThirdListViewController: BaseListViewController { 13 | 14 | override func viewDidLoad() { 15 | super.viewDidLoad() 16 | do { 17 | let data = try JsonTool.decode([Feed].self, jsonfileName: "data3") 18 | self.objects.append(contentsOf: data) 19 | adapter.performUpdates(animated: true, completion: nil) 20 | } catch { 21 | print("decode failure") 22 | } 23 | } 24 | 25 | override func listAdapter(_ listAdapter: ListAdapter, sectionControllerFor object: Any) -> ListSectionController { 26 | let stack = ListStackedSectionController(sectionControllers: 27 | [UserInfoSectionController(), 28 | ContentSectionController(), 29 | ImageSectionController(), 30 | FavorSectionController()]) 31 | stack.inset = UIEdgeInsets(top: 5, left: 0, bottom: 0, right: 0) 32 | return stack 33 | } 34 | 35 | override func didReceiveMemoryWarning() { 36 | super.didReceiveMemoryWarning() 37 | // Dispose of any resources that can be recreated. 38 | } 39 | 40 | 41 | /* 42 | // MARK: - Navigation 43 | 44 | // In a storyboard-based application, you will often want to do a little preparation before navigation 45 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 46 | // Get the new view controller using segue.destinationViewController. 47 | // Pass the selected object to the new view controller. 48 | } 49 | */ 50 | 51 | } 52 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/data/data1.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "feedId":1, 4 | "avatar":"http://tse4.mm.bing.net/th?id=OIP.pYkSDAPsbJdgrdN_Oub2QgAAAA&w=196&h=196&c=7&o=5&dpr=2&pid=1.7", 5 | "userName":"Bruce", 6 | "content":"this is a content" 7 | }, 8 | { 9 | "feedId":2, 10 | "avatar":"http://tse4.mm.bing.net/th?id=OIP.pYkSDAPsbJdgrdN_Oub2QgAAAA&w=196&h=196&c=7&o=5&dpr=2&pid=1.7", 11 | "userName":"Bruce", 12 | "content":"11" 13 | },{ 14 | "feedId":3, 15 | "avatar":"http://tse4.mm.bing.net/th?id=OIP.pYkSDAPsbJdgrdN_Oub2QgAAAA&w=196&h=196&c=7&o=5&dpr=2&pid=1.7", 16 | "userName":"Bruce", 17 | "content":"this is a long long long long long long long long long long long long long long long content" 18 | },{ 19 | "feedId":4, 20 | "avatar":"http://tse4.mm.bing.net/th?id=OIP.pYkSDAPsbJdgrdN_Oub2QgAAAA&w=196&h=196&c=7&o=5&dpr=2&pid=1.7", 21 | "userName":"Bruce", 22 | "content":"11" 23 | },{ 24 | "feedId":5, 25 | "avatar":"http://tse4.mm.bing.net/th?id=OIP.pYkSDAPsbJdgrdN_Oub2QgAAAA&w=196&h=196&c=7&o=5&dpr=2&pid=1.7", 26 | "userName":"Bruce", 27 | "content":"11" 28 | } 29 | ] 30 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/data/data2.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "feedId": 1, 3 | "avatar": "http://tse4.mm.bing.net/th?id=OIP.pYkSDAPsbJdgrdN_Oub2QgAAAA&w=196&h=196&c=7&o=5&dpr=2&pid=1.7", 4 | "userName": "Bruce", 5 | "content": "this is a content", 6 | "isFavor": true, 7 | "favor": 10 8 | }, 9 | { 10 | "feedId": 2, 11 | "avatar": "http://tse4.mm.bing.net/th?id=OIP.pYkSDAPsbJdgrdN_Oub2QgAAAA&w=196&h=196&c=7&o=5&dpr=2&pid=1.7", 12 | "userName": "Bruce", 13 | "content": "11", 14 | "isFavor": false, 15 | "favor": 10 16 | }, 17 | { 18 | "feedId": 3, 19 | "avatar": "http://tse4.mm.bing.net/th?id=OIP.pYkSDAPsbJdgrdN_Oub2QgAAAA&w=196&h=196&c=7&o=5&dpr=2&pid=1.7", 20 | "userName": "Bruce", 21 | "content": "this is a long long long long long long long long long long long long long long long content", 22 | "isFavor": false, 23 | "favor": 10 24 | }, 25 | { 26 | "feedId": 4, 27 | "avatar": "http://tse4.mm.bing.net/th?id=OIP.pYkSDAPsbJdgrdN_Oub2QgAAAA&w=196&h=196&c=7&o=5&dpr=2&pid=1.7", 28 | "userName": "Bruce", 29 | "content": "11", 30 | "isFavor": true, 31 | "favor": 10 32 | }, 33 | { 34 | "feedId": 5, 35 | "avatar": "http://tse4.mm.bing.net/th?id=OIP.pYkSDAPsbJdgrdN_Oub2QgAAAA&w=196&h=196&c=7&o=5&dpr=2&pid=1.7", 36 | "userName": "Bruce", 37 | "content": null, 38 | "isFavor": true, 39 | "favor": 10 40 | }] 41 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/data/data3.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "feedId": 1, 3 | "avatar": "http://tse4.mm.bing.net/th?id=OIP.pYkSDAPsbJdgrdN_Oub2QgAAAA&w=196&h=196&c=7&o=5&dpr=2&pid=1.7", 4 | "userName": "Bruce", 5 | "content": "this is a content", 6 | "isFavor": true, 7 | "favor": 10, 8 | "images": ["red","blue"] 9 | }, 10 | { 11 | "feedId": 2, 12 | "avatar": "http://tse4.mm.bing.net/th?id=OIP.pYkSDAPsbJdgrdN_Oub2QgAAAA&w=196&h=196&c=7&o=5&dpr=2&pid=1.7", 13 | "userName": "Bruce", 14 | "content": "11", 15 | "isFavor": false, 16 | "favor": 10, 17 | "images": ["red","blue","yellow","green"] 18 | }, 19 | { 20 | "feedId": 3, 21 | "avatar": "http://tse4.mm.bing.net/th?id=OIP.pYkSDAPsbJdgrdN_Oub2QgAAAA&w=196&h=196&c=7&o=5&dpr=2&pid=1.7", 22 | "userName": "Bruce", 23 | "content": "this is a long long long long long long long long long long long long long long long content", 24 | "isFavor": false, 25 | "favor": 10, 26 | "images": ["red","blue","yellow"] 27 | }, 28 | { 29 | "feedId": 4, 30 | "avatar": "http://tse4.mm.bing.net/th?id=OIP.pYkSDAPsbJdgrdN_Oub2QgAAAA&w=196&h=196&c=7&o=5&dpr=2&pid=1.7", 31 | "userName": "Bruce", 32 | "content": "11", 33 | "isFavor": true, 34 | "favor": 10, 35 | "images": [] 36 | }, 37 | { 38 | "feedId": 5, 39 | "avatar": "http://tse4.mm.bing.net/th?id=OIP.pYkSDAPsbJdgrdN_Oub2QgAAAA&w=196&h=196&c=7&o=5&dpr=2&pid=1.7", 40 | "userName": "Bruce", 41 | "content": null, 42 | "isFavor": true, 43 | "favor": 10, 44 | "images": ["red","blue","yellow","green"] 45 | }] 46 | 47 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/data/data4.json: -------------------------------------------------------------------------------- 1 | 2 | [{ 3 | "feedId": 1, 4 | "avatar": "http://tse4.mm.bing.net/th?id=OIP.pYkSDAPsbJdgrdN_Oub2QgAAAA&w=196&h=196&c=7&o=5&dpr=2&pid=1.7", 5 | "userName": "Bruce", 6 | "content": "this is a content", 7 | "images": ["red", "blue"], 8 | "isFavor": true, 9 | "favor": 10, 10 | "comments": [{ 11 | "comment": "comment 1", 12 | "person": "jack" 13 | }] 14 | }, 15 | { 16 | "feedId": 2, 17 | "avatar": "http://tse4.mm.bing.net/th?id=OIP.pYkSDAPsbJdgrdN_Oub2QgAAAA&w=196&h=196&c=7&o=5&dpr=2&pid=1.7", 18 | "userName": "Bruce", 19 | "content": "11", 20 | "images": [], 21 | "isFavor": false, 22 | "favor": 10, 23 | "comments": [] 24 | }, 25 | { 26 | "feedId": 3, 27 | "avatar": "http://tse4.mm.bing.net/th?id=OIP.pYkSDAPsbJdgrdN_Oub2QgAAAA&w=196&h=196&c=7&o=5&dpr=2&pid=1.7", 28 | "userName": "Bruce", 29 | "content": "this is a long long long long long long long long long long long long long long long content", 30 | "images": ["red", "blue", "yellow"], 31 | "isFavor": false, 32 | "favor": 10, 33 | "comments": [{ 34 | "comment": "comment 3", 35 | "person": "jane" 36 | }] 37 | }, 38 | { 39 | "feedId": 4, 40 | "avatar": "http://tse4.mm.bing.net/th?id=OIP.pYkSDAPsbJdgrdN_Oub2QgAAAA&w=196&h=196&c=7&o=5&dpr=2&pid=1.7", 41 | "userName": "Bruce", 42 | "content": "11", 43 | "images": ["red", "blue", "yellow", "green"], 44 | "isFavor": true, 45 | "favor": 10, 46 | "comments": [{ 47 | "comment": "cav", 48 | "person": "james" 49 | }, 50 | { 51 | "comment": "boston", 52 | "person": "irving" 53 | }, 54 | { 55 | "comment": "cav", 56 | "person": "love" 57 | }] 58 | }, 59 | { 60 | "feedId": 5, 61 | "avatar": "http://tse4.mm.bing.net/th?id=OIP.pYkSDAPsbJdgrdN_Oub2QgAAAA&w=196&h=196&c=7&o=5&dpr=2&pid=1.7", 62 | "userName": "Bruce", 63 | "content": null, 64 | "images": ["red"], 65 | "isFavor": true, 66 | "favor": 10, 67 | "comments": [{ 68 | "comment": "comment 1", 69 | "person": "jack" 70 | }] 71 | }] 72 | -------------------------------------------------------------------------------- /IGListKitDemoSwift/data/data5.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "type": 1, 3 | "data": { 4 | "feedId": 1, 5 | "avatar": "http://tse4.mm.bing.net/th?id=OIP.pYkSDAPsbJdgrdN_Oub2QgAAAA&w=196&h=196&c=7&o=5&dpr=2&pid=1.7", 6 | "userName": "Bruce", 7 | "content": "this is a content", 8 | "images": [ 9 | "red", 10 | "blue" 11 | ], 12 | "isFavor": true, 13 | "favor": 10, 14 | "comments": [ 15 | { 16 | "comment": "comment 1", 17 | "person": "jack" 18 | } 19 | ] 20 | } 21 | }, 22 | { 23 | "type": 2, 24 | "data": { 25 | "adTitle": "这是广告1", 26 | "adUrl": "" 27 | } 28 | }, 29 | { 30 | "type": 1, 31 | "data": { 32 | "feedId": 2, 33 | "avatar": "http://tse4.mm.bing.net/th?id=OIP.pYkSDAPsbJdgrdN_Oub2QgAAAA&w=196&h=196&c=7&o=5&dpr=2&pid=1.7", 34 | "userName": "Bruce", 35 | "content": "11", 36 | "images": [], 37 | "isFavor": false, 38 | "favor": 10, 39 | "comments": [] 40 | } 41 | }, 42 | { 43 | "type": 1, 44 | "data": { 45 | "feedId": 3, 46 | "avatar": "http://tse4.mm.bing.net/th?id=OIP.pYkSDAPsbJdgrdN_Oub2QgAAAA&w=196&h=196&c=7&o=5&dpr=2&pid=1.7", 47 | "userName": "Bruce", 48 | "content": "this is a long long long long long long long long long long long long long long long content", 49 | "images": [ 50 | "red", 51 | "blue", 52 | "yellow" 53 | ], 54 | "isFavor": false, 55 | "favor": 10, 56 | "comments": [ 57 | { 58 | "comment": "comment 3", 59 | "person": "jane" 60 | } 61 | ] 62 | } 63 | }, 64 | { 65 | "type": 1, 66 | "data": { 67 | "feedId": 4, 68 | "avatar": "http://tse4.mm.bing.net/th?id=OIP.pYkSDAPsbJdgrdN_Oub2QgAAAA&w=196&h=196&c=7&o=5&dpr=2&pid=1.7", 69 | "userName": "Bruce", 70 | "content": "11", 71 | "images": [ 72 | "red", 73 | "blue", 74 | "yellow", 75 | "green" 76 | ], 77 | "isFavor": true, 78 | "favor": 10, 79 | "comments": [ 80 | { 81 | "comment": "cav", 82 | "person": "james" 83 | }, 84 | { 85 | "comment": "boston", 86 | "person": "irving" 87 | }, 88 | { 89 | "comment": "cav", 90 | "person": "love" 91 | } 92 | ] 93 | } 94 | }, 95 | { 96 | "type": 2, 97 | "data": { 98 | "adTitle": "这是广告2", 99 | "adUrl": "" 100 | } 101 | }] 102 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | use_frameworks! 2 | 3 | target 'IGListKitDemoSwift' do 4 | pod 'IGListKit' 5 | end 6 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - IGListKit (3.4.0): 3 | - IGListKit/Default (= 3.4.0) 4 | - IGListKit/Default (3.4.0): 5 | - IGListKit/Diffing 6 | - IGListKit/Diffing (3.4.0) 7 | 8 | DEPENDENCIES: 9 | - IGListKit 10 | 11 | SPEC REPOS: 12 | https://github.com/cocoapods/specs.git: 13 | - IGListKit 14 | 15 | SPEC CHECKSUMS: 16 | IGListKit: 7a5d788e9fb746bcd402baa8e8b24bc3bd2a5a07 17 | 18 | PODFILE CHECKSUM: baeb5555fefc3f1a4f6caab1ee0606bd8ffeaccb 19 | 20 | COCOAPODS: 1.5.3 21 | --------------------------------------------------------------------------------