Reputation: 2169
I build ViewController with UiCollectionView, and I created my custom View to display in every cell. This is the code on my controller to display, resize the cell. I need to have 3 cell for every row in UiCollectionView
class HomeViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource , UICollectionViewDelegateFlowLayout{
@IBOutlet weak var collectionView: UICollectionView!
var listaCategorie = [CategoryModel]()
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.listaCategorie.count
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let noOfCellsInRow = 3
let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
let totalSpace = flowLayout.sectionInset.left
+ flowLayout.sectionInset.right
+ 30
+ (flowLayout.minimumInteritemSpacing * CGFloat(noOfCellsInRow - 1))
let size = Int((collectionView.bounds.width - totalSpace) / CGFloat(noOfCellsInRow))
return CGSize(width: 100, height: 130)
}
// UICollectionViewDelegateFlowLayout method
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout,
insetForSectionAtIndex section: Int) -> UIEdgeInsets {
let cellWidthPadding = collectionView.frame.size.width / 30
let cellHeightPadding = collectionView.frame.size.height / 4
return UIEdgeInsets(top: cellHeightPadding,left: cellWidthPadding, bottom: cellHeightPadding,right: cellWidthPadding)
}
public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
var category = self.listaCategorie[indexPath.row];
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cella", for: indexPath) as! CustomCellViewsCategories
var puntoLuce = self.listaCategorie[indexPath.row];
cell.labelCategoryName.text = puntoLuce.description
//cell.image.image = UIImage(named: "light-bulb-2.png");
cell.backgroundColor = getUIColorFromRGBThreeIntegers(red: 63,green: 162,blue: 217);
cell.layer.cornerRadius = 6
cell.layer.masksToBounds = false;
cell.layer.shadowColor = UIColor.black.cgColor
cell.layer.shadowOffset = CGSize(width: 0, height: 0)
cell.layer.shadowOpacity = 0.5
//RECUPERO LA DIMENSIONE
let noOfCellsInRow = 4
//FINE RECUPERO DIMENSIONE
if(puntoLuce.imageUrl != ""){
let imageUrl:NSURL = NSURL(string: puntoLuce.imageUrl!)!
DispatchQueue.global(qos: .userInitiated).async {
let imageData:NSData = NSData(contentsOf: imageUrl as URL)!
DispatchQueue.main.async {
let image = UIImage(data: imageData as Data)
cell.imageCategory.image = image
}
}
}
return cell
}
func getUIColorFromRGBThreeIntegers(red: Int, green: Int, blue: Int) -> UIColor {
return UIColor(red: CGFloat(Float(red) / 255.0),
green: CGFloat(Float(green) / 255.0),
blue: CGFloat(Float(blue) / 255.0),
alpha: CGFloat(1.0))
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.title = "ARRIVA ARRIVA"
//on click su label temp
let tap = UITapGestureRecognizer(target: self, action: #selector(HomeViewController.tapFunction))
getCategoryList()
collectionView.delegate = self // Unless you have already defined the delegate in IB
collectionView.dataSource = self // Unless you have already defined the dataSource in IB
self.collectionView.frame = self.collectionView.frame.inset(by: UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0))
}
@objc func tapFunction() {
// handle label tap here
print("click");
}
func getCategoryList(){
var params = [
"" : ""
]
let postUrl = APIRequest(endPoint: "category_list")
postUrl.sendRequest(parameters: params as! [String : String]) {
responseObject, error in
let user = CategoryModel(id: "0",
description: "Tutti",
imageUrl: "")
self.listaCategorie.append(user)
guard let responseObject = responseObject, error == nil else {
print(error ?? "Unknown error")
return
}
do{
let messageData = try JSONDecoder().decode(ResponseCategoryModel.self, from: responseObject)
var array = messageData.result
for categoryModel in array {
let user = CategoryModel(id: "",
description: categoryModel.categoryName,
imageUrl: categoryModel.image)
self.listaCategorie.append(user)
}
print(array.count);
DispatchQueue.main.async { // Correct
self.collectionView.reloadData()
}
}catch{
print("errore durante la decodifica dei dati")
}
}
}
But this is the result:
As you can see from the photo there is too space from the 3 cells. There is a way to set minus space by cells?
EDIT
I try to use the code on first response. THis is the result
Upvotes: 0
Views: 1797
Reputation: 119272
UICollectionViewCompositionalLayout
will give you a layout that automatically adjusts to the collection view size. Remove all code you have relating to the flow layout and create a compositional layout in viewDidLoad
:
// Cell will be the full height of the enclosing group
let cellHeight = NSCollectionLayoutDimension.fractionalHeight(1)
// Cell will be 1/3 width of the enclosing group
let cellWidth = NSCollectionLayoutDimension.fractionalWidth(0.333)
// The size of the cell
let size = NSCollectionLayoutSize(widthDimension: cellWidth, heightDimension: cellHeight)
// This item represents a single cell
let item = NSCollectionLayoutItem(layoutSize: size)
// The cell will be inset by these distances within the item
item.contentInsets = NSDirectionalEdgeInsets(top: 10, leading: 10, bottom: 10, trailing: 10)
// The group will be a fixed height
let groupHeight = NSCollectionLayoutDimension.absolute(130)
// The group will occupy the full available width
let groupWidth = NSCollectionLayoutDimension.fractionalWidth(1)
// The group will repeat to hold as many of the cells as it can in a horizontal row before wrapping
let group = NSCollectionLayoutGroup.horizontal(layoutSize: NSCollectionLayoutSize(widthDimension: groupWidth, heightDimension: groupHeight), subitems: [item])
// The actual section, which consists of a single group
let section = NSCollectionLayoutSection(group: group)
// The insets of the group from the edge of the collection view
section.contentInsets = NSDirectionalEdgeInsets(top: 10, leading: 10, bottom: 10, trailing: 10)
// Create and assign the layout
let layout = UICollectionViewCompositionalLayout(section: section)
collectionView.collectionViewLayout = layout
I've tried to break it up into chunks so it makes sense, these layouts can take some time to wrap your head around.
It gives you the following portrait layout:
And in landscape:
If you want a fixed cell size, then use .absoluteWidth
for the cell width, and add an interItemSpacing
of .flexible
to the group.
Using UICollectionViewFlowLayout
you can achieve a very similar result with less code than you have in your question. With a plain project, the only collection view related code I had was this in viewDidLoad()
:
(collectionView.collectionViewLayout as? UICollectionViewFlowLayout)?.sectionInset = .init(top: 10, left: 10, bottom: 10, right: 10)
Then this single flow layout delegate method:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
var width = (collectionView.bounds.width - 20) / 3
width -= 10
return CGSize(width: width, height: 130)
}
This gives you three columns per row in portrait or landscape.
Upvotes: 3
Reputation: 629
Add the UICollectionViewDelegateFlowLayout
delegate and add these methods and update your values according to your requirement like:-
let edge : CGFloat = 10.0
let spacing : CGFloat = 10.0
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let noOfColumn = 3
let collectionviewWidth = collectionView.frame.width
let bothEdge = CGFloat(edge + edge) // left + right
let excludingEdge = collectionviewWidth - bothEdge
let cellWidthExcludingSpaces = excludingEdge - ((noOfColumn-1) * spacing)
let finalCellWidth = cellWidthExcludingSpaces / noOfColumn
let height = finalCellWidth
return CGSize(width: finalCellWidth, height: height)
}
Upvotes: 0