【发布时间】:2018-02-13 20:56:01
【问题描述】:
我想创建一个可以在 Pinterest 上找到的 collectionView。这将是 2 列图片。
我的问题很简单。根据使用的图片,使用我的代码,一列可以包含比另一列更多的高高度图片。
一开始一切正常,但如果我们滚动,你会发现有一个问题:
我的问题是:这正常吗?我是否必须调整我的代码才能更好地放置图片,或者我是否必须调整我的“loadMore()”函数?
这是我的代码:
NewsfeedCollectionViewController
import UIKit
import AVKit
import AVFoundation
class NewsfeedCollectionViewController : UICollectionViewController
{
var searchController: UISearchController!
var posts: [Post]?
override func viewDidLoad() {
super.viewDidLoad()
self.fetchPosts()
collectionView?.contentInset = UIEdgeInsets(top: 12, left: 4, bottom: 12, right: 4)
if let layout = collectionView?.collectionViewLayout as? PinterestLayout {
layout.delegate = self
}
}
func fetchPosts()
{
self.posts = Post.fetchPosts()
self.collectionView?.reloadData()
}
}
extension NewsfeedCollectionViewController
{
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if let posts = posts {
return posts.count
} else {
return 0
}
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PostCell", for: indexPath) as! PostCollectionViewCell
cell.post = self.posts?[indexPath.item]
return cell
}
}
extension NewsfeedCollectionViewController: PinterestLayoutDelegate {
func collectionView(collectionView: UICollectionView, heightForPhotoAt indexPath: IndexPath, with width: CGFloat) -> CGFloat {
if let post = posts?[indexPath.item], let photo = post.image {
let boundingRect = CGRect(x: 0, y: 0, width: width, height: CGFloat(MAXFLOAT))
let rect = AVMakeRect(aspectRatio: photo.size, insideRect: boundingRect)
return rect.size.height
}
return 0
}
}
Pinterest 布局
import UIKit
protocol PinterestLayoutDelegate {
func collectionView(collectionView: UICollectionView, heightForPhotoAt indexPath: IndexPath, with width: CGFloat) -> CGFloat
}
class PinterestLayout: UICollectionViewLayout {
var delegate: PinterestLayoutDelegate?
var controller: NewsfeedCollectionViewController?
var numberOfColumns: CGFloat = 2
var cellPadding: CGFloat = 5.0
private var contentHeight: CGFloat = 0.0
private var contentWidth: CGFloat {
let insets = collectionView!.contentInset
return (collectionView!.bounds.width - (insets.left + insets.right))
}
private var attributesCache = [PinterestLayoutAttributes]()
override func prepare() {
if attributesCache.isEmpty {
let columnWidth = contentWidth / numberOfColumns
var xOffsets = [CGFloat]()
for column in 0 ..< Int(numberOfColumns) {
xOffsets.append(CGFloat(column) * columnWidth)
}
var column = 0
var yOffsets = [CGFloat](repeating: 0, count: Int(numberOfColumns))
for item in 0 ..< collectionView!.numberOfItems(inSection: 0) {
let indexPath = IndexPath(item: item, section: 0)
let width = columnWidth - cellPadding * 2
// Calculate the frame
let photoHeight: CGFloat = (delegate?.collectionView(collectionView: collectionView!, heightForPhotoAt: indexPath, with: width))!
let height = cellPadding + photoHeight + cellPadding
let frame = CGRect(x: xOffsets[column], y: yOffsets[column], width: columnWidth, height: height)
let insetFrame = frame.insetBy(dx: cellPadding, dy: cellPadding)
// Create layout attributes
let attributes = PinterestLayoutAttributes(forCellWith: indexPath)
attributes.photoHeight = photoHeight
attributes.frame = insetFrame
attributesCache.append(attributes)
// Update column, yOffest
contentHeight = max(contentHeight, frame.maxY)
yOffsets[column] = yOffsets[column] + height
if column >= Int(numberOfColumns - 1) {
column = 0
} else {
column += 1
}
}
}
}
override var collectionViewContentSize: CGSize {
return CGSize(width: contentWidth, height: contentHeight)
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
var layoutAttributes = [UICollectionViewLayoutAttributes]()
for attributes in attributesCache {
if attributes.frame.intersects(rect) {
layoutAttributes.append(attributes)
}
}
return layoutAttributes
}
}
class PinterestLayoutAttributes : UICollectionViewLayoutAttributes {
var photoHeight: CGFloat = 0.0
override func copy(with zone: NSZone? = nil) -> Any {
let copy = super.copy(with: zone) as! PinterestLayoutAttributes
copy.photoHeight = photoHeight
return copy
}
override func isEqual(_ object: Any?) -> Bool {
if let attributes = object as? PinterestLayoutAttributes {
if attributes.photoHeight == photoHeight {
return super.isEqual(object)
}
}
return false
}
}
【问题讨论】:
-
我也面临同样的问题。你找到解决办法了吗?
-
我也面临同样的问题
-
开源项目以实现 Pinterest github.com/FarisAlbalawi/PinterestUISwift
标签: ios swift swift3 pinterest collectionview