iOS 사용자 정의 UICollection View Layout 폭포 흐름 레이아웃 구현

이동 단 접근 이 좋 지 않 습 니 다.저 를 방문 해 주세요개인 블 로그
최근 프로젝트 에 서 는 폭포 류 의 효 과 를 사용 해 야 하 는데,UICollection View Flow Layout 로 는 효 과 를 보지 못 하고 폭포 류 의 layot 를 직접 썼 습 니 다.다음은 제 마음의 거리 입 니 다.
선행 효과 도와demo 주소:

UICollectionView 로 폭포 흐름 을 실현 하기 때문에 UICollectionView Layout 를 계승 하여 하나의 layot 를 정의 하여 간단 한 폭포 흐름 의 구 조 를 실현 하기 로 결 정 했 습 니 다.다음은 다시 쓰 는 방법 입 니 다.
이 속성 을 다시 쓰 면 UICollection View 의 ContentSize:collection View ContentSize 를 얻 을 수 있 습 니 다.
이 방법 을 다시 써 서 각 아 이 템 의 레이아웃 을 가 져 옵 니 다:layout Attributes ForItem(at indexPath:IndexPath)->UICollection View LayoutAttributes?
이 방법 을 다시 쓰 면 UICollection View 의 모든 아 이 템 의 레이아웃 을 보 여 줍 니 다:layoutAttributes ForElements(in rect:CGRect)->[UICollection View LayoutAttributes]?
이 방법 을 다시 써 서 UICollectionView 전 동작:prepare()
사고의 방향 을 실현 하 다.
프 록 시 모드 를 통 해 필요 한 열 수 와 각 아 이 템 의 높이 를 얻 을 수 있 습 니 다.과 열 수 와 열 사이 의 간격 과 UICollection View 의 너비 로 각 열의 폭 을 얻 을 수 있 습 니 다.item 은 왼쪽 에서 오른쪽으로 배치 하고 다음 열의 item 은 높이 가 가장 작은 열 아래 에 놓 아 각 열의 높이 가 고 르 지 않 은 것 을 방지 합 니 다.아래 에 코드 와 설명 을 붙 입 니 다.

import UIKit

@objc protocol WCLWaterFallLayoutDelegate {
 //waterFall   
 func columnOfWaterFall(_ collectionView: UICollectionView) -> Int
 //  item   
 func waterFall(_ collectionView: UICollectionView, layout waterFallLayout: WCLWaterFallLayout, heightForItemAt indexPath: IndexPath) -> CGFloat
}

class WCLWaterFallLayout: UICollectionViewLayout {

 //  
 weak var delegate: WCLWaterFallLayoutDelegate?
 //   
 @IBInspectable var lineSpacing: CGFloat = 0
 //   
 @IBInspectable var columnSpacing: CGFloat = 0
 //section top
 @IBInspectable var sectionTop: CGFloat = 0 {
 willSet {
  sectionInsets.top = newValue
 }
 }
 //section Bottom
 @IBInspectable var sectionBottom: CGFloat = 0 {
 willSet {
  sectionInsets.bottom = newValue
 }
 }
 //section left
 @IBInspectable var sectionLeft: CGFloat = 0 {
 willSet {
  sectionInsets.left = newValue
 }
 }
 //section right
 @IBInspectable var sectionRight: CGFloat = 0 {
 willSet {
  sectionInsets.right = newValue
 }
 }
 //section Insets
 @IBInspectable var sectionInsets: UIEdgeInsets = UIEdgeInsets.zero
 //       
 private var columnHeights: [Int: CGFloat]   = [Int: CGFloat]()
 private var attributes: [UICollectionViewLayoutAttributes] = [UICollectionViewLayoutAttributes]()

 //MARK: Initial Methods
 init(lineSpacing: CGFloat, columnSpacing: CGFloat, sectionInsets: UIEdgeInsets) {
 super.init()
 self.lineSpacing = lineSpacing
 self.columnSpacing = columnSpacing
 self.sectionInsets = sectionInsets
 }

 required init?(coder aDecoder: NSCoder) {
 super.init(coder: aDecoder)
 }

 //MARK: Public Methods


 //MARK: Override
 override var collectionViewContentSize: CGSize {
 var maxHeight: CGFloat = 0
 for height in columnHeights.values {
  if height > maxHeight {
  maxHeight = height
  }
 }
 return CGSize.init(width: collectionView?.frame.width ?? 0, height: maxHeight + sectionInsets.bottom)
 }

 override func prepare() {
 super.prepare()
 guard collectionView != nil else {
  return
 }
 if let columnCount = delegate?.columnOfWaterFall(collectionView!) {
  for i in 0..<columnCount {
  columnHeights[i] = sectionInsets.top
  }
 }
 let itemCount = collectionView!.numberOfItems(inSection: 0)
 attributes.removeAll()
 for i in 0..<itemCount {
  if let att = layoutAttributesForItem(at: IndexPath.init(row: i, section: 0)) {
  attributes.append(att)
  }
 }
 }

 override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
 if let collectionView = collectionView {
  //  indexPath  item attributes
  let att = UICollectionViewLayoutAttributes.init(forCellWith: indexPath)
  //  collectionView   
  let width = collectionView.frame.width
  if let columnCount = delegate?.columnOfWaterFall(collectionView) {
  guard columnCount > 0 else {
   return nil
  }
  //item    = (collectionView    -        ) /   
  let totalWidth = (width - sectionInsets.left - sectionInsets.right - (CGFloat(columnCount) - 1) * columnSpacing)
  let itemWidth = totalWidth / CGFloat(columnCount)
  //  item   ,       
  let itemHeight = delegate?.waterFall(collectionView, layout: self, heightForItemAt: indexPath) ?? 0
  //        
  var minIndex = 0
  for column in columnHeights {
   if column.value < columnHeights[minIndex] ?? 0 {
   minIndex = column.key
   }
  }
  //          item x 
  let itemX = sectionInsets.left + (columnSpacing + itemWidth) * CGFloat(minIndex)
  //item y  =       y  +    
  let itemY = (columnHeights[minIndex] ?? 0) + lineSpacing
  //  attributes frame
  att.frame = CGRect.init(x: itemX, y: itemY, width: itemWidth, height: itemHeight)
  //        y 
  columnHeights[minIndex] = att.frame.maxY
  }
  return att
 }
 return nil
 }

 override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
 return attributes
 }
}

마지막 으로demo 주소..마음 에 드 시 면 스타 해 주세요.
위 는 간단 한 폭포 흐름 의 실현 과정 입 니 다.여러분 들 이 배 울 수 있 는 것 이 많 고 고려 할 부분 이 부족 합 니 다.여러분 들 이 교류 하고 공부 하 는 것 을 환영 합 니 다.읽 어 주 셔 서 감사합니다.

좋은 웹페이지 즐겨찾기