This is my UICollectionView code:
extension UserFeed: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
resizeCollectionView()
return feeds.count
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
userFeedDelegate?.didSelectFeed(feeds[indexPath.row])
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: UserFeedCollectionViewCell.kCellIdentifier, for: indexPath) as! UserFeedCollectionViewCell
print(indexPath.row)
cell.setup(feeds[indexPath.row])
return cell
}
}
An here is the setup for my collection view
feedLayout.sectionInset = UIEdgeInsets.zero
feedLayout.itemSize = CGSize(width: size, height: size)
feedLayout.scrollDirection = .vertical
feedLayout.minimumInteritemSpacing = 0
feedLayout.minimumLineSpacing = 0
In this instance the feeds.count is 2 and 2 cells being created by the amount of indexPath.row being printed: 0,1
However in the output 4 cells are being displayed with the last to be uninstantiated versions of the custom UICollectionView Cell type. If it helps I only saw this extra cells after adding scrolling to my view.
Thanks!
Edit:
My resize collection view function:
fileprivate func resizeCollectionView() {
let height:CGFloat = CGFloat(Int(ceil(Double(feeds.count)/2))) * size
frame = CGRect(x: 0, y: frame.origin.y, width: frame.width, height: height)
userFeedDelegate?.didChangedCollectionHeight()
}
Related
I am looking to put a header on my collection view's sections. I have a collectionview embedded inside a tablebview. Using the section headers of the tableview puts the header too far from the content. Putting the section header as part of the collection view; however, is putting that header on top of the collection view cell itself. I am looking for some space between the section header and the section detail.
func setup() {
let layout = UICollectionViewFlowLayout()
layout.itemSize = THUMB_SIZE
layout.minimumLineSpacing = 25
layout.sectionInset.right = layout.itemSize.width / 2
layout.scrollDirection = .horizontal
collectionView = UICollectionView(frame: self.bounds, collectionViewLayout: layout)
collectionView.backgroundColor = UIColor(named: "collectionView")
collectionView.delegate = self
collectionView.dataSource = self
collectionView.remembersLastFocusedIndexPath = true
collectionView.register(MainCVCell.self, forCellWithReuseIdentifier: "cvCell")
self.addSubview(collectionView)
self.collectionView.register(HeaderCVCell.self, forCellWithReuseIdentifier: "headerCell")
}
// MARK: - Collectionview Delegate & Datasource
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return topics.shows.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cvCell", for: indexPath) as! MainCVCell
cell.show = topics.shows[indexPath.row]
cell.selectedIndex = indexPath.row
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
delegate.selectedMedia(showID: topics.shows[indexPath.row])
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let footerView = collectionView.dequeueReusableCell(withReuseIdentifier: "headerCell", for: indexPath)
if kind == UICollectionView.elementKindSectionHeader {
let headerView = collectionView.dequeueReusableCell(withReuseIdentifier: "headerCell", for: indexPath) as! HeaderCVCell
headerView.headerText = topics.title
return headerView
} else {
return footerView
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSize(width: 172, height: 60)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
return .zero
}
Now for collection view header cell:
class HeaderCVCell: UICollectionViewCell {
var headerText:String! {
didSet {
setup()
}
}
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
private func setup() {
let headerLabel = UILabel()
headerLabel.text = headerText
headerLabel.textColor = .white
headerLabel.sizeToFit()
self.subviews.forEach {$0.removeFromSuperview()}
self.addSubview(headerLabel)
}
}
One thing I noted by putting a background color on the header cell itself, is that the height of the header cell is equaling the height of the collection view. There does not though seem to be anyway that I can adjust the height of the header view cell independently of the collection view cells. If I change layout.itemSize it changes the size for both the header and the content. If I use layout.headerReferenceSize, it does not change anything. I am also using the delegate method as you can see from the code. Per the documentation it appears that it won't look at the height when in a horizontal scrolling situation such as this is. I have also tried to set the frame of the header cell directly but this is ignored.
Net, my section header is crashing into my regular content in the collection view. I suspect this might be because the height of the header is the height of the collection view and thus it is being positioned as high as it can go. I cannot change the height nor find any other way to separate the header from the content.
I have a similar set up and in my Header file, I have the size set with:
override func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: frame.width / 2 + 60, height: frame.height)
}
And, if you want to create some spacing, you can use insets. Setting the top to a negative number should show some space after the header.
override func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
}
I am placing a horizontal scroll UICollectionViewController inside of another UICollectionViewController cell. I am doing this because I want to create an image slider like effect.
Code for horizontal scroll UICollectionViewController:
class BusinessPhotosViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout{
var photos = [String]()
let cellId = "photos"
override func viewDidLoad() {
super.viewDidLoad()
if let layout = collectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
layout.scrollDirection = .horizontal
layout.minimumLineSpacing = 0
layout.minimumInteritemSpacing = 0
}
collectionView?.backgroundColor = .red
collectionView?.showsVerticalScrollIndicator = false
collectionView?.showsHorizontalScrollIndicator = false
collectionView?.alwaysBounceVertical = false
collectionView?.isPagingEnabled = true
collectionView?.isScrollEnabled = true
collectionView?.register(BusinessPhotoCells.self, forCellWithReuseIdentifier: cellId)
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! BusinessPhotoCells
if photos.count != 0 {
let imageUrl = photos[indexPath.item]
let url = URL(string: imageUrl)
cell.logoImage.kf.setImage(with: url)
}
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.height-10, height: view.frame.height-10)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
}
override func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
}
In another class I add this horizontal scroll UICollectionViewController as such:
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
//ADDING SCROLL CELL HERE
if indexPath.section == 1 {
let scrollCell = collectionView.dequeueReusableCell(withReuseIdentifier: pictureCellId, for: indexPath)
scrollCell.backgroundColor = .blue
let bizVC = BusinessPhotosViewController(collectionViewLayout: UICollectionViewFlowLayout())
scrollCell.addSubview(bizVC.view)
bizVC.view.anchor(top: scrollCell.topAnchor, left: scrollCell.leftAnchor, bottom: scrollCell.bottomAnchor, right: nil, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: scrollCell.frame.width, height: scrollCell.frame.height)
return scrollCell
}
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: listCellId, for: indexPath) as! CouponCell
return cell
}
Edit: Adding numberOfItemsInSection per comments
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if section == 0 {
return 0
}
if section == 1 {
return 1
}
return coupons.count
}
I return 1 for this section because I only want 1 horizontal scroll cell...Below that horizontal scroll cell (in section 2) I then have a list of vertical scroll cells that work as expected.
This results in something like this where only 3 squares are loaded up not the 10 as expected:
EDIT: ADDING IMAGE OF WHAT MY VIEW LOOKS LIKE NOW
I am new to swift, I am working in UICollectionView I need to load Seven column in it how can do it, Also padding between each cell should be (top:1,bottom:1,left:1,right:1)
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: CGFloat(collectionView.frame.size.width / 10.2), height: CGFloat(100))
}
//UICollectionViewDatasource methods
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 31
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as UICollectionViewCell
cell.backgroundColor = self.randomColor()
return cell
}
Works for both horizontal and vertical scroll directions and variable spacing
Specify number of columns
let numberOfColumns: CGFloat = 7
Configure flowLayout to render specified numberOfColumns
if let flowLayout = collectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
let horizontalSpacing = flowLayout.scrollDirection == .vertical ? flowLayout.minimumInteritemSpacing : flowLayout.minimumLineSpacing
let cellWidth = (view.frame.width - max(0, numberOfColumns - 1)*horizontalSpacing)/numberOfColumns
flowLayout.itemSize = CGSize(width: cellWidth, height: cellWidth)
}
I have a simple UICollectionViewController that returns X amount of cells. I want to have it so when a cell is selected, that specific selected cell will change it's size and become larger in height as all of the other cells stay the same. How do I achieve this? Here's my code:
class HomeController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
let cellId = "cellId"
override func viewDidLoad() {
super.viewDidLoad()
collectionView?.backgroundColor = UIColor(white: 0.90, alpha: 1.0)
collectionView?.register(PostCell.self, forCellWithReuseIdentifier: cellId)
collectionView?.showsVerticalScrollIndicator = false
collectionView?.alwaysBounceVertical = true
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 4
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! PostCell
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let height = (view.frame.width) * 9 / 16
return CGSize(width: view.frame.width, height: height + 50 + 50)
}
}
You can check to see if the indexPath from sizeForItemAt is selected. If it is, you return a different height otherwise return the standard height.
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
collectionView.performBatchUpdates(nil, completion: nil)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
switch collectionView.indexPathsForSelectedItems?.first {
case .some(indexPath):
return CGSize() // your selected height
default:
let height = (view.frame.width) * 9 / 16
return CGSize(width: view.frame.width, height: height + 50 + 50)
}
}
I'm trying to create a demo app that has a TabBarViewController as well as 4 tabs ( 4 Different ViewControllers on the storyboard)
On the first Tab which is the first ViewController, I have a collectionView
with Cells that have ImageView and few Labels.
What I'm trying to do is, when you click on a Cell, It expands to the whole screen, and the view still stays in the first Tab from the Tab Bar,
just now that the view inside the ViewController has changed to a new view that is an expanded view of the Cell that was selected, and when you scroll down the collection view continues, and you can click another cell and it expands and so on...while you can at any time press back and it shows the last cell that was expanded in the view
I hope I was clear enough about what I'm trying to do. now ill add the code of what I've got already
import UIKit
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
var imagesArray = []
var imageSizes = [CGSize]()
var labelsArray = [""]
var descArray = [""]
#IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView.delegate = self
self.collectionView.dataSource = self
for i in 0..<imagesArray.count {
let currImg = imagesArray[i]
let currHeight = currImg.size.height
let currSize = CGSize(width: 150, height: currHeight + 125)
imageSizes.append(currSize)
}
}
public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imagesArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CollectionVCe
cell.cellImg.image = imagesArray[indexPath.row]
cell.descLabel.text = descArray[1]
cell.itemLabel.text = labelsArray[0]
cell.cellImg.contentMode = .scaleAspectFill
cell.layer.cornerRadius = 9
cell.backgroundColor = UIColor.red
cell.cellImg.backgroundColor = UIColor.blue
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return imageSizes[indexPath.row]
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsetsMake(0, 25, 0, 25)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 10
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if let cell = collectionView.cellForItem(at: indexPath) {
cell.frame = collectionView.frame
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
You have reload the collection view and also call size delegate of collection view