Aligning CollectionView Cells to Left with equal spacing in between (Cells will be of dynamic width depending on the data received i.e the length of the string that will go in the cell).
My Custom View is TrendingView.swift
//
// TrendingView.swift
//
// Created by Abhishek Chandrakant Gidde on 24/05/23.
//
import UIKit
protocol TrendingViewDelegate: AnyObject {
func didSelectScrip(scrip:ScripModel)
func seeAllScrips()
func seeAllBreakouts()
}
enum DataType {
case EQUITY
case DERIVATIVES
func isEquityData() -> Bool {
switch self {
case .EQUITY:
return true
case .DERIVATIVES:
return false
}
}
}
class TrendingView: UIView {
@IBOutlet var contentViewRoot: UIView!
@IBOutlet weak var lblTrendingTitle: UILabel!
@IBOutlet weak var clvTrendingData: UICollectionView!
var isTrending = true
var dataType: DataType?
var arrayTrendingData = [MarketScripModel]() {
didSet{
self.updateCollectionViewUI()
}
}
var arrayBreakoutData = [SignalListModel]() {
didSet{
self.updateCollectionViewUI()
}
}
// MARK: Properties
weak var delegate:TrendingViewDelegate?
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
customInit()
}
override init(frame: CGRect) {
super.init(frame: frame)
customInit()
}
override func awakeFromNib() {
super.awakeFromNib()
customInit()
}
func customInit(){
Bundle.main.loadNibNamed("TrendingView",owner: self, options: nil)
addSubview(self.contentViewRoot)
self.contentViewRoot.frame = self.bounds
self.contentViewRoot.autoresizingMask = [.flexibleWidth,.flexibleHeight]
clvTrendingData.dataSource = self
clvTrendingData.delegate = self
clvTrendingData.register(UINib(nibName: "TrendingViewCell", bundle: .main),forCellWithReuseIdentifier: "trendingViewCell")
clvTrendingData.collectionViewLayout = CustomCollectionViewFlowLayout()
}
func updateCollectionViewUI() {
DispatchQueue.main.async {
if self.isTrending {
if self.dataType == .EQUITY {
self.lblTrendingTitle.text = "Trending Stocks"
} else if self.dataType == .DERIVATIVES {
self.lblTrendingTitle.text = "Trending Strikes"
}
} else {
if self.dataType == .EQUITY {
self.lblTrendingTitle.text = "Breakout Stocks"
} else if self.dataType == .DERIVATIVES {
self.lblTrendingTitle.text = "Breakout Futures"
}
}
//
self.clvTrendingData.reloadData()
}
}
// MARK: Actions
@IBAction func onSellAllTap(_ sender: Any) {
if(isTrending){
self.delegate?.seeAllScrips()
}
else{
self.delegate?.seeAllBreakouts()
}
}
}
// CollectionView FlowLayout
extension TrendingView:UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
}
}
extension TrendingView: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if self.isTrending {
return self.arrayTrendingData.count
} else {
return self.arrayBreakoutData.count
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let trendingViewCell: TrendingViewCell = clvTrendingData.dequeueReusableCell(withReuseIdentifier: "trendingViewCell", for: indexPath) as! TrendingViewCell
if(isTrending) {
print("Returning Trending Data Cell")
trendingViewCell.configureCell(scripModel: arrayTrendingData[indexPath.row],isEquityData: dataType!.isEquityData() )
} else {
print("Returning Derivative Data Cell")
trendingViewCell.configureCell(scripModel: arrayBreakoutData[indexPath.row],isEquityData: dataType!.isEquityData())
}
trendingViewCell.layoutIfNeeded()
return trendingViewCell
}
}
extension TrendingView: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if(isTrending){
self.delegate?.didSelectScrip(scrip: arrayTrendingData[indexPath.row].scrip)}
else{
self.delegate?.didSelectScrip(scrip: arrayBreakoutData[indexPath.row].scrip)
}
}
}
My Trending View Cell is TrendingViewCell.swift
//
// TrendingViewCell.swift
//
// Created by Abhishek Chandrakant Gidde on 24/05/23.
//
import UIKit
enum CallType: String {
case BUY = "buy"
case SELL = "sell"
}
class TrendingViewCell: UICollectionViewCell {
@IBOutlet weak var lblScripTitle: UILabel!
@IBOutlet weak var ivTrendingIcon: UIImageView!
private var isStockPositive: Bool?{
didSet{
updateUI()
}
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
func configureCell(scripModel: MarketScripModel, isEquityData:Bool){
if(!isEquityData){
let nameOfScrip = scripModel.marketScripModel.Name
let components = nameOfScrip?.components(separatedBy: "|")
// Extracting the underlying asset (e.g., "NIFTY")
let underlyingAsset = components?[0].trimmingCharacters(in: .whitespaces)
// Extracting the expiration date (e.g., "25MAY23")
let expirationDate = components?[1].trimmingCharacters(in: .whitespaces)
let strikePrice = scripModel.marketScripModel.LTP
let trendingStrikeText = "\(underlyingAsset!) \(strikePrice!) \(expirationDate!)"
print("debugabhi:")
print(underlyingAsset!)
print(expirationDate!)
print(strikePrice!)
print(trendingStrikeText)
self.lblScripTitle.text=trendingStrikeText
// lblScripTitle.text = "NIFTY 18,400 25MAY2023"
}
else{
lblScripTitle.text = scripModel.scrip.scripNameWithExpiry()}
if let ltpChange = scripModel.marketScripModel.PerChange {
isStockPositive = ltpChange >= 0
}
}
func configureCell(scripModel: SignalListModel, isEquityData:Bool){
if(!isEquityData){
let nameOfScrip = scripModel.scrip.scripNameWithExpiry()
self.lblScripTitle.text = nameOfScrip
if scripModel.callType.removingWhitespaces().lowercased() == CallType.BUY.rawValue {
isStockPositive = true
}
else {
isStockPositive = false
}
}
else{
lblScripTitle.text = scripModel.scrip.scripNameWithExpiry()
if scripModel.scrip.changePer() >= 0{
isStockPositive = true
}
else{
isStockPositive = false
}
}
}
func updateUI(){
self.ivTrendingIcon.image = isStockPositive! ? UIImage(named: "icn_stockPositive") : UIImage(named: "icn_stockNegative")
}
}
I have tried my best to do everything I can but it is too frustrating to get it the way it is needed, I have also tried using a custom class as suggested by ChatGPT like class WrapFlowLayout: UICollectionViewFlowLayout {... and setting collectionView.collectionViewLayout = WrapflowLayout() but that leaves me with the cells aligning to the left and wrapping just as i need but then the cell width is not as per my constrains or my data it looks like this. 


Use this layout class for tags layout
after that give estimated size to cell