I have a vertical scrolling Collection view and I want to make the centered cell bigger when scrolling happens.
I'm using InfiniteLayout for infinite scrolling on my collection view.
here is my custom flow layout:
import Foundation
import InfiniteLayout
class CustomLayout: InfiniteLayout {
public override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let attributes = super.layoutAttributesForElements(in: rect).flatMap {
self.copyLayoutAttributes(from: $0)
}
guard let visibleRect = self.visibleCollectionViewRect() else {
return attributes
}
let centeredOffset = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
for attributes in attributes ?? [] {
let diff = self.scrollDirection == .horizontal ? centeredOffset.x - attributes.center.x : centeredOffset.y - attributes.center.y
let distance = abs(diff)
let tolerance : CGFloat = 0.02
var scale = 1.00 + tolerance - (( distance / centeredOffset.y ) * 0.105)
if(scale > 1.0){
scale = 1.0
}
if(scale < 0.460091){
scale = 0.460091
}
attributes.transform = attributes.transform.scaledBy(x: scale, y: scale)
attributes.alpha = changeSizeScaleToAlphaScale(scale)
}
return attributes
}
func changeSizeScaleToAlphaScale(_ x : CGFloat) -> CGFloat {
let minScale : CGFloat = 0.46
let maxScale : CGFloat = 1.0
let minAlpha : CGFloat = 0.25
let maxAlpha : CGFloat = 1.0
return ((maxAlpha - minAlpha) * (x - minScale)) / (maxScale - minScale) + minAlpha
}
}
but it doesn't work...
here is my delegate and data source:
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return fakeData.count
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = infinteCollectionView.dequeueReusableCell(withReuseIdentifier: "myCell", for: indexPath) as! MyCollectionViewCell
cell.setText(text: fakeData[infinteCollectionView.indexPath(from: indexPath).row])
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 200, height: 55)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return collectionView.frame.height
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 10
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 0, left: 0, bottom: 10, right: 0)
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
self.infinteCollectionView.scrollToNearestVisibleCollectionViewCell()
}
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if !decelerate {
self.infinteCollectionView.scrollToNearestVisibleCollectionViewCell()
}
}
here is my extension for scroll to visible cell:
extension InfiniteCollectionView {
func scrollToNearestVisibleCollectionViewCell() {
self.decelerationRate = UIScrollView.DecelerationRate.normal
let visibleCenterPositionOfScrollView = Float(self.contentOffset.y + (self.bounds.size.height / 2))
var closestCellIndex = -1
var closestDistance: Float = .greatestFiniteMagnitude
for i in 0..<self.visibleCells.count {
let cell = self.visibleCells[i]
let cellHeight = cell.bounds.size.width
let cellCenter = Float(cell.frame.origin.y + cellHeight / 2)
// Now calculate closest cell
let distance: Float = fabsf(visibleCenterPositionOfScrollView - cellCenter)
if distance < closestDistance {
closestDistance = distance
closestCellIndex = self.indexPath(for: cell)!.row
}
}
if closestCellIndex != -1 {
self.scrollToItem(at: IndexPath(row: closestCellIndex, section: 0), at: .centeredVertically, animated: true)
}
}
}
Basicly I want to approach this:
Here is how I did it not sure if it's the best way to do it
Make a var to track the index in the middle of collection view
var index = IndexPath()
in the viewDidLayoutSubviews check for the cell in the middle once it's calculated invalidate the already configured layout
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let center = self.view.convert(collectionView.center, to: collectionView)
index = collectionView.indexPathForItem(at: center) ?? IndexPath(item: 0, section: 0)
collectionView.collectionViewLayout.invalidateLayout()
}
then in sizeforitem
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if index.count != 0 {
if index.item == indexPath.item {
return CGSize(width: collectionView.frame.size.width, height: 100)
}
}
return CGSize(width: collectionView.frame.size.width, height: 50)
}
then in scrollviewdidscroll call viewDidLayoutSubviews again so the centered element gets recalculated and item size gets changed
func scrollViewDidScroll(_ scrollView: UIScrollView) {
viewDidLayoutSubviews()
}
Related
I have taken collectionview in storyboard and in its cell i have taken ImageView and its below one label
i need to show only three rounded images horzontally and number of rows from JSON vertically in all screen sizes
like below image i need:
in cell for imageview costraints like below
leading = trailing = top = bottom = 5
and in coding:
class FriendsViewController: UIViewController {
// MARK: - IBOutlets
#IBOutlet weak var galleryCollectionView: UICollectionView!
// MARK: - LifeCycleMethods
override func viewDidLoad() {
super.viewDidLoad()
let layout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5)
layout.scrollDirection = .vertical
let width = UIScreen.main.bounds.width/4
let height = width*1.1
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 5
layout.itemSize = CGSize(width: width, height: height)
self.galleryCollectionView.collectionViewLayout = layout
}
}
class FriendsCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var imgView: UIImageViewX!
#IBOutlet weak var lblTitle: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
imgView.layer.cornerRadius = imgView.frame.height/2.0 }
}
so i am getting weird o/p in different screen sizes why?
o/p of ipodtouch7
In your collectionview cell Set constraints as shown in attached image, i.e. ur image view width should depend on imageview height, you can do it using ratio.
Then in willDisplay method calculate cornerRadius
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath)
{
guard let cell = cell as? TestCollectionViewCell else
{
return
}
let cellHeight : CGFloat = cell.frame.size.height
let labelHeight : CGFloat = cell.label?.frame.size.height ?? 0.0
cell.imageView?.layer.cornerRadius = (cellHeight - labelHeight) / 2.0
}
Below is the entire code
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout
{
#IBOutlet weak var collectionView : UICollectionView? = nil
let horizontalSpaceBetweenCell : CGFloat = 16
let verticalSpaceBetweenCell : CGFloat = 16
let edgeInsets = UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16)
override func viewDidLoad()
{
super.viewDidLoad()
setup()
}
func setup()
{
let nib = UINib(nibName: "TestCollectionViewCell", bundle: nil)
collectionView?.register(nib, forCellWithReuseIdentifier: "TestCollectionViewCell")
}
func numberOfSections(in collectionView: UICollectionView) -> Int
{
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return 40
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TestCollectionViewCell", for: indexPath) as? TestCollectionViewCell
{
return cell
}
return UICollectionViewCell()
}
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath)
{
guard let cell = cell as? TestCollectionViewCell else
{
return
}
let cellHeight : CGFloat = cell.frame.size.height
let labelHeight : CGFloat = cell.label?.frame.size.height ?? 0.0
cell.imageView?.layer.cornerRadius = (cellHeight - labelHeight) / 2.0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
{
let numberOfCellsPerRow = 3
let otherSpace = (edgeInsets.left + edgeInsets.right)
let width = (collectionView.frame.size.width - otherSpace) / CGFloat(numberOfCellsPerRow)
return CGSize(width: width, height: 80) // Height can be anything 80, 90 ,100
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 16
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return edgeInsets
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
{
}
}
Please change Widhth to height :
imgView.layer.cornerRadius = imgView.frame.size.height/2.0
I am trying to implement the Tags Layout using UICollectionView.
It works fine but only at some places the word is not displayed properly (Cropped) (mostly at the end of the UICollectioView frame). I have attached the screenshot as well.
I followed this Setup a collectionView with "tag"-like cells and tried to implement the same but it didn't work for me.
class UserProfileTagsFlowLayout: UICollectionViewFlowLayout {
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
guard let attributesForElementsInRect = super.layoutAttributesForElements(in: rect) else { return nil }
guard var newAttributesForElementsInRect = NSArray(array: attributesForElementsInRect, copyItems: true) as? [UICollectionViewLayoutAttributes] else { return nil }
var leftMargin: CGFloat = 0.0;
for attributes in attributesForElementsInRect {
if (attributes.frame.origin.x == self.sectionInset.left) {
leftMargin = self.sectionInset.left
}
else {
var newLeftAlignedFrame = attributes.frame
newLeftAlignedFrame.origin.x = leftMargin
attributes.frame = newLeftAlignedFrame
}
leftMargin += attributes.frame.size.width + 8 // Makes the space between cells
newAttributesForElementsInRect.append(attributes)
}
return newAttributesForElementsInRect
}
}
I am using the below array to populate the data :
data = ["Kishor", "iOS", "Developer", "Software Engineer", "ABCD", "Coding", "Xcode", "I am an iOS Developer","JKLMNO" , "Testing Coding", "Development", "XYZ-XYZ-XYZCD", "Enable the Tag Layout", "Layouts Arrangement"]
But if you see in the screenshot, last word of the first line "ABCD", 'D' is cropped and also few of the words are cropped at the end of the frame.
Below is my UICollectionView (Inside the UITableViewCell)
class TagListCell: UITableViewCell {
#IBOutlet weak var tagListCollection: UICollectionView!
var data: [String] = []
override func awakeFromNib() {
super.awakeFromNib()
}
fileprivate func setCollectioView() {
self.setupCollectionnViewLayout()
self.tagListCollection.register(UINib(nibName: "TagListNameCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "TagListNameCollectionViewCell")
tagListCollection.delegate = self
tagListCollection.dataSource = self
}
private func setupCollectionnViewLayout() {
let layout = UserProfileTagsFlowLayout()
//layout.estimatedItemSize = CGSize.init(width: 50, height: 50)
layout.scrollDirection = .vertical
tagListCollection.collectionViewLayout = layout
}
// MARK: UIView functions
override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize {
self.tagListCollection.layoutIfNeeded()
let size = tagListCollection.collectionViewLayout.collectionViewContentSize
let newSize = CGSize(width: size.width, height: size.height + 1)
debugPrint("New Size : \(newSize)")
return newSize
}
func setData(data: [String]) {
self.setCollectioView()
self.data = data
}
}
//MARK:- UICollectionView Delegate and DataSource
extension TagListCell: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return data.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TagListNameCollectionViewCell", for: indexPath) as? TagListNameCollectionViewCell {
cell.titleLable.text = data[indexPath.row]
return cell
}
else {
return UICollectionViewCell()
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let tag = data[indexPath.row]
let font = UIFont.systemFont(ofSize: 17)//UIFont(name: "Label Test Data", size: 16)!
let size = tag.size(withAttributes: [NSAttributedString.Key.font: font])
let dynamicCellWidth = size.width
return CGSize(width: dynamicCellWidth, height: 50)
}
// Space between rows
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 5
}
// Space between cells
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 5
}
}
I can't figure out how I can adjust the cell sizes without "breaking" rows count.
I have a collectionView with images from a service request that are showed in lines with 3 elements.
What I need is that when a Have just one or two images from the request, the images shows aligned to the left, but the screen shows the images centered.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if imageFuelArray.count == 1{
let padding: CGFloat = 10
let collectionViewWidth = collectionView.frame.size.width - padding
let collectionViewHeight = collectionView.frame.size.height - padding
return CGSize(width: collectionViewWidth, height: collectionViewHeight)
} else{
let padding: CGFloat = 10
let collectionViewWidth = collectionView.frame.size.width - padding
let collectionViewHeight = collectionView.frame.size.height - padding
return CGSize(width: collectionViewWidth/2, height: collectionViewHeight/2)
}
}
I have this function
func getSizeVews(){
if imageFuelArray.count > 6{
self.collectionView.heightAnchor.constraint(equalToConstant: self.collectionView.contentSize.height+45).isActive = true
self.servicesTableView.heightAnchor.constraint(equalToConstant: self.servicesTableView.contentSize.height+70).isActive = true
view.layoutSubviews()
} else {
self.collectionView.heightAnchor.constraint(equalToConstant: self.collectionView.contentSize.height).isActive = true
self.servicesTableView.heightAnchor.constraint(equalToConstant: self.servicesTableView.contentSize.height+70).isActive = true
view.layoutSubviews()
}
}
And there I have my collectionView datasource and delegate
extension ServicesStationViewController: UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
imageFuelArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: flCollectionVieCell, for: indexPath) as! FuelCollectionViewCell
let fuel = imageFuelArray[indexPath.row]
if let cepsaFuel = CepsaFeaturesFuel(key: Int(fuel) ?? 0) {
let imgName = CepsaFeaturesFuel.featureFuelImageName(with: cepsaFuel.featuresFuelType)
cell.fuelImageView?.image = UIImage(named: imgName!)
}
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if imageFuelArray.count == 1{
let padding: CGFloat = 10
let collectionViewWidth = collectionView.frame.size.width - padding
let collectionViewHeight = collectionView.frame.size.height - padding
return CGSize(width: collectionViewWidth, height: collectionViewHeight)
} else{
let padding: CGFloat = 10
let collectionViewWidth = collectionView.frame.size.width - padding
let collectionViewHeight = collectionView.frame.size.height - padding
return CGSize(width: collectionViewWidth/2, height: collectionViewHeight/2)
}
}
}
Hey i want to create stack of UIImageView like the photo, how to do this
It must be dynamic. How can I move the cells so that they are one below the other?
Use UICollectionViewDelegateFlowLayout methods to make this kind of UI.
Example:
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
#IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 3
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
cell.layer.borderWidth = 2.0
cell.layer.borderColor = UIColor.white.cgColor
cell.layer.cornerRadius = 50.0
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.bounds.height, height: collectionView.bounds.height)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return -50
}
}
In the above code
Configure minimumLineSpacingForSectionAt and minimumInteritemSpacingForSectionAt methods of UICollectionViewDelegateFlowLayout.
Since the cell in collectionView are aligned left to right default, so to get the desired result we need to align them right to left.
As shown in above screenshot, use semantic property of collectionView for right to left alignment of cells.
Screenshot:
Edit-1:
One way to centre the cells in collectionView is to play with collectionView's width and centre it horizontally.
CollectionView constraints - top, width, centeredorizontally
In viewDidAppear, manually calculate the width of collectionView according to the numberOfItems. In your case numberOfItems = 3
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let width = min((collectionView.bounds.height) * CGFloat((numberOfItems-1)/2 + 1), UIScreen.main.bounds.width)
self.collectionViewWidthConstraint.constant = width
}
You can use UICollectionView Custom Layout .
Collection view layouts are subclasses of the abstract UICollectionViewLayout class. They define the visual attributes of every item in your collection view. The individual attributes are instances of UICollectionViewLayoutAttributes and contain the properties of each item in your collection view, such as the item’s frame or transform.
The similar Tutorial
This is a more complex layout , Change some parameters , you will get what you want.
Copyed from github , mpospese/IntroducingCollectionViews
translate some to Swift
class SpiralLayout: UICollectionViewLayout{
let itemSize: CGFloat = 170
var pageSize: CGSize!
var contentSize: CGSize!
var radius: CGFloat!
var cellCounts: [Int]!
var pageRects: [CGRect]!
var pageCount: Int!
override func prepare() {
super.prepare()
pageSize = collectionView?.bounds.size
let iPad = UIDevice.current.userInterfaceIdiom == UIUserInterfaceIdiom.pad
let scaleFactor: CGFloat = iPad ? 1 : 0.5
let side = itemSize * scaleFactor
radius = min(pageSize.width - side, pageSize.height - side * 1.2 )/2 - 5
pageCount = collectionView?.numberOfSections
var counts = [Int]()
var rects = [CGRect]()
for section in 0..<pageCount{
counts.append((collectionView?.numberOfItems(inSection: section))!)
rects.append(CGRect(origin: CGPoint(x: CGFloat(section) * pageSize.width, y: 0), size: pageSize))
}
cellCounts = counts
pageRects = rects
contentSize = CGSize(width: pageSize.width * CGFloat(pageCount), height: pageSize.height)
}
override var collectionViewContentSize: CGSize{
return contentSize
}
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
return !pageSize.equalTo(newBounds.size)
}
func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
var attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
attributes.size = CGSize(width: itemSize, height: itemSize)
// ...
return attributes
}
}
I have a collectionView with horizontal scroll direction and paging enabled, now I want to make it scroll as smoothly as the games section on the AppStore.
To be more specific this is how I want the first cell to be:
EDIT
I actually achieved both of the next images one with the smaller width
of the cell and the next with the .centeredHorizontally in selectItem,
my problem is the non smoothly scrolling.
As you can see a little of the second cell is appearing.
And here is the next cells:
As you can see now the previous and the next cell are appearing.
I managed to do this by setting this part of code but with bouncing no smoothly as AppStore.
This is the code I used:
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
var visibleRect = CGRect()
visibleRect.origin = collectionView.contentOffset
visibleRect.size = collectionView.bounds.size
let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
let visibleIndexPath: IndexPath = collectionView.indexPathForItem(at: visiblePoint) ?? IndexPath()
let indexPath = IndexPath(item: visibleIndexPath[1], section: 0)
collectionView.selectItem(at: indexPath, animated: true, scrollPosition: .centeredHorizontally )
}
And this is my collectionView code:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let frameSize = collectionView.frame.size
return CGSize(width: frameSize.width - 30, height: frameSize.height - 40)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 0, left: 0, bottom: 20, right: 0)
}
Example project here
In class property
var itemSize = CGSize(width: 0, height: 0)
#IBOutlet weak var collectionViewHeight: NSLayoutConstraint!
#IBOutlet weak var collectionView: UICollectionView!
fileprivate let sectionInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
In viewDidLoad or awakeFormNib(If in collectionViewCell or tableViewCell)
if let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
layout.minimumLineSpacing = 0
layout.minimumInteritemSpacing = 0
}
collectionView.contentInset = UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 8)
collectionView.isPagingEnabled = false
layoutIfNeeded()
let width = collectionView.bounds.size.width-24
let height = width * (3/4)
itemSize = CGSize(width: width, height: height)
layoutIfNeeded()
Implement UICollectionViewDelegateFlowLayout
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
insetForSectionAt section: Int) -> UIEdgeInsets {
return sectionInsets
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
return itemSize
}
Implement ScrollViewDelegate
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
let pageWidth = itemSize.width
targetContentOffset.pointee = scrollView.contentOffset
var factor: CGFloat = 0.5
if velocity.x < 0 {
factor = -factor
print("right")
} else {
print("left")
}
let a:CGFloat = scrollView.contentOffset.x/pageWidth
var index = Int( round(a+factor) )
if index < 0 {
index = 0
}
if index > collectionViewDataList.count-1 {
index = collectionViewDataList.count-1
}
let indexPath = IndexPath(row: index, section: 0)
collectionView?.scrollToItem(at: indexPath, at: .left, animated: true)
}
See example screenshot from my project at Past rides section
I have implemented uicollectionview in collectionViewCell
Set collectionView?.isPagingEnabled = true and remove your scrollViewDidEndDecelerating method