[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-6871":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":16,"stars7d":16,"stars30d":17,"stars90d":16,"forks30d":16,"starsTrendScore":16,"compositeScore":18,"rankGlobal":10,"rankLanguage":10,"license":19,"archived":20,"fork":20,"defaultBranch":21,"hasWiki":22,"hasPages":20,"topics":23,"createdAt":10,"pushedAt":10,"updatedAt":29,"readmeContent":30,"aiSummary":31,"trendingCount":16,"starSnapshotCount":16,"syncStatus":32,"lastSyncTime":33,"discoverSource":34},6871,"CollectionKit","SoySauceLab\u002FCollectionKit","SoySauceLab","Reimagining UICollectionView","",null,"Swift",4514,265,64,38,0,3,59.57,"MIT License",false,"master",true,[24,25,26,27,28],"collectionkit","ios","swift","uicollectionview","uicollectionviewlayout","2026-06-12 04:00:30","# CollectionKit\n\n**Reimagining `UICollectionView`**\n\nA modern Swift framework for building composable data-driven collection view.\n\n[![Carthage compatible](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FCarthage-Compatible-brightgreen.svg?style=flat)](https:\u002F\u002Fgithub.com\u002FCarthage\u002FCarthage)\n[![Version](https:\u002F\u002Fimg.shields.io\u002Fcocoapods\u002Fv\u002FCollectionKit.svg?style=flat)](http:\u002F\u002Fcocoapods.org\u002Fpods\u002FCollectionKit)\n[![License](https:\u002F\u002Fimg.shields.io\u002Fcocoapods\u002Fl\u002FCollectionKit.svg?style=flat)](https:\u002F\u002Fgithub.com\u002FSoySauceLab\u002FCollectionKit\u002Fblob\u002Fmaster\u002FLICENSE?raw=true)\n[![Build Status](https:\u002F\u002Ftravis-ci.org\u002FSoySauceLab\u002FCollectionKit.svg?branch=master)](https:\u002F\u002Ftravis-ci.org\u002FSoySauceLab\u002FCollectionKit)\n[![codecov](https:\u002F\u002Fcodecov.io\u002Fgh\u002FSoySauceLab\u002FCollectionKit\u002Fbranch\u002Fmaster\u002Fgraph\u002Fbadge.svg)](https:\u002F\u002Fcodecov.io\u002Fgh\u002FSoySauceLab\u002FCollectionKit)\n![Xcode 8.2+](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FXcode-8.2%2B-blue.svg)\n![iOS 8.0+](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FiOS-8.0%2B-blue.svg)\n![Swift 3.0+](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FSwift-3.0%2B-orange.svg)\n[![Slack](https:\u002F\u002Fslackin-axnycthvks.now.sh\u002Fbadge.svg)](https:\u002F\u002Fslackin-axnycthvks.now.sh)\n\n### Migration Guide\n\n[v2.0](\u002FResources\u002Fv2_migration.md)\n\n### Features\n\n* Rewritten `UICollectionView` on top of `UIScrollView`.\n* Automatically diff data changes and update UI.\n* Superb performance through cell reuse, batched reload, visible-only diff, & the use of swift value types.\n* Builtin layout & animation systems specifically built for collections.\n* Composable sections with independent layout.\n* Strong type checking powered by Swift Generics.\n\n## Install\n\n```ruby\n# CocoaPods\npod \"CollectionKit\"\n\n# Carthage\ngithub \"SoySauceLab\u002FCollectionKit\"\n```\n\n## Getting Started\n\nTo start using CollectionKit, use `CollectionView` in place of `UICollectionView`. `CollectionView` is CollectionKit's alternative to `UICollectionView`. You give it a `Provider` object that tells `CollectionView` how to display a collection.\n\nThe simpliest way to construct a provider is by using `BasicProvider` class.\n\n### BasicProvider\n\nTo build a `BasicProvider`, here is what you need:\n\n* **DataSource**\n  * an object that supplies data to the BasicProvider.\n* **ViewSource**\n  * an object that maps each data into a view, and update the view accordingly\n* **SizeSource**\n  * an function that gives the size for each cell.\n\nIt sounds complicated, but it really isn't. Here is a short example demostrating\nhow it all works.\n\n```swift\nlet dataSource = ArrayDataSource(data: [1, 2, 3, 4])\nlet viewSource = ClosureViewSource(viewUpdater: { (view: UILabel, data: Int, index: Int) in\n  view.backgroundColor = .red\n  view.text = \"\\(data)\"\n})\nlet sizeSource = { (index: Int, data: Int, collectionSize: CGSize) -> CGSize in\n  return CGSize(width: 50, height: 50)\n}\nlet provider = BasicProvider(\n  dataSource: dataSource,\n  viewSource: viewSource,\n  sizeSource: sizeSource\n)\n\n\u002F\u002Flastly assign this provider to the collectionView to display the content\ncollectionView.provider = provider\n```\n\n\u003Cimg src=\"https:\u002F\u002Fcdn.rawgit.com\u002FSoySauceLab\u002FCollectionKit\u002F4045170\u002FResources\u002Fexample1.svg\" \u002F>\n\nNote that we used `ArrayDataSource` & `ClosureViewSource` here. These two classes are built-in to CollectionKit, and should be able to serve most jobs. You can implement other `dataSource` and `viewSource` as well. Imagine implementing a `NetworkDataSource` in your project, that retrives json data and parse into swift objects.\n\n\n### Reload\n\nIt is easy to update the CollectionView with new data.\n\n```swift\ndataSource.data = [7, 8, 9]\n```\n\nThis will trigger an update of the CollectionView that is served by this dataSource.\n\n\u003Cimg src=\"https:\u002F\u002Fcdn.rawgit.com\u002FSoySauceLab\u002FCollectionKit\u002F4045170\u002FResources\u002Fexample2.svg\" \u002F>\n\nNote that `append` and other array mutating methods will also work.\n\n```swift\ndataSource.data.append(10)\ndataSource.data.append(11)\ndataSource.data.append(12)\n```\n\n\u003Cimg src=\"https:\u002F\u002Fcdn.rawgit.com\u002FSoySauceLab\u002FCollectionKit\u002F4045170\u002FResources\u002Fexample3.svg\" \u002F>\n\nWe updated the array three times in this example. Each update is triggering a reload. You might be thinking that this is very computational intensive, but it isn't. CollectionKit is smart enough to only update once per layout cycle. It will wait until the next layout cycle to actually reload.\n\nAfter executing the 3 lines above, CollectionView will still show `[7, 8, 9]`. But once the current run loop cycle is completed, CollectionView will update immediately. Your user won't notice any lag from this process.\n\nTo trigger an update immediately, you can call `collectionView.reloadData()` or `provider.reloadData()` or `dataSource.reloadData()`. \n\nTo make collectionView reload on the next layout cycle, you can call `collectionView.setNeedsReload()` or `provider.setNeedsReload()` or `dataSource.setNeedsReload()`. You might already noticed, once you update the array inside `ArrayDataSource`, it is basically calling `setNeedsReload()` for you.\n\nNote that if you assign an array to the dataSource and later update that array instead. It won't actually update the `CollectionView`\n\n```swift\nvar a = [1, 2 ,3]\ndataSource.data = a\na.append(5) \u002F\u002F won't trigger an update be cause dataSource.data & a is now two different array.\na = [4 ,5 ,6] \u002F\u002F also won't trigger an update\n```\n\n### Layout\n\nUp to this point, the collection is still a bit ugly to look at. Every cell is left aligned and doesn't have space in between. You might want the views to be evenly spaced out, or you might want to add some spacing in between items or lines.\n\nThese can be achieved with Layout objects. Here is an example.\n\n```swift\nprovider.layout = FlowLayout(spacing: 10, justifyContent: .center)\n```\n\n\u003Cimg src=\"https:\u002F\u002Fcdn.rawgit.com\u002FSoySauceLab\u002FCollectionKit\u002F4045170\u002FResources\u002Fexample4.svg\" \u002F>\n\n`FlowLayout` is a `Layout` class that it built-in to CollectionKit. There are many more built-in layouts including `WaterfallLayout` & `RowLayout`. You can also easily create your own layout.\n\n`FlowLayout` is basically a better `UICollectionViewFlowLayout` that aligns items in row by row fashion. It supports `lineSpacing`, `interitemSpacing`, `alignContent`, `alignItems`, & `justifyContent`.\n\nEvery layout also supports `inset(by:)` and `transposed()` methods. \n\n`inset(by:)` adds an outer padding to the layout and return the result layout as `InsetLayout`. \n\n```swift\nlet inset = UIEdgeInset(top: 10, left: 10, bottom: 10, right: 10)\nprovider.layout = FlowLayout(spacing: 10).inset(by: inset)\n```\n\n\u003Cimg src=\"https:\u002F\u002Fcdn.rawgit.com\u002FSoySauceLab\u002FCollectionKit\u002F4045170\u002FResources\u002Fexample5.svg\" \u002F>\n\n`transposed()` converts a vertical layout into a horizontal layout or vice-versa. It returns the original layout wrapped inside a `TransposedLayout`\n\n```swift\nprovider.layout = FlowLayout(spacing: 10).transposed()\n```\n\n\u003Cimg src=\"https:\u002F\u002Fcdn.rawgit.com\u002FSoySauceLab\u002FCollectionKit\u002F4045170\u002FResources\u002Fexample6.svg\" \u002F>\n\nYou can also use them together like\n\n```swift\nlet inset = UIEdgeInset(top: 10, left: 10, bottom: 10, right: 10)\nprovider.layout = FlowLayout(spacing: 10).transposed().inset(by: inset)\n```\n\n\u003Cimg src=\"https:\u002F\u002Fcdn.rawgit.com\u002FSoySauceLab\u002FCollectionKit\u002F4045170\u002FResources\u002Fexample7.svg\" \u002F>\n\n\nThere can be a lot to talk about with Layouts. We will create more tutorial later to teach you how to create your own layout and show you some advance usages. In the mean time, feel free to dive in the source code. I promise you it is not complecated at all.\n\n### Composing (ComposedProvider)\n\nThe best feature of CollectionKit, is that you can freely combine providers together into multiple sections within one CollectionView. And it is **REALLY EASY** to do so.\n\n```swift\nlet finalProvider = ComposedProvider(sections: [provider1, provider2, provider3])\n\ncollectionView.provider = finalProvider\n```\n\n\u003Cimg src=\"https:\u002F\u002Fcdn.rawgit.com\u002FSoySauceLab\u002FCollectionKit\u002F4045170\u002FResources\u002Fexample8.svg\" \u002F>\n\nTo update individual sections, just update its own `dataSource`.\n\n```swift\nprovider2DataSource.data = [2]\n```\n\n\u003Cimg src=\"https:\u002F\u002Fcdn.rawgit.com\u002FSoySauceLab\u002FCollectionKit\u002F4045170\u002FResources\u002Fexample9.svg\" \u002F>\n\nYou can also live update sections around.\n\n```swift\nfinalProvider.sections = [provider2, provider3, provider1]\n```\n\n\u003Cimg src=\"https:\u002F\u002Fcdn.rawgit.com\u002FSoySauceLab\u002FCollectionKit\u002F4045170\u002FResources\u002Fexample10.svg\" \u002F>\n\nOr add more to it.\n\n```swift\nfinalProvider.sections.append(provider4)\n```\n\n\u003Cimg src=\"https:\u002F\u002Fcdn.rawgit.com\u002FSoySauceLab\u002FCollectionKit\u002F4045170\u002FResources\u002Fexample11.svg\" \u002F>\n\nYou can even put `ComposedProvider` into another `ComposedProvider` no problem.\n\n```swift\nlet trulyFinalProvider = ComposedProvider(sections: [finalProvider, provider5])\n\ncollectionView.provider = trulyFinalProvider\n```\n\n#### How cool is that!\n\n### Animation\n\nCollectionKit offers a animation system which allows you to create fancy animations and adjust how cells are displayed. \n\nHere are some examples of custom animators that is included in the example project. They can be used in combination with any layout. Here we are using a transposed waterfall layout.\n\n| Wobble  | Edge Shrink | Zoom |\n| ------------- | ------------- | ------------- |\n| \u003Cimg width=\"200\" src=\"http:\u002F\u002Flkzhao.com\u002Fpublic\u002Fposts\u002FcollectionKit\u002Fwobble.gif\" \u002F>  | \u003Cimg width=\"200\" src=\"http:\u002F\u002Flkzhao.com\u002Fpublic\u002Fposts\u002FcollectionKit\u002FedgeShrink.gif\" \u002F> | \u003Cimg width=\"200\" src=\"http:\u002F\u002Flkzhao.com\u002Fpublic\u002Fposts\u002FcollectionKit\u002Fzoom.gif\" \u002F> |\n\nAnimator can also perform animations when a cell is added\u002Fmoved\u002Fdeleted. Here is an example showing a 3d scale animation with a cascading effect.\n\n\u003Cimg width=\"200\" src=\"http:\u002F\u002Flkzhao.com\u002Fpublic\u002Fposts\u002FcollectionKit\u002FreloadAnimation.gif\" \u002F>\n\nIt is easy to use an `Animator`. You can assign it to providers, cells, or to entire `CollectionView`.\n\n```swift\n\u002F\u002F apply to the entire CollectionView\ncollectionView.animator = ScaleAnimator()\n\n\u002F\u002F apply to a single section, will override CollectionView's animator\nprovider.animator = FadeAnimator()\n\n\u002F\u002F apply to a single view, will take priority over all other animators\nview.collectionAnimator = WobbleAnimator()\n```\n\nNote: that in order to use  `WobbleAnimator`, you have to include `pod \"CollectionKit\u002FWobbleAnimator\"` subspec to your podfile.\n\n#### Please checkout the example project to see many of these examples in action.\n\n## Questions? Want to contribute?\n\nJoin our public [Slack](https:\u002F\u002Fslackin-axnycthvks.now.sh)!\n","CollectionKit 是一个用于构建可组合的数据驱动集合视图的现代 Swift 框架。它基于 `UIScrollView` 重写了 `UICollectionView`，能够自动检测数据变化并更新 UI，通过单元格复用、批量刷新和仅对可见部分进行差异更新等技术手段实现卓越性能。内置布局与动画系统专为集合设计，支持具有独立布局的可组合部分，并利用 Swift 泛型提供强大的类型检查功能。适用于 iOS 开发中需要高效且灵活地展示复杂列表或网格数据的应用场景。",2,"2026-06-11 03:09:19","top_language"]