第一次用Pinterest的时候觉得这个设计还是很惊艳的,这个东西本质上是随着iOS6发布的UICollectionView 给开发者带来的强大功能。这个将是我们今天介绍的第二种实现这类UI的方法,其实我们可以用tableview做出类似的效果,而且还更加简单,因为tableView有UITableViewAutoDimension。我知道iOS10给UICollectionView也带来的自动模式,但是首先,是iOS10,其次,谁用谁知道...
当然下面要介绍的方法并不是一个可以真正被使用的方法,因为错的就是错的,但是这种方法体现了一种最直接的工程师思维,如果飞机超音速怎么办?加大动力!飞机太重了怎么办,加大动力!别管白猫黑猫,能找到耗子的就是好猫。Talk is cheap,let's code:
import UIKit
class PinTableViewController: UIViewController {
@IBOutlet weak var rightTable: UITableView!
@IBOutlet weak var leftTable: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
automaticallyAdjustsScrollViewInsets = false
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
fileprivate func generateRandomColor()->UIColor {
let r = Float(arc4random_uniform(200)) + 5
let g = Float(arc4random_uniform(200)) + 5
let b = Float(arc4random_uniform(200)) + 5
return UIColor(colorLiteralRed: r/255.0, green: g/255.0, blue: b/255.0, alpha: 1)
}
}
extension PinTableViewController:UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 20
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell:UITableViewCell!
if tableView == leftTable {
cell = tableView.dequeueReusableCell(withIdentifier: "LeftCell", for: indexPath)
cell.backgroundColor = generateRandomColor()
return cell
}else {
cell = tableView.dequeueReusableCell(withIdentifier: "RightCell", for: indexPath)
cell.backgroundColor = generateRandomColor()
return cell
}
}
}
extension PinTableViewController:UITableViewDelegate{
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let height = arc4random_uniform((170)) + 30
return CGFloat(height)
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView == rightTable {
leftTable.contentOffset = rightTable.contentOffset
}else {
rightTable.contentOffset = leftTable.contentOffset
}
}
}
So far so good, 我们用成本最低,最直觉的方法实现了这样一种形态的UI,当然,实际上的代码还要更加复杂一点,如果你需要通过size class来决定到底是两列还是四列等等,但是,这些都是不重要的细节。
好了,以上都是玩笑,我们来看看,这个UI设计到底是如何“正确地”实现的:
首先需要明确的是,控制CollectionView布局的东西叫做UICollectionViewLayout,默认值是FlowLayout,说到底就是字面意思,flow模式,大小都一样的蠢哭了模式,基本不可用... 既然如此,那我们就来建立自己的Layout:
class PinterestLayout: UICollectionViewLayout {
var delegate:PinterestLayoutDelegate!
//水平滑动的话就是几列,垂直滑动就是几行
var numberOfColumns = 3
//Cell之间的间隔,上下,左或者右
var cellPadding:CGFloat = 6.0
//储存每一个Cell的属性
private var cache = [UICollectionViewLayoutAttributes]()
private var contentHeight:CGFloat = 0
private var contentWidth:CGFloat {
let insets = collectionView?.contentInset
//collectionView的宽度减去左右边框宽度就是内容的宽度
return collectionView!.bounds.width - insets!.left - insets!.right
}
override func prepare() {
let columnWidth = contentWidth/CGFloat(numberOfColumns)
var xOffset = [CGFloat]()
for column in 0..<numberOfColumns {
xOffset.append(CGFloat(column) * columnWidth)
}
var column = 0
var yOffset = [CGFloat](repeating:0,count:numberOfColumns)
for item in 0..<collectionView!.numberOfItems(inSection: 0) {
let indexPath = IndexPath(item: item, section: 0)
let width = columnWidth - cellPadding * 2
let itemHeight = delegate.collectionView(collectionView: collectionView!, heightForItemAtIndexPath: indexPath, withWideth: width)
let height = cellPadding + itemHeight + cellPadding
let frame = CGRect(x: xOffset[column], y: yOffset[column], width: columnWidth, height: height)
let insetFrame = frame.insetBy(dx: cellPadding, dy: cellPadding)
let attributes = PinterestLayoutArributes(forCellWith: indexPath)
attributes.frame = insetFrame
cache.append(attributes)
contentHeight = max(contentHeight, frame.maxY)
yOffset[column] = yOffset[column] + height
column = column >= numberOfColumns - 1 ? 0 : column+1
}
}
override var collectionViewContentSize:CGSize {
return CGSize(width: contentWidth, height: contentHeight)
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
var layoutArrtibutes = [UICollectionViewLayoutAttributes]()
for attribute in cache {
if attribute.frame.intersects(rect) {
layoutArrtibutes.append(attribute)
}
}
return layoutArrtibutes
}
}
Layout设计好了以后呢就到cell里面去使用一下,就大功告成了:
import UIKit
class MyCollectionViewCell: UICollectionViewCell {
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) {
super.apply(layoutAttributes)
}
}