Unable to create TAGVIEW in swift? - ios

I am having a collection view. I want to create cells of collection view as TAGS. I Have written but it does not calculate the width & also left,irght margin among cells. Please tell me how can I improve it ?
extension StoreItemCell:UICollectionViewDelegate {
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
let width = CGSize(
return self.sizingCell!.systemLayoutSizeFitting(UILayoutFittingCompressedSize)
}
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
self.tagsCollectionView.delegate = self
self.tagsCollectionView.dataSource = self
let cellNib = UINib(nibName: Titles.CellIdentifier.TagCell, bundle: nil)
self.tagsCollectionView.register(cellNib, forCellWithReuseIdentifier: Titles.CellIdentifier.TagCell)
self.tagsCollectionView.backgroundColor = UIColor.clear
self.sizingCell = (cellNib.instantiate(withOwner: nil, options: nil) as NSArray).firstObject as! TagCell?
self.flowLayout.sectionInset = UIEdgeInsetsMake(8, 8, 8, 8)
self.flowLayout.minimumInteritemSpacing = 15
}
Please tell me how can I improve it. I have attached the screenshot for my design.

Add this one
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let Labell : UILabel = UILabel()
Labell.text = self.TagsArray[indexPath.item] as? String
let labelTextWidth = Labell.intrinsicContentSize.width
return CGSize(width: labelTextWidth + 10, height: 30)
}
create UILabel in
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
}

Your code should be in your parent class, not in cell class,
extension YourViewController:UICollectionViewDelegate {
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
return //YourCellSize here
}
}
You have to use that delegate method in your parent class. Not in Cell Class.

Related

Centering cells for paging UICollectionView

I have a UICollectionView setup like so:
In viewDidLoad:
func setupCollectionView() {
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(UINib(nibName: "NewQuizzesCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "NewQuizzesCollectionViewCell")
let flowLayout = UICollectionViewFlowLayout()
flowLayout.scrollDirection = .horizontal
flowLayout.minimumInteritemSpacing = 20
flowLayout.minimumLineSpacing = 20
collectionView.isPagingEnabled = true
collectionView.setCollectionViewLayout(flowLayout, animated: false)
}
And my delegates:
extension NewQuizzesViewController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 3
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell: NewQuizzesCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "NewQuizzesCollectionViewCell", for: indexPath) as! NewQuizzesCollectionViewCell
cell.backgroundColor = colors[indexPath.row]
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.frame.size.width*0.8, height: collectionView.frame.size.height*0.8)
}
}
When I run the app it looks like this:
My question is, how can I make the cells centered? I noticed I can adjust the spacing between the cells, but how would I add spacing to the left of the red cell? Any pointers on this would be really appreciated. Thanks!
Try this delegate function will help and you need to set width of cell according to you wants
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionat section: Int) -> CGFloat {
return 0
}
Hope it will help you
you try that code that may help you..
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
let offSet = self.collectionView.contentOffset
let width = self.collectionView.bounds.size.width
let index = round(offSet.x / width)
let newPoint = CGPoint(x: index * size.width, y: offSet.y)
coordinator.animate(alongsideTransition: { (UIViewControllerTransitionCoordinatorContext) in
},completion: {(UIVIewTransitionCoordinatorContext) in
self.collectionView.reloadData()
self.collectionView.setContentOffset(newPoint, animated: true)
})
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.frame.size.width, height: collectionView.frame.size.height)
}
for swift 3.0
minimumLineSpacingForSectionAt function use for set spacing between the cells of UICollectionView Layout..
and you need to add subclass of UICollectionViewDelegateFlowLayout so you can use the function minimumLineSpacingForSectionAt like this
class HomeBestSallingCatgCell: DatasourceCell ,UICollectionViewDelegate,UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
.......
......
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0 //set return 0 for no spacing you can check to change the return value
}
}
i hope it will useful for you

UICollectionView with multiple rows

I use UICollectionView (views with UIButtons) to book the time:
override func viewDidLoad() {
super.viewDidLoad()
collectionViewTime.register(UINib(nibName: "TimeCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "timecell")
collectionViewTime.dataSource = self
collectionViewTime.delegate = self
if let layout = collectionViewTime.collectionViewLayout as? UICollectionViewFlowLayout {
layout.scrollDirection = .vertical
}
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return Timeline.count
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
let numberOfItems = CGFloat(collectionView.numberOfItems(inSection: 0))
let combinedItemWidth = (numberOfItems * flowLayout.itemSize.width) + ((numberOfItems - 1) * flowLayout.minimumInteritemSpacing)
let padding = (collectionView.frame.width - combinedItemWidth) / 2
return UIEdgeInsets(top: 0, left: padding, bottom: 0, right: padding)
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "timecell", for: indexPath) as! TimeCollectionViewCell
let time = Timeline[indexPath.row][0]
cell.btnTime.setTitle(DateManager.dateToTime(date: time.0), for: .normal)
return cell
}
And I got all views (UIButtons) in one line:
How can I set automatically moving UIViews in new rows?
So, in my case (iPad) one row will contain 7 UIViews, iPhone will contain 4-5 UIViews in one row.
For that you need to implement UICollectionViewDelegateFlowLayout method collectionView(_:layout:sizeForItemAt:) and change the collectionView's Scroll direction to Vertical
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let minCellSpace: CGFloat = 10 //Set minimum cell space that you want
if UIDevice.current.userInterfaceIdiom == .pad {
//For iPad return 7 cell as you mention in question
return CGSize(width: (collectionView.frame.size.width / 7) - minCellSpace, height: yourCellHeight)
}
else {
//For iPhone return 4 cell, if you want to return 5 cell divide width to 5
return CGSize(width: (collectionView.frame.size.width / 4) - minCellSpace, height: yourCellHeight)
}
}
Please use one more flow delegate method as below
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize;
------
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width:(button width), height:button hieght);
}

cellForItemAt IndexPath does not call if I'm using UICollectionViewDelegateFlowLayout. Is it a bug of iOS?

cellForItemAt indexPath does not call if I'm using UICollectionViewDelegateFlowLayout.
In this case:
class Something: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
}
it calls my cellforItemAtIndexPath, but does not call my
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
}
but if I include UICollectionViewDelegateFlowLayout:
class Something: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
}
it will call:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
}
but will not call cellForItemAtIndexPath. I do not understand the problem. Is that a bug of iOS or I do not see anything?
For me, when creating the collectionView with layout, it should be let layout = UICollectionViewFlowLayout(), not let layout = UICollectionViewLayout() which is so easy to neglect. I was trapped in this like more than twice.
Try this code.
import UIKit
let kSCREENWIDTH = UIScreen.main.bounds.size.width
let kSCREENHEIGHT = UIScreen.main.bounds.size.height
let COLLECTION_CELL = "collectionCell"
class DemoController: UIViewController {
var collectionView : UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
setupCollectionView()
}
/// create programatically collection view
fileprivate func setupCollectionView() {
let layout = UICollectionViewFlowLayout()
// layout.itemSize = CGSize(width:(kSCREENWIDTH-20)/2,height:150)
layout.sectionInset = UIEdgeInsetsMake(5, 7, 5, 7)
layout.minimumLineSpacing = 5
layout.minimumInteritemSpacing = 1
collectionView = UICollectionView.init(frame: self.view.bounds, collectionViewLayout: layout)
collectionView.delegate = self
collectionView.dataSource = self
collectionView.backgroundColor = UIColor.white
self.view .addSubview(collectionView)
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: COLLECTION_CELL)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
//MARK: UICollectionViewDelegate
extension DemoController : UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// add your code here
}
}
//MARK: UICollectionViewDataSource
extension DemoController : UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
/// add your code here
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: COLLECTION_CELL, for: indexPath)
cell.backgroundColor = UIColor.lightGray
print("Here cellForItemAt Works")
return cell
}
}
//MARK: UICollectionViewDelegateFlowLayout
extension DemoController : UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
print("Here sizeForItemAt Works")
return CGSize(width: 150, height: 150)
}
}
In my case contentInset was not proper for the UICollectionView sub class.
Try adding below code in you sub class
override func layoutSubviews() {
super.layoutSubviews()
self.contentInset = UIEdgeInsetsMake(0, 0, 0, 0)
}
override func reloadData() {
DispatchQueue.main.async {
super.reloadData()
}
}
Hope this helps someone!
Returning a size of CGSize(width: 0, height: 0) caused the delegate cellForItemAt not to get called in my case.
For example:
This would result in the issue.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 0, height: 0)
}
Where as this would not.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 10, height: 10)
}

UICollectionView must be initialized with a non-nil layout parameter even after initialized in ViewDidLoad

I tried to do what all the other questions seem to do, but I still get the error. Maybe I'm missing something obvious but I looked over the documentation and all it seems is you need a layout to initialize.
let flowLayout = UICollectionViewFlowLayout()
flowLayout.scrollDirection = .vertical
collectionView = UICollectionView(frame: view.frame, collectionViewLayout: flowLayout)
collectionView?.delegate = self
collectionView?.dataSource = self
collectionView?.register(InterestCollectionViewCell.self, forCellWithReuseIdentifier: interestReuseIdentifier)
view.addSubview(collectionView!)
Collection View Delegate Method
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return interests.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let vc = collectionView.dequeueReusableCell(withReuseIdentifier: interestReuseIdentifier, for: indexPath) as! InterestCollectionViewCell
vc.interestLabel.text = interests[indexPath.row].rawValue as String
return vc
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.size.width, height: 45)
}
The solution was that I had to initialize the collectionView before presenting the UICollectionViewController. And I had to register my cell class in viewWillAppear as opposed to viewDidLoad.

Swift UICollectionView horizontal scroll not working

I have an issue with a UICollectionView that doesn't want to scroll horizontally. I want to show 5 cells that I can scroll between. What is preventing my collectionview from scrolling?
import UIKit
class FeaturedCell: UICollectionViewCell, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout
{
// Attributes
lazy var featuredVideos = UICollectionView(frame: .zero)
// Superclass initializer
required init?(coder aDecoder: NSCoder)
{
fatalError("init(coder:) has not been implemented")
}
// Custom initializer
required override init(frame: CGRect)
{
super.init(frame: frame)
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .Horizontal
featuredVideos = UICollectionView(frame: self.frame, collectionViewLayout: layout)
featuredVideos.dataSource = self
featuredVideos.delegate = self
// Setting the collection view's scrolling behaviour
featuredVideos.pagingEnabled = true
featuredVideos.scrollEnabled = true
featuredVideos.setContentOffset(CGPoint(x: 0,y: 0), animated: true)
featuredVideos.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: "cellId")
addSubview(featuredVideos)
setConstraints("H:|[v0(\(frame.width))]|", subviews: featuredVideos)
setConstraints("V:|[v0(345)]", subviews: featuredVideos)
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 5
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cellId", forIndexPath: indexPath)
if indexPath.item == 1 { cell.backgroundColor = .lightGrayColor() } else { cell.backgroundColor = .brownColor() }
return cell
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize
{
return CGSizeMake(frame.width/3, frame.height)
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAtIndex section: Int) -> CGFloat
{
return 10
}
}
Edit : UICollectionView actually doesn't react to any interaction, i tried "didSelectAtIndexPath", doesn't trigger.
To realize UICollectionView with UICollectionView in UICollectionViewCell try this idea (both of the collectionViews are scrollable):
CollectionViewController.swift
import UIKit
class CollectionViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout
{
var featuredVideos: UICollectionView?
override func viewDidLoad() {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .Horizontal
featuredVideos = UICollectionView(frame: UIScreen.mainScreen().bounds, collectionViewLayout: layout)
featuredVideos!.dataSource = self
featuredVideos!.delegate = self
// Setting the collection view's scrolling behaviour
featuredVideos!.pagingEnabled = true
featuredVideos!.scrollEnabled = true
featuredVideos!.setContentOffset(CGPoint(x: 0,y: 0), animated: true)
featuredVideos!.registerClass(CollectionViewCell.self, forCellWithReuseIdentifier: "cellId")
view.addSubview(featuredVideos!)
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 5
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cellId", forIndexPath: indexPath) as! CollectionViewCell
cell.initCell()
if indexPath.item%2 == 0
{
cell.backgroundColor = .lightGrayColor()
}
else
{
cell.backgroundColor = .brownColor()
}
return cell
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize
{
return CGSizeMake(300, UIScreen.mainScreen().bounds.height)
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAtIndex section: Int) -> CGFloat
{
return 10
}
}
CollectionViewCell.swift
class CollectionViewCell: UICollectionViewCell, UICollectionViewDataSource, UICollectionViewDelegate
{
var collectionView: UICollectionView?
func initCell () {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .Horizontal
var collectionViewBounds = self.bounds
collectionViewBounds.size.height -= 80
collectionViewBounds.origin.y = 40
collectionView = UICollectionView(frame: collectionViewBounds, collectionViewLayout: layout)
collectionView!.dataSource = self
collectionView!.delegate = self
// Setting the collection view's scrolling behaviour
collectionView!.pagingEnabled = true
collectionView!.scrollEnabled = true
collectionView!.setContentOffset(CGPoint(x: 0,y: 0), animated: true)
collectionView!.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: "cellWithCollectionView")
addSubview(collectionView!)
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cellWithCollectionView", forIndexPath: indexPath)
if indexPath.item%2 == 0
{
cell.backgroundColor = .blueColor()
}
else
{
cell.backgroundColor = .whiteColor()
}
return cell
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize
{
return CGSizeMake(100, collectionView.frame.height)
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAtIndex section: Int) -> CGFloat
{
return 10
}
}
I've found the problem.
In the parent view, I added a border to this view (which is a UICollectionViewCell in the parent view) inside the cellForItemAtIndexPath(), and that caused the view to only load the first cells and refuse any interaction.
I fixed it by adding the border in the init() inside the "child view" which worked just fine.
Thank you all for your help :)
If you are using Scroll View delegate methods, then this problem may come.
So, resolve by adding this line into those delegate methods :
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView.isKind(of: UICollectionView.self)
{
return
};
}

Resources