使用Swift平衡Pinterest布局

问题描述 投票:2回答:1

我想在Pinterest上创建一个collectionView。这将是2列图片。

我的问题很简单。根据所使用的图片,使用我的代码,列可以包含更多高于另一列的图片。

一开始,一切都运行良好,但如果我们滚动,你会发现存在问题:

enter image description here enter image description here

我的问题是:这是正常的吗?我是否必须调整我的代码才能更好地放置图片,或者我是否必须调整我的“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
   }

}

PinterestLayout

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
   }
}
ios swift swift3 pinterest collectionview
1个回答
1
投票

我也面临同样的问题。我通过以下方式解决了它:

一开始我有一个包含一些元素的数组。我还声明了一个变量乘数。

var photos = ["pin1", "pin2", "pin3", "pin4", "pin2", "pin3", "pin4", "pin1", "pin2","pin1", "pin2", "pin3", "pin4", "pin2", "pin3", "pin4", "pin1", "pin2"]

var multiplier = 1

我按以下方式在数组中添加新元素:

override func scrollViewDidScroll(_ scrollView: UIScrollView) {
    let offset:CGFloat = CGFloat(200 * multiplier)
    let bottomEdge = scrollView.contentOffset.y + scrollView.frame.size.height;
    if (bottomEdge + offset >= scrollView.contentSize.height) {
        //Here Add new batch of elements in the array
        self.photos.append("pin1")
        self.photos.append("pin2")
        self.photos.append("pin3")
        self.photos.append("pin4")

        self.collectionView?.reloadData()
        self.multiplier =  self.multiplier + 1    

    }
}

我希望这对你有所帮助。

© www.soinside.com 2019 - 2024. All rights reserved.