Created
March 8, 2017 18:34
-
-
Save algal/bc22e837c83d0bb299a344c89b8be32e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// known-good: Swift 3 | |
import UIKit | |
/// for a UIView that can be populated via `configure` | |
protocol ConfigurableView : class { | |
associatedtype Value | |
func configure(_ value:Value) | |
} | |
/// for a UICollectionViewCell wrapping a UIView | |
protocol ConfigurableCell : class { | |
associatedtype View : ConfigurableView | |
var wrappedView:View { get } | |
static var classReuseIdentifier:String { get } | |
} | |
/// Generic UICollectionViewCell, for UIViews that conform to ConfigurableView | |
class WrappedCollectionViewCell<T:UIView> : UICollectionViewCell, ConfigurableCell | |
where T:ConfigurableView | |
{ | |
func setup() | |
{ | |
let wrappedView = T.init(frame: self.contentView.bounds) | |
self.contentView.addSubview(wrappedView) | |
wrappedView.translatesAutoresizingMaskIntoConstraints = false | |
for vfl in ["V:|[v]|","H:|[v]|"] | |
{ | |
let cs = NSLayoutConstraint.constraints(withVisualFormat: vfl, options: [], metrics: nil, views: ["v":wrappedView]) | |
self.contentView.addConstraints(cs) | |
} | |
} | |
var wrappedView:T { | |
return self.contentView.subviews.first! as! T | |
} | |
class var classReuseIdentifier:String { | |
return "\(T.self)" + "CellIdentifier" | |
} | |
override class var requiresConstraintBasedLayout:Bool { return true } | |
override init(frame:CGRect) | |
{ | |
super.init(frame:frame) | |
setup() | |
} | |
required init?(coder aDecoder: NSCoder) { | |
super.init(coder:aDecoder) | |
setup() | |
} | |
} | |
/** | |
Generic single-row, horizontal scrolling collection view. | |
This is generic over the data type and the view that displays a data item. | |
This works, but maybe is too generic/clever for real use. | |
How to use: | |
1. Choose a value type V, like Int | |
2. Define a UIView subtype, like MyView, adopting to ConfigurableView | |
3. Instantiate the VC via HorizontalGalleryVC<Int,MyView>(items: hundred) | |
*/ | |
class HorizontalGalleryVC<V,View:UIView> : UICollectionViewController | |
where View.Value==V, View:ConfigurableView | |
{ | |
var items:[V] = [] | |
typealias Cell = WrappedCollectionViewCell<View> | |
let interItemHorizontalSpace:CGFloat = 20 | |
let topPadding:CGFloat = 10 | |
let bottomPadding:CGFloat = 10 | |
init(items:[V]) { | |
self.items = items | |
let lay = UICollectionViewFlowLayout() | |
lay.scrollDirection = .horizontal | |
lay.minimumLineSpacing = self.interItemHorizontalSpace | |
lay.minimumInteritemSpacing = CGFloat.greatestFiniteMagnitude // force one row | |
lay.sectionInset = UIEdgeInsets(top: self.topPadding, | |
left: 0, | |
bottom: self.bottomPadding, | |
right: 0) | |
super.init(collectionViewLayout: lay) | |
} | |
required init?(coder aDecoder: NSCoder) { | |
fatalError("init(coder:) has not been implemented") | |
} | |
override func viewDidLoad() | |
{ | |
super.viewDidLoad() | |
self.collectionView!.isOpaque = true | |
self.collectionView!.backgroundColor = .white | |
self.collectionView!.register(Cell.self, forCellWithReuseIdentifier: Cell.classReuseIdentifier) | |
let cv = self.collectionView! | |
cv.allowsSelection = true | |
cv.allowsMultipleSelection = false | |
cv.scrollsToTop = false | |
cv.isPagingEnabled = false | |
let flowLayout = self.collectionView!.collectionViewLayout as! UICollectionViewFlowLayout | |
flowLayout.itemSize = CGSize(width: 59, height: 50) | |
} | |
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell | |
{ | |
let cell = self.collectionView!.dequeueReusableCell(withReuseIdentifier: Cell.classReuseIdentifier, | |
for: indexPath) | |
let configurableCell = cell as! Cell | |
configurableCell.wrappedView.configure(self.items[indexPath.row]) | |
return cell | |
} | |
override func numberOfSections(in collectionView: UICollectionView) -> Int | |
{ | |
return 1 | |
} | |
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int | |
{ | |
return items.count | |
} | |
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) | |
{ | |
NSLog("tapped") | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment