iOS swift collection view - ios

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/

Related

I am implementing UICollectionView with two rows of cells and I need both can be scroll horizontally at the same time

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)

Reuse identifier when using two different collection views

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.

UICollectionView is not displaying - bug?

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.

iOS Swift: How to prepare a cell for reuse

I have a UITableView with a custom cell, each of which contains a horizontally scrolling UICollectionView. When the table view cells are recycled the horizontal scroll position of the collection view is recycled with it. Should I be resetting the collection view scroll position manually when I create new cells? And if so is there a way to preserve the scroll position on a per-cell basis?
Custom UITableViewCell
class CustomCell: UITableViewCell, UICollectionViewDelegate, UICollectionViewDataSource {
var collectionView:UICollectionView!
var layout = UICollectionViewFlowLayout()
var collectionData = [UIImage]()
let kCellIdentifier = "Cell"
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
layout.minimumLineSpacing = 10.0
layout.minimumInteritemSpacing = 1.0
layout.scrollDirection = UICollectionViewScrollDirection.Horizontal
collectionView = UICollectionView(frame: CGRectZero, collectionViewLayout: layout)
collectionView.registerClass(ItemCell.self, forCellWithReuseIdentifier: kCellIdentifier)
collectionView.delegate = self
collectionView.dataSource = self
addSubview(collectionView)
}
override func layoutSubviews() {
super.layoutSubviews()
layout.itemSize = CGSize(width: 800, height: bounds.height)
collectionView.frame = bounds
}
}
extension ProjectCell: UICollectionViewDataSource {
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 5
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(kCellIdentifier, forIndexPath: indexPath) as! ItemCell
//Reset collectionView scroll position?
return cell
}
}
The best place to put the code to reset the scroll position in the UICollectionViewCell would be in the prepareForReuse method. Override it in your cell subclass and it will be called every time a previously existing cell is dequeued by dequeueReusableCellWithReuseIdentifier.

swift fatal error: unexpectedly found nil while unwrapping an Optional value

I'm new to swift and I can't quite figure out how to address this error.
I'm creating a collection view and this is my code:
import UIKit
class FlashViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
#IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
// Move on ...
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 20, left: 10, bottom: 10, right: 10)
layout.itemSize = CGSize(width: 90, height: 90)
collectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
self.collectionView.dataSource = self
self.collectionView.delegate = self
collectionView.registerClass(CollectionViewCell.self, forCellWithReuseIdentifier: "CollectionViewCell")
collectionView.backgroundColor = UIColor.whiteColor()
self.view.addSubview(collectionView!)
}
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
}
}
every time I run it the self.collectionView.dataSource = self line gets highlighted and I get the above mentioned error.
As you use weak reference your collection view released before you call it.
So you have to make it strong by removing "weak" keyword.
#IBOutlet var collectionView: UICollectionView!
Or make it stay in memory in another way.
...
collectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
// because collectionView is a weak variable, it will be released here
self.collectionView.dataSource = self // error, collectionView is nil
...
As #Vitaliy1 said, you can make collectionView a strong reference, or use a local variable to hole it before you add it to the view hierarchy.
...
let collectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
collectionView.dataSource = self
...
view.addSubview(collectionView)
// view establishes a strong reference to collectionView,
// so you can reference it until it is removed from the view hierarchy.
self.collectionView = collectionView
or, why not just use a subclass of UICollectionViewController

Resources