I am a bit of a novice with swift. I am trying to simply create a collection view that is placed within a specific region of the screen (landscape iPad iOS). It is possible that there is actually a collectionView bug... The following code produces the attached image. The problem is that the entirety of the collection view simply isn't displayed...
import UIKit
class ViewController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
var collectionView: UICollectionView?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 300, left: 500, bottom: 30, right: 10)
layout.itemSize = CGSize(width: 32, height: 32)
collectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
collectionView!.dataSource = self
collectionView!.delegate = self
collectionView!.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
collectionView!.backgroundColor = UIColor.whiteColor()
self.view.addSubview(collectionView!)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 40
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as! UICollectionViewCell
cell.backgroundColor = UIColor.orangeColor()
return cell
}
}
Also, is there a way I can avoid using a FLOW LAYOUT? A rigid collection view is fine. I need a 10x10 collection view that won't vary in size or number of cells.
For what you're trying to achieve using auto layout sounds like it would be your best option. You could alternatively set your UICollectionView's frame to be in the bottom right corner like so:
collectionView!.frame = CGRect(x: self.view.frame.size.width - collectionView!.frame.size.width, y: self.view.frame.size.height - collectionView!.frame.size.height, width: 400, height: 400)
But this is more of a temporary fix and would have to be considered for each device's, and future device's, layout.
Related
I have a UICollectionView that has horizontal scrolling. I need to place all my collection view cells in two rows and both should scroll horizontally. The layout is as shown in the screenshot.
As shown in the above screenshot, I am going to have to build two rows which will scroll horizontally, i.e., both rows will scroll together in the same direction.
I had earlier considered using sections in the scroll view, but then the scrolling would probably be independent, and so, I am hoping to find a better solution.
I looked into this link here : A similar post
This link uses a tableview to hold multiple collection views. Even though solution seems good, I am really not sure if it could work for me, I wish to know if there is a better alternative.
I looked into other stack overflow posts regarding the same (Can’t remember which though), but they did not help much.
Now normally, we would have two columns in the collection view and we can scroll vertically. Instead of this behavior, is there any way to have two rows in a UICollectionView which can scroll horizontally and simultaneously?
Should I consider using two collection views and have some logic that binds the scrolling of both the views? (I’d rather not have two UICollectionviews just to solve this problem)
Also, I am doing this through pure code. No storyboards or xib files have been used.
Can you try the code below?
I was able to do this i guess
class CollectionViewController: UIViewController {
#IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
setUpCollectionView()
}
fileprivate func setUpCollectionView() {
let collectionFlowLayout = UICollectionViewFlowLayout()
collectionFlowLayout.scrollDirection = .horizontal
collectionFlowLayout.itemSize = CGSize(width: 145, height: 145)
collectionView.setCollectionViewLayout(collectionFlowLayout, animated: true)
collectionView.delegate = self
collectionView.dataSource = self
}
}
extension CollectionViewController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 100
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomCollectionViewCell", for: indexPath)
if indexPath.row % 2 == 0 {
cell.contentView.backgroundColor = UIColor.red
} else {
cell.contentView.backgroundColor = UIColor.green
}
return cell
}
}
NOTE: I have set collectionView height as 300
OUTPUT
Use 2 collectionView
let CellId1 = "CellId1"
lazy var collectionViewOne: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.minimumLineSpacing = 0
let width = collectionView.frame.width
let collectionViewOne = UICollectionView(frame: CGRect(x: 0, y: 100, width: width, height: 100), collectionViewLayout: layout)
collectionViewOne.showsHorizontalScrollIndicator = false
collectionViewOne.backgroundColor = .red
return collectionViewOne
}()
let CellId2 = "CellId2"
lazy var collectionViewTwo: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.minimumLineSpacing = 0
let collectionViewTwo = UICollectionView(frame: CGRect(x: 0, y: 250, width: width, height: 100), collectionViewLayout: layout)
collectionViewTwo.backgroundColor = .blue
return collectionViewTwo
}()
then for obtaining the numberOfItem and cellForRow:
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == self.collectionViewOne {
return 10
} else if collectionView == self.collectionViewTwo {
return 20
}
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == self.collectionViewOne {
let Cell1 = collectionViewOne.dequeueReusableCell(withReuseIdentifier: CellId1, for: indexPath)
Cell1.backgroundColor = .green
return Cell1
} else if collectionView == self.collectionViewTwo {
let Cell2 = collectionViewTwo.dequeueReusableCell(withReuseIdentifier: CellId2, for: indexPath )
Cell2.backgroundColor = .purple
return Cell2
}
}
and don't forget to register the collectionView in viewDidLoad()
collectionViewOne.delegate = self
collectionViewOne.dataSource = self
collectionViewTwo.delegate = self
collectionViewTwo.dataSource = self
collectionViewOne.register(Cell1.self, forCellWithReuseIdentifier: storyCell)
collectionViewTwo.register(Cell2.self, forCellWithReuseIdentifier: cardCell)
I would like to make a collectionView that can be scrolled horizontally and has only one cell item visible and one partially visible. Cells should take the whole height of the collectionView.
I have played with the sectionInset of collectionView. But couldn't achieve my target.
My Code:
import UIKit
class BooksController: UIViewController {
#IBOutlet weak var booksCollectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 20)
layout.itemSize = CGSize(width: booksCollectionView.frame.width, height: booksCollectionView.frame.height)
layout.minimumInteritemSpacing = 10
layout.minimumLineSpacing = 10
layout.scrollDirection = .horizontal
booksCollectionView.collectionViewLayout = layout
booksCollectionView.register(UINib(nibName: "BookCell", bundle: .main), forCellWithReuseIdentifier: "BookCell")
booksCollectionView.dataSource = self
booksCollectionView.delegate = self
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
extension BooksController: UICollectionViewDataSource {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "BookCell", for: indexPath) as? BookCell {
return cell
}
return UICollectionViewCell()
}
}
extension BooksController: UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
// func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets {
// return UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 20)
// }
}
Target (Something similar to the collectionView here)
My Output
Use this piece of code
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = self.view.frame.width - 100
let height = self.view.frame.height
return CGSize(width: width, height: height)
}
Don't forget to add this delegate
UICollectionViewDelegateFlowLayout
Add UICollectionViewDelegateFlowLayout
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: self.view.frame.width, height: self.view.frame.height)
}
Use this Pod MSPeekCollectionViewDelegateImplementation
GitHub
You can use if you need to show half of the second collection view cell
collectionView.contentInset = UIEdgeInsets.init(top: 0, left: 10, bottom: 0, right: 10)
For height and with of the collection view you can try CollectionViewLayout delegate
Riddle me this. I have a view that I'm implementing two different collection views on. The two collection views are setup nearly identically.
When I add both to my view, my app calls an error:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'could not dequeue a view of kind: UICollectionElementKindCell with identifier CollectionViewPantsCell - must register a nib or a class for the identifier or connect a prototype cell in a storyboard'
Which doesn't make sense, as I registered it the exact same as my CollectionViewShirtCell.
To debug, I removed the pants collection, and rewrote my "cellForItemAt" method to be really simple. It worked fine with one collectionView.
So, what is the difference? I've added some notes in caps in the code.
import UIKit
class HomeController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
let collectionViewShirtsIdentifier = "CollectionViewShirtsCell"
let collectionViewPantsIdentifier = "CollectionViewPantsCell"
var shirtStore: ShirtStore!
var pantStore: PantStore!
public var collectionViewShirts : UICollectionView{
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = UICollectionViewScrollDirection.horizontal
let collectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height/2), collectionViewLayout: layout)
collectionView.backgroundColor = UIColor.orange
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: collectionViewShirtsIdentifier)
return collectionView
}
public var collectionViewPants : UICollectionView{
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = UICollectionViewScrollDirection.horizontal
let collectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height/2), collectionViewLayout: layout)
collectionView.backgroundColor = UIColor.blue
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: collectionViewPantsIdentifier)
return collectionView
}
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "Hanger"
self.view.addSubview(collectionViewShirts)
///... CANT ADD THE SECOND COLLECTION????
// self.view.addSubview(collectionViewPants)
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == self.collectionViewShirts {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: collectionViewShirtsIdentifier, for: indexPath as IndexPath)
return cell
}
else
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: collectionViewPantsIdentifier, for: indexPath as IndexPath)
return cell
}
}
///... THIS VERSION WORKS IF I ONLY TRY TO MANIPULATE ONE COLLECTION
// func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
// let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewShirtsCell", for: indexPath as IndexPath)
//
// return cell
// }
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int{
if(collectionView == collectionViewShirts)
{
print(shirtStore.allShirts.count)
return shirtStore.allShirts.count
}
else if (collectionView == collectionViewPants)
{
return pantStore.allPants.count
}
else
{
return 5//shoeStore.allShoes.count
}
}
}
The way you are setting up your collectionViewShirts and collectionViewPants variables is incorrect. As a result, the if test in cellForItemAt: is falling through to the else and you are attempting to dequeue a 'pants' cell for the 'shirts' collection view.
You need to declare your collection views properly:
public var collectionViewShirts : UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = UICollectionViewScrollDirection.horizontal
let collectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height/2), collectionViewLayout: layout)
collectionView.backgroundColor = UIColor.orange
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: collectionViewShirtsIdentifier)
return collectionView
}()
public var collectionViewPants : UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = UICollectionViewScrollDirection.horizontal
let collectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height/2), collectionViewLayout: layout)
collectionView.backgroundColor = UIColor.blue
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: collectionViewPantsIdentifier)
return collectionView
}()
Note the = and the () at the end of the closure. This tells Swift to assign the value returned by invoking the anonymous function.
I would also suggest that you use constraints rather than setting the frame directly, as this won't work with view rotation and the frame won't be set correctly at the time you are initialising the collection views, as the view frame is only set when viewDidLayoutSubviews is called.
As I mentioned earlier, doing this sort of stuff in Storyboard is much simpler.
i am using swift 2.o collection view. In that every thing is working fine. But when i run in different screen , the width gap between each cell are different. I need three cell in each row of collection view with 8 px gap for left,right,top,bottom for all cell in collection view. And also i need to set the cell as corner radius. i need like below image :
[![enter image description here][1]][1]
But when i run in 5s screen i am getting like this and for 6 screen like 2nd image :
[![enter image description here][2]][2]
iphone 6 :
[![enter image description here][3]][3]
See the gap between left, right, bottom , top are not equally sapced as like my first image. i need to get like my first image.
I set the min line space for cell is 6 in storyboard. But i not able to get like my first imge.
please help me out.
my popvc.swift :
import UIKit
class popVC: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
var tableData: [String] = ["RESTAURANTS", "BANKS", "COFFEE","PIZZA", "HOTELS", "TAXI", "RESTAURANTS", "BANKS","COFFEE","PIZZA", "HOTELS", "TAXI","RESTAURANTS", "BANKS", "COFFEE","PIZZA", "HOTELS", "TAXI"]
var tableImages: [String] = ["img1.png", "img2.png", "img3.png", "img4.png", "img5.png", "img6.png", "img7.png", "img8.png", "img9.png", "img10.png", "img11.png", "img11.png", "img1.png", "img2.png", "img3.png", "img4.png", "img5.png", "img6.png"]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return tableData.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell: colvwCell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as! colvwCell
cell.lblCell.text = tableData[indexPath.row]
cell.imgCell.image = UIImage(named: tableImages[indexPath.row])
return cell
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
print("Cell \(indexPath.row) selected")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
From the storyboard set CollectionViews Section Inset from size inspector as Top = 8, Bottom = 8, Left = 8 and Right = 8, it should look like as
And return size for cell as
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
//If you want your cell should be square in size the return the equal height and width, and make sure you deduct the Section Inset from it.
return CGSizeMake((self.view.frame.size.width/3) - 16, (self.view.frame.size.width/3) - 45);
}
Thats it, Nothing more. You should see the result as mine:
Create a collection view using following code:
#IBOutlet var collectionView: UICollectionView?
var screenSize: CGRect!
var screenWidth: CGFloat!
var screenHeight: CGFloat!
override func viewDidLoad() {
print("select block is \(self.strBlockname)")
screenSize = UIScreen.mainScreen().bounds
screenWidth = screenSize.width
screenHeight = screenSize.height
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 10, left: 0, bottom: 10, right: 0)
layout.itemSize = CGSize(width: (screenWidth/3)-1, height: (screenWidth/3)-1)
layout.minimumInteritemSpacing = 1
layout.minimumLineSpacing = 1
collectionView = UICollectionView(frame: CGRectMake(0, 0, screenWidth, screenHeight-65), collectionViewLayout: layout)
collectionView!.dataSource = self
collectionView!.delegate = self
collectionView!.registerClass(CollectionViewCell.self, forCellWithReuseIdentifier: "CollectionViewCell")
collectionView!.backgroundColor = UIColor.whiteColor()
self.view.addSubview(collectionView!)
super.viewDidLoad()
// Do any additional setup after loading the view.
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 20
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("CollectionViewCell", forIndexPath: indexPath) as! CollectionViewCell
cell.backgroundColor = UIColor.blackColor()
cell.textLabel?.text = "\(indexPath.section):\(indexPath.row)"
cell.imageView?.image = UIImage(named: "circle")
return cell
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
Its Output for iPhone5s,6s and 6+ is following:
iPhone5s
iPhone6s
#user5513630 Add following code in collection view.
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
let size = UIScreen.mainScreen().bounds.size
// 8 - space between 3 collection cells
// 4 - 4 times gap will appear between cell.
return CGSize(width: (size.width - 4 * 8)/3, height: 40)
}
read this tutorial. it will fulfill your requirement
i have created collection view in swift
language i need to add images to those cells how can i add images?
class ViewController: UIViewController,UICollectionViewDelegateFlowLayout,UICollectionViewDataSource {
var collectionView: UICollectionView?
override func viewDidLoad() {
super.viewDidLoad()
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 20, left: 10, bottom: 10, right: 10)
layout.itemSize = CGSize(width: 90, height: 120)
collectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
collectionView!.dataSource = self
collectionView!.delegate = self
collectionView!.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
collectionView!.backgroundColor = UIColor.blueColor()
self.view.addSubview(collectionView!)
// Do any additional setup after loading the view, typically from a nib.
}
Easiest way is to create collection view in interface builder, subclass uicollectionviewcell add outlet for uiimageview
class colCollectionViewCell: UICollectionViewCell {
#IBOutlet var myImageView: UIImageView!
}
Add one dynamic cell in that collectionview, change class of that cell to your subclass. Drop UIImageView on that cell, connect your outlet and access it from UICollectionView delegate/datasource functions.
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as colCollectionViewCell
cell.myImageView.image = UIImage(named:"myimagename")
return cell
}
Here is a great tutorial for UICollectionView: http://www.raywenderlich.com/78550/beginning-ios-collection-views-swift-part-1
you can use Haneke
Sample
if let urlString = self.data?["images"]["standard_resolution"]["url"]{
let url = NSURL(string: urlString.stringValue)
self.imageView.hnk_setImageFromURL(url!)
}
Reference: http://blog.revivalx.com/2015/02/24/uicollectionview-tutorial-in-swift-using-alamofire-haneke-and-swiftyjson/