同时根据不同数量的数据能够自动生成正确size的圆:
基本思路还是利用CollectionViewLayout来客制化CollectionView的外观,既然如此,那么我们先创建一个Layout的subclass:
import UIKit
protocol CircularDelegateLayout {
func collectionView(collectionView:UICollectionView, radiusForItemAtIndexPath indexPath:IndexPath) -> CGFloat
}
class CircularLayout: UICollectionViewLayout {
//Well, I am not using delegate since I am control freak, however, you can customize radius if you want through protocol above.
var delegate:CircularDelegateLayout!
fileprivate var viewCenter:CGPoint!
fileprivate var numberOfItems = 0
fileprivate var centerCircleRadius:CGFloat!
fileprivate var itemRadius:CGFloat!
fileprivate var itemSize:CGSize!
fileprivate var centerItemSize:CGSize!
override var collectionViewContentSize: CGSize {
return collectionView!.bounds.size
}
override func prepare() {
super.prepare()
guard let collectionView = collectionView else {return}
//You only have one section, yes, only one
numberOfItems = collectionView.numberOfItems(inSection: 0)
viewCenter = CGPoint(x: collectionView.bounds.midX, y: collectionView.bounds.midY)
let shortest = min(collectionView.bounds.width, collectionView.bounds.height)
centerCircleRadius = shortest / 3.4
//Why 7 is the magic number? Well, to be frankly, it's not, but I like 7, so I put it here.
if numberOfItems > 7 {
/*switch reader {
case .EastAsian:
print("Ask your high school teacher to figure out why.")
default:
print("Never mind, it's Voodoo, just use it.")
}
*/
itemRadius = CGFloat(2 * Double(centerCircleRadius) * sin(.pi / Double(numberOfItems - 1)))
}else {
itemRadius = centerCircleRadius
}
itemSize = CGSize(width: itemRadius, height: itemRadius)
centerItemSize = CGSize(width: centerCircleRadius, height: centerCircleRadius)
}
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
let angle = 2 * .pi * CGFloat(indexPath.item) / CGFloat(numberOfItems - 1)
switch indexPath.item {
case 0:
attributes.center = viewCenter
attributes.size = centerItemSize
default:
/*switch reader {
case .EastAsian:
print("Ask your high school teacher to figure out why.")
default:
print("Never mind, it's Voodoo, just use it.")
}
*/
attributes.center = CGPoint(x: viewCenter.x + centerCircleRadius * cos(angle), y: viewCenter.y + centerCircleRadius * sin(angle))
attributes.size = itemSize
}
return attributes
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
guard let collectionView = collectionView else {return nil}
return (0..<collectionView.numberOfItems(inSection: 0)).flatMap{ item -> UICollectionViewLayoutAttributes? in
self.layoutAttributesForItem(at: IndexPath(item: item, section: 0))
}
}
}
Documentation是写给公司老外看的,相信在座的都是中国人,这种简单的几何不需要解释了。如果对Layout有疑问的,可以参考前一篇文章:http://www.jianshu.com/p/47fca57fd30b
下面我们来看一下如何使用这个东西,首先你需要在你的StoryBoard里面把CollectionView对应的Layout改掉:
然后给这个Layout在对应的ViewController里面创建一个属性,lay back and enjoy:
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var circularCollectionView: UICollectionView!
@IBOutlet weak var circularLayout: CircularLayout!
fileprivate var data = ["Zero","First","Second","Third","Forth","Fifth","Sixth","Seventh","Eighth","Ninth","Tenth","One", "Two", "Three"]
fileprivate var realData:[String] = []
fileprivate var count = 0
override func viewDidLoad() {
super.viewDidLoad()
circularCollectionView.register(UINib(nibName: "CircularCellCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "CircularCell")
circularCollectionView.delegate = CollectionFactory.shared
circularCollectionView.dataSource = CollectionFactory.shared
CollectionFactory.shared.delegate = self
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let vm = CollectionFactory.shared.registerViewModel(vm:CircularModel()) as! CircularModel
circularLayout.delegate = vm
Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { (timer) in
if self.count < self.data.count {
self.realData.append(self.data[self.count])
self.count += 1
DispatchQueue.main.async {
self.circularCollectionView.reloadData()
}
}else {
self.count = 0
timer.invalidate()
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
extension ViewController:FactoryDataSource {
var dataContainer:[Any]{return realData}
}
完整的project可以在这里找到:https://github.com/LHLL/CircularCollectionView