UICollectionView not refreshing - swift

I am downloading some images and inserting them into my UICollectionView
These are my class members
var myItems:[UIImage] = []
var myView: UICollectionView?
I have a timer function that receives img:UIImage object. I insert that into my UICollectionView like this
self.myItems.insert(img, atIndex: self.myItems.count)
var count:Int? = self.myView?.numberOfItemsInSection(0)
var index:NSIndexPath = NSIndexPath(forRow: count!, inSection: 0)
self.myView?.insertItemsAtIndexPaths([index])
I also have this function:
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.myItems.count;
}
and this one:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as MyCollectionViewCell
cell.backgroundColor = UIColor.orangeColor()
cell.textLabel.text = "Text \(indexPath.row)"
cell.imageView.image = myItems[indexPath.row]
cell.backgroundView = UIImageView(image: UIImage(named: "cellbg"))
return cell
}
However my view does not show the new images immediately. I have to tap on the empty screen, then the new cell appears with its image. Also I cannot scroll the view if there are more cells that will fit in the view.
How do I refresh the view? Is there something wrong with the way I am dequeuing the cell?

You forgot to reload UICollectionView.
self.myView.reloadData()

reloadData did not quite work
then I stumbled on this SO answer
What fixed the problem was calling reloadData from the main thread.

Related

Showing/Hiding images in CollectionView Cell

I'm trying to show some images and hide others using ".isHidden" in my CollectionView. But when I scroll down or reload the collectionView they either get reordered incorrectly or hidden entirely.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ReadBookCell", for: indexPath) as! ReadBookCell
let item = readBookArray[indexPath.item]
for star in cell.starImgOutletCollection {
if star.tag <= item.starRating {
star.isHidden = false
} else {
star.isHidden = true
}
}
return cell
}
Edit: Here is my prepareForReuse
override func prepareForReuse() {
super.prepareForReuse()
for star in starImgOutletCollection {
star.isHidden = true
}
}
Assuming your "stars" are 5 image views in a stack view like this:
And, assuming your starRating will be between 0 and 5 (Zero being no rating yet)...
In your cell class, create a reference to the stack view - since your question mentions starImgOutletCollection I'm assuming you are using #IBOutlet (that is, not creating your views via code), so:
#IBOutlet var starsStackView: UIStackView!
Then, still in your cell class, add this func:
func updateStars(_ starRating: Int) {
for i in 0..<starsStackView.arrangedSubviews.count {
starsStackView.arrangedSubviews[i].isHidden = i >= starRating
}
}
Now, in cellForRowAt
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ReadBookCell", for: indexPath) as! ReadBookCell
let item = readBookArray[indexPath.item]
cell.updateStars(item.starRating)
// do the other stuff to set labels, images, etc
// in the cell
return cell
}
You no longer need the outlet collection for the "star" image views, and you no longer need to implement prepareForReuse().

Cell takes index of its previous cell - Collectionview inside Tableview

I want to dynamically add collection view inside tableview. I have make following code.
A cell class for collectionview
class NewsFeedCollectionViewCell : UICollectionViewCell{
#IBOutlet weak var imageViewSlider: UIImageView!
}
Than assign collectionview in Tableview cellforrow at indexpath
cell.collectionViewNewsFeed.tag = indexPath.row
cell.collectionViewNewsFeed.reloadData()
Than added following delegates of collectionview
// MARK: - Collection view Delegates / Datasources
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return (mutableArrayNewsFeed[collectionView.tag]["images"] as! NSArray).count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("NewsFeedCollectionViewCell", forIndexPath: indexPath) as! NewsFeedCollectionViewCell
print("tag : \(collectionView.tag) , Row : \(indexPath.row)")
let img = (mutableArrayNewsFeed[collectionView.tag]["images"] as! NSArray)[indexPath.row] as? String ?? "imgLoginScreenLogo"
cell.imageViewSlider.image = UIImage(named: img)
return cell
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
print("Collection View Row : \(indexPath.row)")
}
func collectionView(collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize{
return collectionView.frame.size
}
Its adjusting properly but the indexes gets changes while i scroll the collectionview. For ex, I scroll collectionview upto 3 cell than i go to the tableview 4th index than it also set the index of 4th index of collectionview to 3rd.
Simply want to add collection view with multiple images inside Table view. I have added, but after scrolling the collection view to 3rd image on 1st cell of tableview, i move to 4th cell of Tableview, there also the collectionview gets scrolled automatically upto 4th cell.
Need to get out of this.
There was an issue with the indexpath, I get the solution by keeping the indexpath in an array.
Refer Following link
https://github.com/ashfurrow/Collection-View-in-a-Table-View-Cell

UICollectionView setting first cell to always be specific content

Hi so I'm using a side scrolling UICollectionView to display groups of people that the user makes. The groups are stored on my server and when the view loads, they load from the server. However I want the first cell to always be the same which is a cell which lets you create groups. This is the layout i need.
I know how to use multiple different custom cells, but how do I make it so the first cell is static and the cells after load content from my servers? Thanks :)
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return familyName.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
if indexPath.row == 0 {
let cell : AddGroupCollectionViewCell = collectionViewOutlet.dequeueReusableCellWithReuseIdentifier("Add", forIndexPath: indexPath) as! AddGroupCollectionViewCell
return cell
} else {
let cell : FriendGroupsCell = collectionViewOutlet.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as! FriendGroupsCell
cell.groupImage.image = UIImage(named: "pp")
cell.groupNameLabel.text = familyName[indexPath.row]
return cell
}
}
This is my code and it misses out the first person in the array because the index path skips over it. How can i modify this so it works
UICollectionViewCell is leveraging reusing techniques to improve performance. Remember this. Nothing can be static in a cell, because this cell later will be on another index.
You can use collectionView:cellForItemAtIndexPath: to make the first cell always load the same images/labels via indexPath.row == 0
You can use prepareReuse method to clean up the resources in the cell. So if cell No.2 is going to be the new No.1 cell, it get a chance to clean up old resources.
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell : AddGroupCollectionViewCell = collectionViewOutlet.dequeueReusableCellWithReuseIdentifier("Add", forIndexPath: indexPath) as! AddGroupCollectionViewCell
if indexPath.row == 0 {
cell.groupImage.image = UIImage(named: "new")
cell.groupNameLabel.text = "new"
} else {
cell.groupImage.image = UIImage(named: "pp")
cell.groupNameLabel.text = familyName[indexPath.row]
}
return cell
}

UICollectionView didSelectItemAtIndexPath effects multiple cells - swift

Swift, no storyboard, UICollectionView from xib file
I am running very simple code to update cell's background color but, more then one cells are updating.
override func viewDidLoad(){
super.viewDidLoad()
// getting images from library
images = PHAsset.fetchAssetsWithMediaType(.Image, options: nil)
collectionView.allowsMultipleSelection = false
var nipName2 = UINib(nibName: "CollectionViewCell", bundle:nil)
collectionView.registerNib(nipName2, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "HeaderCell")
var nipName = UINib(nibName: "MyViewCell", bundle:nil)
collectionView.registerNib(nipName, forCellWithReuseIdentifier: "Cell")
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return images.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell{
var cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as! MyViewCell
cell.frame.size.width = 60
return cell
}
func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView{
switch kind
{
case UICollectionElementKindSectionHeader:
let headerView = collectionView.dequeueReusableSupplementaryViewOfKind(kind, withReuseIdentifier: "HeaderCell", forIndexPath: indexPath) as! CollectionViewCell
return headerView
default:
assert(false, "Unexpected element kind")
}
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath)
{
var cell = collectionView.cellForItemAtIndexPath(indexPath)
cell?.backgroundColor = UIColor.redColor()
}
I have about 300 different cells. I want to update just third one but randomly many other cells' background changing.
So collection and table views have a strong concept of view reuse. This allows for large performance gains since it does not have to keep [in your case] 300 cells in memory at the same time.
When you are setting the background color on some cells, those cells have the potential to be reused when scrolling. Since you are not explicitly setting the background upon the view showing, it just uses whatever it currently is.
To fix this just set the color when the view is requested:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell{
// This does not guarantee to be a fresh, new cell, can be reused
var cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as! MyViewCell
cell.frame.size.width = 60
// Explicitly set the background color:
cell.backgroundColor = .whiteColor() // or whatever your default color is
return cell
}
Now it is obvious this will cause additional side-effects. Say you change the background color of a cell to red and scroll away. When you come back you are now setting it back to white. That being said, you need to track which cells (probably by storing their indexes) are selected and set their color appropriately.

Is it possible to retrieve data from collectionViewCell?

I'm looking to retrieve data, such as a label.text from within a visible cell, and I don't know how that would be possible.
Plain context: I have a collectionView displaying questions (each cell display a question)
the collectionView is within a UIView.
Within this same uiview I have a button which, when pressed, should validate the question answer.
At this point the only thing Im doing is linking a #IBAction to the button in order for it to println the question from the visible cell (only one cell is visible).
here is how I construct the cell
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// return arr.count
return questionData.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell:CollectionViewCell = collectionView.dequeueReusableCellWithReuseIdentifier("CollectionViewCell", forIndexPath: indexPath) as CollectionViewCell
let thereq:PFObject = self.questionData.objectAtIndex(indexPath.row) as PFObject
// cell.contentView.frame = cell.bounds
var action = thereq.objectForKey("action") as String
var what = thereq.objectForKey("what") as String
cell.askingQuestionLabel.text = "where \(action) \(what)"
return cell
}
on button touch (button is out of the cell).
I know visibleCells() exists but it doesn't look like I can retrieve info out of it.
for cell in self.collectionView!.visibleCells() as [UICollectionViewCell] {
}
Is there any way?
You already have a custom collection view cell class. The obvious solution is to pass the PFObject to the CollectionViewCell in your cellForItemAtIndexRow method, and then retrieve it from the cell when the button is clicked.
Just cast the return value from visibleCells to your collection view cell class and then pull the PFObject out of it.
To access data (such as a label.text) within a visible cell, you can use the visibleCells() method as follow:
for item in self.collectionView!.visibleCells() as [UICollectionViewCell] {
var indexpath : NSIndexPath = self.collectionView!.indexPathForCell(item as CollectionViewCell)!
var cell : CollectionViewCell = self.collectionView!.cellForItemAtIndexPath(indexpath) as CollectionViewCell
//access cell data
println(cell.labelName.text)
}