πŸ₯ΊPinterest Layout Tutorial

Overview

PinterestTutorial-iOS

πŸ₯Ί Pinterest Layout Tutorial

이미지 크기에 λ”°λΌμ„œ λ™μ μœΌλ‘œ μ…€μ˜ λ ˆμ΄μ•„μ›ƒμ„ μ„€μ •ν•˜λŠ” ν•€ν„°λ ˆμŠ€νŠΈ λ ˆμ΄μ•„μ›ƒ κ΅¬ν˜„ν•΄ λ³΄μ•˜λ‹€.

μ™„μ„±

μ½”λ“œ

  • UICollectionViewDelegateFlowLayout 의 μ„œλΈŒν΄λž˜μŠ€μΈ PinterestLayout 생성.
// PinterestLayout μ—μ„œ 각 이미지 높이λ₯Ό μ•Œ 수 μžˆλ„λ‘ Delegate 생성.
protocol PinterestLayoutDelegate: AnyObject {
    func collectionView(_ collectionView: UICollectionView, heightForPhotoAtIndexPath indexPath: IndexPath) -> CGFloat
}

class PinterestLayout: UICollectionViewFlowLayout {
    
    // delegate둜 ViewController λ₯Ό λ‚˜νƒ€λ‚Έλ‹€.
    weak var delegate: PinterestLayoutDelegate?
    
    private var contentHeight: CGFloat = 0
    
    private var contentWidth: CGFloat {
        guard let collectionView = collectionView else {
            return 0
        }
        let insets = collectionView.contentInset
        return collectionView.bounds.width - (insets.left + insets.right)
    }
    
    // 1. μ½œλ ‰μ…˜ 뷰의 μ½˜ν…μΈ  μ‚¬μ΄μ¦ˆλ₯Ό μ§€μ •ν•©λ‹ˆλ‹€.
    override var collectionViewContentSize: CGSize {
        return CGSize(width: contentWidth, height: contentHeight)
    }
    
    // λ‹€μ‹œ λ ˆμ΄μ•„μ›ƒμ„ 계산할 ν•„μš”κ°€ 없도둝 λ©”λͺ¨λ¦¬μ— μ €μž₯ν•©λ‹ˆλ‹€.
    private var cache: [UICollectionViewLayoutAttributes] = []
    
    // 2. μ½œλ ‰μ…˜ λ·°κ°€ 처음 μ΄ˆκΈ°ν™”λ˜κ±°λ‚˜ λ·°κ°€ 변경될 λ–„ μ‹€ν–‰λ©λ‹ˆλ‹€. 이 λ©”μ„œλ“œμ—μ„œ λ ˆμ΄μ•„μ›ƒμ„
    //    미리 κ³„μ‚°ν•˜μ—¬ λ©”λͺ¨λ¦¬μ— μ μž¬ν•˜κ³ , ν•„μš”ν•  λ•Œλ§ˆλ‹€ 효율적으둜 μ ‘κ·Όν•  수 μžˆλ„λ‘ κ΅¬ν˜„ν•΄μ•Ό ν•©λ‹ˆλ‹€.
    override func prepare() {
        guard let collectionView = collectionView, cache.isEmpty else { return }
        
        let numberOfColumns: Int = 2 // ν•œ ν–‰μ˜ μ•„μ΄ν…œ 갯수
        let cellPadding: CGFloat = 5
        let cellWidth: CGFloat = contentWidth / CGFloat(numberOfColumns)
        
        let xOffSet: [CGFloat] = [0, cellWidth] // cell 의 x μœ„μΉ˜λ₯Ό λ‚˜νƒ€λ‚΄λŠ” λ°°μ—΄
        var yOffSet: [CGFloat] = .init(repeating: 0, count: numberOfColumns) // // cell 의 y μœ„μΉ˜λ₯Ό λ‚˜νƒ€λ‚΄λŠ” λ°°μ—΄
        
        var column: Int = 0 // ν˜„μž¬ ν–‰μ˜ μœ„μΉ˜
        
        for item in 0..<collectionView.numberOfItems(inSection: 0) {
            // IndexPath 에 λ§žλŠ” μ…€μ˜ 크기, μœ„μΉ˜λ₯Ό κ³„μ‚°ν•©λ‹ˆλ‹€.
            let indexPath = IndexPath(item: item, section: 0)
            let imageHeight = delegate?.collectionView(collectionView, heightForPhotoAtIndexPath: indexPath) ?? 180
            let height = cellPadding * 2 + imageHeight
            
            let frame = CGRect(x: xOffSet[column],
                               y: yOffSet[column],
                               width: cellWidth,
                               height: height)
            let insetFrame = frame.insetBy(dx: cellPadding, dy: cellPadding)
            
            // μœ„μ—μ„œ κ³„μ‚°ν•œ Frame 을 기반으둜 cache 에 λ“€μ–΄κ°ˆ λ ˆμ΄μ•„μ›ƒ 정보λ₯Ό μΆ”κ°€ν•©λ‹ˆλ‹€.
            let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
            attributes.frame = insetFrame
            cache.append(attributes)
            
            // μ½œλ ‰μ…˜ 뷰의 contentHeight λ₯Ό λ‹€μ‹œ μ§€μ •ν•©λ‹ˆλ‹€.
            contentHeight = max(contentHeight, frame.maxY)
            yOffSet[column] = yOffSet[column] + height
            
            // λ‹€λ₯Έ 이미지 크기둜 μΈν•΄μ„œ, ν•œμͺ½ μ—΄μ—λ§Œ 이미지가 μΆ”κ°€λ˜λŠ” 것을 λ°©μ§€ν•©λ‹ˆλ‹€.
            column = yOffSet[0] > yOffSet[1] ? 1 : 0
        }
    }
    
    // 3. λͺ¨λ“  μ…€κ³Ό 보좩 뷰의 λ ˆμ΄μ•„μ›ƒ 정보λ₯Ό λ¦¬ν„΄ν•©λ‹ˆλ‹€. ν™”λ©΄ ν‘œμ‹œ μ˜μ—­ 기반(Rect)의 μš”μ²­μ΄ λ“€μ–΄μ˜¬ λ•Œ μ‚¬μš©ν•©λ‹ˆλ‹€.
        override func layoutAttributesForElements(in rect: CGRect)
        -> [UICollectionViewLayoutAttributes]? {
            var visibleLayoutAttributes: [UICollectionViewLayoutAttributes] = []
            
            for attributes in cache {
                if attributes.frame.intersects(rect) { // μ…€ frame κ³Ό μš”μ²­ Rect κ°€ κ΅μ°¨ν•œλ‹€λ©΄, 리턴 값에 μΆ”κ°€ν•©λ‹ˆλ‹€.
                    visibleLayoutAttributes.append(attributes)
                }
            }
            
            return visibleLayoutAttributes
        }
        
        // 4. λͺ¨λ“  μ…€μ˜ λ ˆμ΄μ•„μ›ƒ 정보λ₯Ό λ¦¬ν„΄ν•©λ‹ˆλ‹€. IndexPath 둜 μš”μ²­μ΄ λ“€μ–΄μ˜¬ λ•Œ 이 λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.
        override func layoutAttributesForItem(at indexPath: IndexPath)
        -> UICollectionViewLayoutAttributes? {
            return cache[indexPath.item]
        }
}
  • MainVC μ—μ„œ PinterestLayoutDelegate λ₯Ό 채택.
// MARK: - UICollectionViewDelegateFlowLayout
extension MainVC: PinterestLayoutDelegate {
    func collectionView(_ collectionView: UICollectionView, heightForPhotoAtIndexPath indexPath: IndexPath) -> CGFloat {
        let cellWidth: CGFloat = (view.bounds.width - 4) / 2 // μ…€ κ°€λ‘œ 크기
        let imageHeight = imageList[indexPath.item].image.size.height
        let imageWidth = imageList[indexPath.item].image.size.width
        // 이미지 λΉ„μœ¨
        let imageRatio = imageHeight/imageWidth
        
        
        return imageRatio * cellWidth
    }
}

좜처

μΆœμ²˜γ…£Swift. UICollectionView Pinterest λ ˆμ΄μ•„μ›ƒ

You might also like...
Auto Layout made easy
Auto Layout made easy

EasyPeasy is a Swift framework that lets you create Auto Layout constraints programmatically without headaches and never ending boilerplate code. Besi

Lightweight Swift framework for Apple's Auto-Layout
Lightweight Swift framework for Apple's Auto-Layout

I am glad to share with you a lightweight Swift framework for Apple's Auto-Layout. It helps you write readable and compact UI code using simple API. A

An Impressive Auto Layout DSL for  iOS, tvOS & OSX. & It is written in pure swift.
An Impressive Auto Layout DSL for iOS, tvOS & OSX. & It is written in pure swift.

KVConstraintKit KVConstraintKit is a DSL to make easy & impressive Auto Layout constraints on iOS, tvOS & OSX with Swift Installation Using CocoaPods

A compact but full-featured Auto Layout DSL for Swift
A compact but full-featured Auto Layout DSL for Swift

Mortar allows you to create Auto Layout constraints using concise, simple code statements. Use this: view1.m_right |=| view2.m_left - 12.0 Instead of:

The ultimate API for iOS & OS X Auto Layout β€” impressively simple, immensely powerful. Objective-C and Swift compatible.
The ultimate API for iOS & OS X Auto Layout β€” impressively simple, immensely powerful. Objective-C and Swift compatible.

The ultimate API for iOS & OS X Auto Layout β€” impressively simple, immensely powerful. PureLayout extends UIView/NSView, NSArray, and NSLayoutConstrai

Auto Layout In Swift Made Easy

Swiftstraints Swiftstraints can turn verbose auto-layout code: let constraint = NSLayoutConstraint(item: blueView, attr

TinyConstraints is the syntactic sugar that makes Auto Layout sweeter for human use.
TinyConstraints is the syntactic sugar that makes Auto Layout sweeter for human use.

TinyConstraints is the syntactic sugar that makes Auto Layout sweeter for human use. Features Pure Swift 5 sweetness. Everything you can do with Auto

A declarative UIKit for improve layout productivity when developing an iOS application

TifoKit A declarative UIKit for improve layout productivity when developing an iOS application Requirements Min. iOS 11 Swift 5+ Installation Currentl

πŸ— MondrianLayout - describing structured layout for AutoLayout
πŸ— MondrianLayout - describing structured layout for AutoLayout

πŸ— A DSL based layout builder for AutoLayout

Owner
Hyungyu Kim
λ‚˜λŠ” ν˜„κ·œλ‹€
Hyungyu Kim
Auto Layout (and manual layout) in one line.

Auto Layout (and manual layout) in one line. Quick Look view.bb.centerX().below(view2).size(100) It’s equivalent to iOS 9 API: view.centerXAnchor.cons

Javier Zhang 74 Oct 19, 2022
Auto Layout made easy with the Custom Layout.

Auto Layout made easy with the Custom Layout. Getting started CocoaPods CocoaPods is a dependency manager for Cocoa projects. You can install it with

Malith Nadeeshan 1 Jan 16, 2022
AppStoreClone - Understanding the complex layout of app store using UICompositional layout in swift

AppStoreClone Understanding the complex layout of app store using UICompositiona

Dheeraj Kumar Sharma 8 Dec 28, 2022
A custom layout built on top of SwiftUI's Layout API that lays elements out in multiple lines. Similar to flex-wrap in CSS, CollectionViewFlowLayout.

WrapLayout A custom layout built on top of SwiftUI's Layout API that lays elements out in multiple lines. Similar to flex-wrap in CSS, CollectionViewF

Hiroshi Kimura 6 Sep 27, 2022
BrickKit is a delightful layout library for iOS and tvOS. It is written entirely in Swift!

BrickKit is a delightful layout library for iOS and tvOS. It is written entirely in Swift! Deprecated BrickKit is being phased out at Wayfair, and the

Wayfair Tech – Archive 608 Sep 15, 2022
LayoutKit is a fast view layout library for iOS, macOS, and tvOS.

?? UNMAINTAINED ?? This project is no longer used by LinkedIn and is currently unmaintained. LayoutKit is a fast view layout library for iOS, macOS, a

LinkedIn's Attic 3.2k Dec 27, 2022
A powerful Swift programmatic UI layout framework.

Build dynamic and beautiful user interfaces like a boss, with Swift. Neon is built around how user interfaces are naturally and intuitively designed.

Mike 4.6k Dec 26, 2022
Fast Swift Views layouting without auto layout. No magic, pure code, full control and blazing fast. Concise syntax, intuitive, readable & chainable. [iOS/macOS/tvOS/CALayer]

Extremely Fast views layouting without auto layout. No magic, pure code, full control and blazing fast. Concise syntax, intuitive, readable & chainabl

layoutBox 2.1k Dec 22, 2022
A declarative Auto Layout DSL for Swift :iphone::triangular_ruler:

Cartography ?? ?? Using Cartography, you can set up your Auto Layout constraints in declarative code and without any stringly typing! In short, it all

Robb BΓΆhnke 7.3k Jan 4, 2023
An easy way to create and layout UI components for iOS (Swift version).

Introduction Cupcake is a framework that allow you to easily create and layout UI components for iOS 8.0+. It use chaining syntax and provides some fr

nerdycat 288 Oct 9, 2022