Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create CardsCollectionViewVerticalLayout.swift #3

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 140 additions & 0 deletions CardsCollectionViewHorizontalLayout.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
//
// CardsCollectionViewHorizontalLayout.swift
// CardsLayout
//
// Created by Filipp Fediakov on 03.01.18.
// Copyright © 2018 filletofish. All rights reserved.
//

import UIKit


protocol CardsCollectionViewLayout {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the protocol to constraint different layouts for common interface.

var itemSize: CGSize { get set }
var spacing: CGPoint { get set }
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use CGPoint instead CGFloat to add different spacing for different axis.

var maximumVisibleItems: Int { get set }
}


open class CardsCollectionViewHorizontalLayout: UICollectionViewLayout, CardsCollectionViewLayout {

// MARK: Layout configuration

public var itemSize: CGSize = CGSize(width: 200, height: 300) {
didSet {
invalidateLayout()
}
}

public var spacing: CGPoint = CGPoint(x: 10.0, y: 10.0) {
didSet {
invalidateLayout()
}
}

public var maximumVisibleItems: Int = 4 {
didSet {
invalidateLayout()
}
}

// MARK: - UICollectionViewLayout

override open var collectionView: UICollectionView {
return super.collectionView!
}

override open var collectionViewContentSize: CGSize {
let itemsCount = CGFloat(collectionView.numberOfItems(inSection: 0))
return CGSize(width: collectionView.bounds.width * itemsCount,
height: collectionView.bounds.height)
}

override open func prepare() {
super.prepare()
assert(collectionView.numberOfSections == 1, "Multiple sections aren't supported!")
}

override open func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let totalItemsCount = collectionView.numberOfItems(inSection: 0)
let minVisibleIndex = max(Int(collectionView.contentOffset.x) / Int(collectionView.bounds.width), 0)
let maxVisibleIndex = min(minVisibleIndex + maximumVisibleItems, totalItemsCount)
let visibleIndices = minVisibleIndex..<maxVisibleIndex
let attributes: [UICollectionViewLayoutAttributes?] = visibleIndices.map { index in
let indexPath = IndexPath(item: index, section: 0)
return self.layoutAttributesForItem(at: indexPath)
}
let filteredAttributes = attributes.flatMap { $0 }
return filteredAttributes
}

override open func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
let minVisibleIndex = Int(collectionView.contentOffset.x) / Int(collectionView.bounds.width)
let deltaOffset = CGFloat(Int(collectionView.contentOffset.x) % Int(collectionView.bounds.width))
let percentageDeltaOffset = CGFloat(deltaOffset) / collectionView.bounds.width
let visibleIndex = indexPath.row - minVisibleIndex

let attributes = UICollectionViewLayoutAttributes(forCellWith:indexPath)
attributes.size = itemSize
let midY = self.collectionView.bounds.midY
let midX = self.collectionView.bounds.midX
attributes.center = CGPoint(x: midX + spacing.x * CGFloat(visibleIndex),
y: midY + spacing.y * CGFloat(visibleIndex))
attributes.zIndex = maximumVisibleItems - visibleIndex
attributes.transform = scaleTransform(forVisibleIndex: visibleIndex,
percentageOffset: percentageDeltaOffset)


switch visibleIndex {
case 0:
attributes.center.x -= deltaOffset
attributes.isHidden = false
break
case 1..<maximumVisibleItems:
attributes.center.x -= spacing.x * percentageDeltaOffset
attributes.center.y -= spacing.y * percentageDeltaOffset
if visibleIndex == maximumVisibleItems - 1 {
attributes.alpha = percentageDeltaOffset
} else {
attributes.alpha = 1.0
}

attributes.isHidden = false
break
default:
attributes.alpha = 0
attributes.isHidden = true
break
}
return attributes
}

override open func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
return true
}
}


extension CardsCollectionViewLayout {
private func scale(at index: Int) -> CGFloat {
let translatedCoefficient = CGFloat(index) - CGFloat(self.maximumVisibleItems) / 2
return CGFloat(pow(0.95, translatedCoefficient))
}

func scaleTransform(forVisibleIndex visibleIndex: Int, percentageOffset: CGFloat) -> CGAffineTransform {
guard visibleIndex != 0 else {
let scaleAtZeroIndex = scale(at: visibleIndex)
return CGAffineTransform(scaleX: scaleAtZeroIndex, y: scaleAtZeroIndex)
}

guard visibleIndex < maximumVisibleItems else {
return CGAffineTransform.identity
}

var rawScale = scale(at: visibleIndex)
let previousScale = scale(at: visibleIndex - 1)
let delta = (previousScale - rawScale) * percentageOffset
rawScale += delta
return CGAffineTransform(scaleX: rawScale, y: rawScale)
}
}
148 changes: 0 additions & 148 deletions CardsCollectionViewLayout.swift

This file was deleted.

108 changes: 108 additions & 0 deletions CardsCollectionViewVerticalLayout.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
//
// CardsCollectionViewVerticalLayout.swift
// CardsLayout
//
// Created by Filipp Fediakov on 18.08.17.
// Copyright © 2017 filletofish. All rights reserved.
//

import UIKit

open class CardsCollectionViewVerticalLayout: UICollectionViewLayout, CardsCollectionViewLayout {

// MARK: Layout configuration

public var itemSize: CGSize = CGSize(width: 200, height: 300) {
didSet{
invalidateLayout()
}
}

public var spacing: CGPoint = CGPoint(x: 10.0, y: 20.0) {
didSet{
invalidateLayout()
}
}

public var maximumVisibleItems: Int = 4 {
didSet{
invalidateLayout()
}
}

// MARK: - UICollectionViewLayout

override open var collectionView: UICollectionView {
return super.collectionView!
}

override open var collectionViewContentSize: CGSize {
let itemsCount = CGFloat(collectionView.numberOfItems(inSection: 0))
return CGSize(width: collectionView.bounds.width,
height: collectionView.bounds.height * itemsCount)
}

override open func prepare() {
super.prepare()
assert(collectionView.numberOfSections == 1, "Multiple sections aren't supported!")
}

override open func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let totalItemsCount = collectionView.numberOfItems(inSection: 0)
let minVisibleIndex = max(Int(collectionView.contentOffset.y) / Int(collectionView.bounds.height), 0)
let maxVisibleIndex = min(minVisibleIndex + maximumVisibleItems, totalItemsCount)
let visibleIndices = minVisibleIndex..<maxVisibleIndex
let attributes: [UICollectionViewLayoutAttributes?] = visibleIndices.map { index in
let indexPath = IndexPath(item: index, section: 0)
return self.layoutAttributesForItem(at: indexPath)
}
let filteredAttributes = attributes.flatMap { $0 }
return filteredAttributes
}

override open func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
let minVisibleIndex = Int(collectionView.contentOffset.y) / Int(collectionView.bounds.height)
let deltaOffset = CGFloat(Int(collectionView.contentOffset.y) % Int(collectionView.bounds.height))
let percentageDeltaOffset = CGFloat(deltaOffset) / collectionView.bounds.height
let visibleIndex = indexPath.row - minVisibleIndex

let attributes = UICollectionViewLayoutAttributes(forCellWith:indexPath)
attributes.size = itemSize
let midY = self.collectionView.bounds.midY
let midX = self.collectionView.bounds.midX
attributes.center = CGPoint(x: midX + spacing.x * CGFloat(visibleIndex),
y: midY + spacing.y * CGFloat(visibleIndex))
attributes.zIndex = maximumVisibleItems - visibleIndex
attributes.transform = scaleTransform(forVisibleIndex: visibleIndex,
percentageOffset: percentageDeltaOffset)


switch visibleIndex {
case 0:
attributes.center.y -= deltaOffset
attributes.isHidden = false
break
case 1..<maximumVisibleItems:
attributes.center.x -= spacing.x * percentageDeltaOffset
attributes.center.y -= spacing.y * percentageDeltaOffset
if visibleIndex == maximumVisibleItems - 1 {
attributes.alpha = percentageDeltaOffset
} else {
attributes.alpha = 1.0
}

attributes.isHidden = false
break
default:
attributes.alpha = 0
attributes.isHidden = true
break
}
return attributes
}


override open func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
return true
}
}
Loading