CollectionView -Stop/Prevent Section Header from Scrolling Beyond a Certain Point - ios

I have a collectionView that is pinned to the top of the view controller with a no navigationBar collectionView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true.
It has a sticky header let headerLayout = cv.collectionViewLayout as? UICollectionViewFlowLayout; headerLayout?.sectionHeadersPinToVisibleBounds = true
The collectionView has 2 sections, the first section has no header but the second section does have a header. The issue is because the collectionView isn't pinned to the safeAreaLayoutGuide.topAnchor and there isn't a navigationBar, when I scroll, the header in the second section gets pinned to the very top of the screen behind the status bar.
How can I prevent the header from scrolling beyond a certain point. For example if I had a button pinned to the top of the screen, the header would stop once it hit the bottom of the button
myButton.topAnchor.constraint(equalTo: view.topAnchor, constant: 50).isActive = true
func scrollViewDidScroll(_ scrollView: UIScrollView) {
scrollView.contentInsetAdjustmentBehavior = .never
let secondIndexPath = IndexPath(item: 0, section: 1)
collectionView.layoutIfNeeded()
if let headerFrameInCollectionView = collectionView.layoutAttributesForSupplementaryElement(ofKind: UICollectionView.elementKindSectionHeader, at: secondIndexPath), let window = UIApplication.shared.windows.first(where: \.isKeyWindow) {
let headerFrameInSuperView = collectionView.convert(headerFrameInCollectionView.frame, to: collectionView.superview)
let headerOriginY = headerFrameInSuperView.origin.y
let buttonFrame = view.convert(myButton.frame, to: window)
let bottomOfButton = buttonFrame.origin.y + buttonFrame.height
if headerOriginY == bottomOfButton {
collectionView.contentInset.top = headerOriginY // stop header from scrolling any further
} else {
collectionView.contentInset.top = 0
}
}
}

In short, to get this to work I had to set the collectionView.contentInset.top to whatever point I wanted section two's header to stop at but I also had to set the collectionView.contentOffset.y to a stop position.
if headerOriginY <= bottomOfButton {
collectionView.contentInset.top = bottomOfButton
collectionView.contentOffset.y = cellHeightFromSectionOne - bottomOfButton
} else {
collectionView.contentInset.top = 0
}
In long, I have 2 sections and what happens is if I set collectionView.contentInset.top = bottomOfButton in section 2 without changing the collectionView.contentOffset.y, the cell in section 1 scrolls off the screen and the whole process is very buggy. To get it to work:
1- get the height for the cell in the first section. Luckily for me this was easy because in section 1 the cell's height is the width of the screen and there is only 1 cell in section 1. In section 2 there aren't any cells so the cell size for that is .zero:
// size for the cells
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = UIScreen.main.bounds.width // the collectionView is the same width
if indexPath.section == 0 {
return CGSize(width: width, height: width)
}
return .zero // section 2 has no cells, just a header
}
2- In scrollViewDidScroll, this is where all the work is done. The variable names explains the process
func scrollViewDidScroll(_ scrollView: UIScrollView) {
scrollView.contentInsetAdjustmentBehavior = .never
let secondIndexPath = IndexPath(item: 0, section: 1)
collectionView.layoutIfNeeded()
if let headerTwoAttributes = collectionView.layoutAttributesForSupplementaryElement(ofKind: UICollectionView.elementKindSectionHeader, at: secondIndexPath), let window = UIApplication.shared.windows.first(where: \.isKeyWindow) {
let headerTwoFrameInSuperView = collectionView.convert(headerTwoAttributes.frame, to: collectionView.superview)
let headerTwoOriginY = headerTwoFrameInSuperView.origin.y
let buttonFrame = view.convert(myButton.frame, to: window)
let bottomPositionOfButtonInWindow = buttonFrame.origin.y + buttonFrame.height
let stopScrollingPositionY = bottomPositionOfButtonInWindow
let cellHeightFromSectionOne = UIScreen.main.bounds.width
let preventFirstCellInSectionOneFromScrollingPosition = cellHeightFromSectionOne - stopScrollingPositionY
if headerTwoOriginY <= stopScrollingPositionY {
collectionView.contentInset.top = stopScrollingPositionY
collectionView.contentOffset.y = preventFirstCellInSectionOneFromScrollingPosition
} else {
collectionView.contentInset.top = 0 // reset this to 0
}
}
}

Related

UICollectionViewFlowLayout issues

Apologies in advance but I've been going around in circles on this for days...
I have a UIViewController that is presented from another VC (in my case, a button is tapped). The new VC (code below) is made up of:
a UITextView which dynamically increases in height based on content the user types in
a UIView which has a fixed height
and then below that, to the bottom of the ViewController view, is a UICollectionView. This has 5 sections in it that horizontally scroll. I will be inserting different content into each of those 5 cells but am just having issues at the moment when the UICollectionView resizes. I've been able to get most of them cleared except for one.
This error can be reproduced whenever the UITextView increases in size to between 3-6 lines long, and again at 13 lines... This happens in the simulator using e.g. an iPhone 8 plus but on an iPhone 11 Pro Max, it only happens around 19 lines of text in the UITextView.
I am using TinyContraints here but I've tested using traditional programmatic constraints and had the same issue.
//
// NewItemVC.swift
//
import TinyConstraints
import UIKit
class NewItemVC: UIViewController {
let titleField = UITextView()
let bannerContainer = UIView(frame: .zero)
var flowLayout = UICollectionViewFlowLayout()
lazy var horizontalCV = UICollectionView(frame: .zero, collectionViewLayout: flowLayout)
let genericCellID = "genericCellID"
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .orange
setupHeaderArea()
setupBannerArea()
setupHorizontalCollectionView()
}
func setupHeaderArea(){
titleField.backgroundColor = .lightGray
titleField.textContainerInset.top = 55
titleField.textContainerInset.bottom = 20
titleField.textContainerInset.left = 15
titleField.textContainerInset.right = 15
titleField.font = UIFont.boldSystemFont(ofSize: 20)
// add to main view & position
view.addSubview(titleField)
titleField.topToSuperview()
titleField.leftToSuperview()
titleField.rightToSuperview()
titleField.isScrollEnabled = false
NotificationCenter.default.addObserver(self, selector: #selector(updateTextFieldHeight), name: UITextView.textDidChangeNotification, object: nil)
// add a header label
let headerLabel = UILabel()
headerLabel.textColor = .systemBlue
headerLabel.text = "NEW ITEM"
headerLabel.font = UIFont.systemFont(ofSize: 12)
view.addSubview(headerLabel)
headerLabel.topToSuperview(offset: 35)
headerLabel.leftToSuperview(offset: 20)
headerLabel.height(13)
// add card handle
let handle = UIView()
handle.backgroundColor = .black
handle.alpha = 0.2
handle.width(45)
handle.height(5)
handle.layer.cornerRadius = 5/2
view.addSubview(handle)
handle.topToSuperview(offset: 10)
handle.centerXToSuperview()
}
func setupBannerArea(){
// position container
view.addSubview(bannerContainer)
bannerContainer.topToBottom(of: titleField)
bannerContainer.edgesToSuperview(excluding: [.top, .bottom])
bannerContainer.height(62)
bannerContainer.backgroundColor = .cyan
}
func setupHorizontalCollectionView() {
horizontalCV = UICollectionView(frame: .zero, collectionViewLayout: flowLayout)
horizontalCV.dataSource = self
horizontalCV.delegate = self
horizontalCV.backgroundColor = .yellow
horizontalCV.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
horizontalCV.scrollIndicatorInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
view.addSubview(horizontalCV)
horizontalCV.topToBottom(of: bannerContainer)
horizontalCV.edgesToSuperview(excluding: .top)
horizontalCV.isPagingEnabled = true
horizontalCV.contentInsetAdjustmentBehavior = .never
flowLayout.scrollDirection = .horizontal
flowLayout.minimumLineSpacing = 0
flowLayout.minimumInteritemSpacing = 0
horizontalCV.register(UICollectionViewCell.self, forCellWithReuseIdentifier: genericCellID)
}
#objc func updateTextFieldHeight() {
DispatchQueue.main.async{
self.horizontalCV.collectionViewLayout.invalidateLayout()
}
}
}
// MARK:- Delegates - UITextViewDelegate
extension NewItemVC: UITextViewDelegate {
func textViewDidChange(_ textView: UITextView) {
let size = CGSize(width: textView.frame.width, height: .infinity)
let estimatedSize = textView.sizeThatFits(size)
textView.constraints.forEach { (constraint) in
if constraint.firstAttribute == .height {
constraint.constant = estimatedSize.height
}
}
}
}
// MARK:- UICollectionView Data Source
extension NewItemVC: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 5
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: genericCellID, for: indexPath)
if indexPath.row % 2 == 0 {
cell.backgroundColor = .orange
} else {
cell.backgroundColor = .red
}
return cell
}
}
// MARK:- Delegates - UICollectionView Flow Layout
extension NewItemVC: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let requiredHeight = self.view.frame.height - (titleField.frame.height + bannerContainer.frame.height)
let requiredWidth = view.frame.width
return CGSize(width: requiredWidth, height: requiredHeight)
}
}
From what I've been able to tell, there's some issue randomly where the collectionView frame and the contentSize are out by 24 points but I can't work out why/where etc...
The error is as follows:
2020-02-06 20:39:18.425280+1100 Scrolling[67237:8005204] The behavior of the UICollectionViewFlowLayout is not defined because:
2020-02-06 20:39:18.425378+1100 Scrolling[67237:8005204] the item height must be less than the height of the UICollectionView minus the section insets top and bottom values, minus the content insets top and bottom values.
2020-02-06 20:39:18.425672+1100 Scrolling[67237:8005204] The relevant UICollectionViewFlowLayout instance is <UICollectionViewFlowLayout: 0x7fcf56d4a120>, and it is attached to <UICollectionView: 0x7fcf5785d000; frame = (0 208.667; 414 487.333); clipsToBounds = YES; gestureRecognizers = <NSArray: 0x600000ce8a50>; layer = <CALayer: 0x600000213a00>; contentOffset: {0, 0}; contentSize: {2070, 511}; adjustedContentInset: {0, 0, 0, 0}; layout: <UICollectionViewFlowLayout: 0x7fcf56d4a120>; dataSource: <Scrolling.NewItemVC: 0x7fcf56d20110>>.
2020-02-06 20:39:18.425760+1100 Scrolling[67237:8005204] Make a symbolic breakpoint at UICollectionViewFlowLayoutBreakForInvalidSizes to catch this in the debugger.

How can I apply a CGAffineTransform to a UICollectionViewCell while the UICollectionView is scrolling

I am creating a kind of horizontally scrolling menu with multiple items that the user can scroll through.(see picture at the bottom for a preview of what I mean)
The UICollectionView offset already always centers on one of its items. What I want to do is that when an item is the next one to approach the center, I want to apply a transformation to make it larger. This is the code that I'm using to achieve this (the logic doesn't handle animating out of the center or scrolling the other direction yet):
func scrollViewDidScroll(_ scrollView: UIScrollView) {
guard let scrolledCollectionView = scrollView as? UICollectionView,
let flowLayout = scrolledCollectionView.collectionViewLayout as? UICollectionViewFlowLayout else { return }
let itemWidth = flowLayout.itemSize.width
let collectionViewCenter = collectionView.bounds.width * 0.5 + scrolledCollectionView.contentOffset.x
let itemToEnlarge = Int((scrolledCollectionView.contentOffset.x + (itemWidth * 0.5)) / (itemWidth + flowLayout.minimumInteritemSpacing))
let itemEnlargeIndexpath = IndexPath(row: itemToEnlarge, section: 0)
guard let cellToAnimate = collectionView.cellForItem(at: itemEnlargeIndexpath) else { return }
let diff = cellToAnimate.center.x - collectionViewCenter
var transformationVolume: CGFloat = 1
if diff == 0 {
transformationVolume += 0.2
} else {
transformationVolume += (0.2 / diff)
}
DispatchQueue.main.async {
cellToAnimate.transform = CGAffineTransform(scaleX: transformationVolume, y: transformationVolume)
}
}
The problem that I'm having is that the transformation is only applied once the collectionview has stopped scrolling. Does anyone know if there's a way to apply the transformation dynamically? So that if you scroll the item towards the center little by little, the transformation is applied incrementally.

How do I center align my collectionView cells?

I tried this solution here but it seems to only work for vertical layout. I'm trying to make it work for a horizontal layout. In my case, I always want 3 cells on top and 2 on bottom that is center aligned.
Example:
I think this should help you a bit (I defined insets in delegate method because collectionview would otherwise center only my 1st section and leave others untouched):
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
// handling layout
// which needs to be centered vertically and horizontally
// also:
// maximum number of items = 6
// maximum number of rows = 2
// maximum number of items in row = 3
let numberOfItems: CGFloat
let numberOfRows: CGFloat
if collectionView.numberOfItems(inSection: section) > Constants.maxNumberOfItemsInRow {
numberOfItems = CGFloat(Constants.maxNumberOfItemsInRow)
numberOfRows = CGFloat(Constants.maxNumberOfRows)
} else {
numberOfItems = CGFloat(collectionView.numberOfItems(inSection: section))
numberOfRows = CGFloat(Constants.minNumberOfRows)
}
let totalCellWidth = Constants.itemSize.width * numberOfItems
let totalSpacingWidth = Constants.minimumInteritemSpacing * numberOfItems
var leftInset = (collectionView.layer.frame.size.width - CGFloat(totalCellWidth + totalSpacingWidth)) / 2
let totalCellHeight = Constants.itemSize.height * numberOfRows
let maximumSectionHeight = (Constants.itemSize.height * CGFloat(Constants.maxNumberOfRows)) + (CGFloat(Constants.maxNumberOfRows + 1) * Constants.minimumLineSpacing)
if leftInset < 0.0 { leftInset = 0.0 }
let topInset = (maximumSectionHeight - totalCellHeight) / 2
let rightInset = leftInset
return UIEdgeInsets(top: topInset, left: leftInset, bottom: topInset, right: rightInset)
}
Also, layout is defined by class:
class CollectionViewFlowLayout: UICollectionViewFlowLayout {
// MARK: - Constants
private struct Constants {
static let minimumInteritemSpacing: CGFloat = 12.5
static let minimumLineSpacing: CGFloat = 16.5
static let itemSize = CGSize(width: 64.0, height: 90.0)
}
override func prepare() {
guard let collectionView = collectionView else { return }
/// Defining flow layout for collectionview presentation
itemSize = Constants.itemSize
headerReferenceSize = CGSize(width: collectionView.dc_width, height: 1)
scrollDirection = .vertical
minimumInteritemSpacing = Constants.minimumInteritemSpacing
minimumLineSpacing = Constants.minimumLineSpacing
super.prepare()
}
}

Resizing UICollectionView with Custom Layout after deleting cells

I downloaded this Pintrest-esc Custom Layout for my CollectionView from : https://www.raywenderlich.com/164608/uicollectionview-custom-layout-tutorial-pinterest-2 (modified it a little bit to do with cache code)
So the layout works fine, i got it set up so when you scroll to the bottom, i make another API call, create and populate additional cells.
Problem: If a User scrolls down and loads some more cells (lets say 20 for example) and then uses the "Search Feature" i have implemented at the top, it will then filter some of the data via price from MinRange - MaxRange leaving you with (lets say 5 results), thus deleting some cells and repopulating those. BUT - All that space and scrollable space that existed for the first 20 cells still exists as blank white space.... How can i remove this space ? and why can it resize when adding more cells, but not when removing them ?
Code of my API Call:
DispatchQueue.global(qos: .background).async {
WebserviceController.GetSearchPage(parameters: params) { (success, data) in
if success
{
if let products = data!["MESSAGE"] as? [[String : AnyObject]]
{
self.productList = products
}
}
DispatchQueue.main.async(execute: { () -> Void in
self.pintrestCollectionView.reloadData()
self.pintrestCollectionView.collectionViewLayout.invalidateLayout()
self.pintrestCollectionView.layoutSubviews()
})
}
}
Code Of Custom Layout Class & protocol:
protocol PinterestLayoutDelegate: class {
func collectionView(_ collectionView:UICollectionView, heightForPhotoAtIndexPath indexPath:IndexPath) -> CGFloat
}
class PintrestLayout: UICollectionViewFlowLayout {
// 1
weak var delegate : PinterestLayoutDelegate!
// 2
fileprivate var numberOfColumns = 2
fileprivate var cellPadding: CGFloat = 10
// 3
fileprivate var cache = [UICollectionViewLayoutAttributes]()
// 4
fileprivate var contentHeight: CGFloat = 0
fileprivate var contentWidth: CGFloat {
guard let collectionView = collectionView else {
return 0
}
let insets = collectionView.contentInset
return collectionView.bounds.width - (insets.left + insets.right)
}
// 5
override var collectionViewContentSize: CGSize {
return CGSize(width: contentWidth, height: contentHeight)
}
override func prepare() {
// 1
//You only calculate the layout attributes if cache is empty and the collection view exists.
/*guard cache.isEmpty == true, let collectionView = collectionView else {
return
}*/
cache.removeAll()
guard cache.isEmpty == true || cache.isEmpty == false, let collectionView = collectionView else {
return
}
// 2
//This declares and fills the xOffset array with the x-coordinate for every column based on the column widths. The yOffset array tracks the y-position for every column.
let columnWidth = contentWidth / CGFloat(numberOfColumns)
var xOffset = [CGFloat]()
for column in 0 ..< numberOfColumns {
xOffset.append(CGFloat(column) * columnWidth)
}
var column = 0
var yOffset = [CGFloat](repeating: 0, count: numberOfColumns)
// 3
//This loops through all the items in the first section, as this particular layout has only one section.
for item in 0 ..< collectionView.numberOfItems(inSection: 0) {
if collectionView.numberOfItems(inSection: 0) < 3
{
collectionView.isScrollEnabled = false
} else {
collectionView.isScrollEnabled = true
}
let indexPath = IndexPath(item: item, section: 0)
// 4
//This is where you perform the frame calculation. width is the previously calculated cellWidth, with the padding between cells removed.
let photoHeight = delegate.collectionView(collectionView, heightForPhotoAtIndexPath: indexPath)
let height = cellPadding * 2 + photoHeight
let frame = CGRect(x: xOffset[column], y: yOffset[column], width: columnWidth, height: height)
let insetFrame = frame.insetBy(dx: 7, dy: 4)
collectionView.contentInset = UIEdgeInsets.init(top: 15, left: 12, bottom: 0, right: 12)
// 5
//This creates an instance of UICollectionViewLayoutAttribute, sets its frame using insetFrame and appends the attributes to cache.
let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
attributes.frame = insetFrame
cache.append(attributes)
// 6
//This expands contentHeight to account for the frame of the newly calculated item.
contentHeight = max(contentHeight, frame.maxY)
yOffset[column] = yOffset[column] + height
column = column < (numberOfColumns - 1) ? (column + 1) : 0
}
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]?
{
var visibleLayoutAttributes = [UICollectionViewLayoutAttributes]()
// Loop through the cache and look for items in the rect
for attributes in cache {
if attributes.frame.intersects(rect) {
visibleLayoutAttributes.append(attributes)
}
}
return visibleLayoutAttributes
}
FYI: In MainStoryboard, i disabled "Adjust Scroll View Insets" as many of other threads and forums have suggested...
I'm guessing you've already found the answer, but I'm posting here for the next person since I ran into this issue.
The trick here is contentHeight actually never gets smaller.
contentHeight = max(contentHeight, frame.maxY)
This is a nondecreasing function.
To fix it, just set contentHeight to 0 if prepare is called:
guard cache.isEmpty == true || cache.isEmpty == false, let
collectionView = collectionView else {
return
}
contentHeight = 0

How to set UICollectionView bottom padding and scrolling size

Hello I have working uicollectionview custom layout and i have issuesfor bottom padding and scrolling sizes. Under below picture you can see;
Also top side first cell always stays on top when scrolling ( Left side cell must be always stay right now no problem there , but top side cell must be scroll when scrolling )
I try to set in viewDidLoad under below codes but dont work
self.automaticallyAdjustsScrollViewInsets = false
self.collectionView.contentInset = UIEdgeInsetsMake(20, 20, 120, 100);
My custom collectionview layout file
import UIKit
public var CELL_HEIGHT = CGFloat(22)
protocol CustomCollectionViewDelegateLayout: NSObjectProtocol {
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, widthForItemAtIndexPath indexPath: NSIndexPath) -> CGFloat
}
class CustomCollectionViewLayout: UICollectionViewLayout {
// Used for calculating each cells CGRect on screen.
// CGRect will define the Origin and Size of the cell.
let STATUS_BAR = UIApplication.sharedApplication().statusBarFrame.height
// Dictionary to hold the UICollectionViewLayoutAttributes for
// each cell. The layout attribtues will define the cell's size
// and position (x, y, and z index). I have found this process
// to be one of the heavier parts of the layout. I recommend
// holding onto this data after it has been calculated in either
// a dictionary or data store of some kind for a smooth performance.
var cellAttrsDictionary = Dictionary<NSIndexPath, UICollectionViewLayoutAttributes>()
// Defines the size of the area the user can move around in
// within the collection view.
var contentSize = CGSize.zero
// Used to determine if a data source update has occured.
// Note: The data source would be responsible for updating
// this value if an update was performed.
var dataSourceDidUpdate = true
weak var delegate: CustomCollectionViewDelegateLayout?
override func collectionViewContentSize() -> CGSize {
return self.contentSize
}
override func prepareLayout() {
// Only update header cells.
if !dataSourceDidUpdate {
// Determine current content offsets.
let xOffset = collectionView!.contentOffset.x
let yOffset = collectionView!.contentOffset.y
if collectionView?.numberOfSections() > 0 {
for section in 0...collectionView!.numberOfSections()-1 {
// Confirm the section has items.
if collectionView?.numberOfItemsInSection(section) > 0 {
// Update all items in the first row.
if section == 0 {
for item in 0...collectionView!.numberOfItemsInSection(section)-1 {
// Build indexPath to get attributes from dictionary.
let indexPath = NSIndexPath(forItem: item, inSection: section)
// Update y-position to follow user.
if let attrs = cellAttrsDictionary[indexPath] {
var frame = attrs.frame
// Also update x-position for corner cell.
if item == 0 {
frame.origin.x = xOffset
}
frame.origin.y = yOffset
attrs.frame = frame
}
}
// For all other sections, we only need to update
// the x-position for the fist item.
} else {
// Build indexPath to get attributes from dictionary.
let indexPath = NSIndexPath(forItem: 0, inSection: section)
// Update y-position to follow user.
if let attrs = cellAttrsDictionary[indexPath] {
var frame = attrs.frame
frame.origin.x = xOffset
attrs.frame = frame
}
}
}
}
}
// Do not run attribute generation code
// unless data source has been updated.
return
}
// Acknowledge data source change, and disable for next time.
dataSourceDidUpdate = false
var maxWidthInASection = CGFloat(0)
// Cycle through each section of the data source.
if collectionView?.numberOfSections() > 0 {
for section in 0...collectionView!.numberOfSections()-1 {
// Cycle through each item in the section.
if collectionView?.numberOfItemsInSection(section) > 0 {
var prevCellAttributes: UICollectionViewLayoutAttributes?
for item in 0...collectionView!.numberOfItemsInSection(section)-1 {
let cellIndex = NSIndexPath(forItem: item, inSection: section)
guard let width = delegate?.collectionView(collectionView!, layout: self, widthForItemAtIndexPath: cellIndex) else {
print("Please comform to CustomCollectionViewDelegateLayout protocol")
return
}
// Build the UICollectionVieLayoutAttributes for the cell.
var xPos = CGFloat(0)
let yPos = CGFloat(section) * CELL_HEIGHT
if let prevCellAttributes = prevCellAttributes {
xPos = CGRectGetMaxX(prevCellAttributes.frame)
}
let cellAttributes = UICollectionViewLayoutAttributes(forCellWithIndexPath: cellIndex)
cellAttributes.frame = CGRect(x: xPos, y: yPos, width: width, height: CELL_HEIGHT)
// Determine zIndex based on cell type.
if section == 0 && item == 0 {
cellAttributes.zIndex = 4
} else if section == 0 {
cellAttributes.zIndex = 3
} else if item == 0 {
cellAttributes.zIndex = 2
} else {
cellAttributes.zIndex = 1
}
// Save the attributes.
cellAttrsDictionary[cellIndex] = cellAttributes
prevCellAttributes = cellAttributes
let maxX = CGRectGetMaxX(cellAttributes.frame)
if maxWidthInASection < maxX {
maxWidthInASection = maxX
}
}
}
}
}
// Update content size.
let contentWidth = maxWidthInASection
let contentHeight = Double(collectionView!.numberOfSections())
self.contentSize = CGSize(width: Double(contentWidth), height: contentHeight)
self.contentSize.height = CGFloat(Double(collectionView!.numberOfSections()))
}
override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
// Create an array to hold all elements found in our current view.
var attributesInRect = [UICollectionViewLayoutAttributes]()
// Check each element to see if it should be returned.
for cellAttributes in cellAttrsDictionary.values.elements {
if CGRectIntersectsRect(rect, cellAttributes.frame) {
attributesInRect.append(cellAttributes)
}
}
// Return list of elements.
return attributesInRect
}
override func layoutAttributesForItemAtIndexPath(indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes? {
return cellAttrsDictionary[indexPath]!
}
override func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool {
return true
}
}
I try change collecionview properties in storyboard but doesnt works also i attached current collectionview object properties picture under below
Also i selected zoom 4 but zoom feature doesnt work ? why ? it must be work also zoom feature.
I know this is too late to answer, but this could be useful to other users.
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
collectionView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 50, right: 0)
}
This what worked for me:
messagesCollectionView.contentInset.top = 100
messagesCollectionView.contentInset.bottom = 80
This can be also done on IB under section insets...

Resources