Im making a game that has a collectionView character select at the bottom of the GameScene. Many of the characters are locked, so i display a "Locked" image as the collection view cell image. However, when the user unlocks the character and they load the GameScene again(move to gameOver scene, restart the game back to present GameScene), i need to update the collectionView cells images and swap out the "Locked" image with the regular image. Ive tried so many different things but it isn't working. It won't swap out/reload the new images. I know its just something small I'm missing but heres all my code associated with the collection view.
class CharactersCollectionViewCell: UICollectionViewCell {
//MARK : Public API
var characters : NACharacters!{
didSet{
updateUI()
}
}
//MARK : Private
#IBOutlet weak var featuredImageView: UIImageView!
private func updateUI(){
self.layer.borderColor = UIColor.whiteColor().CGColor
self.layer.borderWidth = 2.5
self.layer.masksToBounds = true
self.layer.cornerRadius = CGFloat(roundf(Float(self.frame.size.width/2.0)))
featuredImageView.image = characters.featuredImage
}
}
class NACharacters {
var featuredImage : UIImage!
static var characterLineUp = [NACharacters]()
init(featuredImage: UIImage){
self.featuredImage = featuredImage
}
static func createCharacters() -> [NACharacters]{
print("Inside create character")
characterLineUp.insert(NACharacters(featuredImage: UIImage(named: "DiploSquadCollectionView")!), atIndex: 0)
characterLineUp.insert(NACharacters(featuredImage: UIImage(named: "LockedNBAPlayersCollectionView")!), atIndex: 1)
if(NSUserDefaults().unlockNBAPlayers == true){
characterLineUp[1].featuredImage = UIImage(named: "NBAPlayersCollectionView")!
}
characterLineUp.insert(NACharacters(featuredImage: UIImage(named: "LockedLeanSquadCollectionView")!), atIndex: 2)
if(NSUserDefaults().totalDabs >= 10000){
print("setting up lean to be unlocked")
characterLineUp[2].featuredImage = UIImage(named: "LeanSquadCollectionView")!
}
return characterLineUp
}
}
//Inside Game View Controller
#IBOutlet var collectionView: UICollectionView!
//MARK : Data Source
internal var characters = NACharacters.createCharacters()
extension GameViewController : UICollectionViewDataSource, UICollectionViewDelegate{
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return characters.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(Storyboard.CellIdentifier, forIndexPath: indexPath) as! CharactersCollectionViewCell
cell.characters = self.characters[indexPath.item]
return cell
}
//Inside Game Scene
var collectionView: UICollectionView? {
return self.view?.subviews.filter{ $0 is UICollectionView }.first as? UICollectionView
}
override func didMoveToView(view: SKView) {
//INSIDE HERE I NEED TO UPDATE THE COLLECTION VIEW CELL IMAGES
}
I know this looks like a lot of code but most of it is pretty standard. I show you all of this so that we can pin point exactly whats wrong or what needs to be done to get this to work. This is all of my code associated with the collectionView.
Have you try this in same place ::
imageView.image = nil
then set the image you want to update as ..
imageView.image = UIImage(named : "YourImage")
When you need to 'refresh' a Collection View, tell it to reload its data, then all the images should update as needed.
collectionView.reloadData()
Related
I have a shop menu for my game in swift. I am using a UICollectionView to hold the views for the items. There is a black glass covering over them before they are bought, and it turns clear when they buy it. I am storing data for owning the certain items in the cells' classes. When I scroll down in the scrollView and then come back up after clicking a cell. A different cell than collected has the clear class and the one I previously selected is black again.
import UIKit
class Shop1CollectionViewCell: UICollectionViewCell {
var owned = Bool(false)
var price = Int()
var texture = String()
#IBOutlet weak var glass: UIImageView!
#IBOutlet weak var ball: UIImageView!
func initiate(texture: String, price: Int){//called to set up the cell
ball.image = UIImage(named: texture)
if owned{//change the glass color if it is owned or not
glass.image = UIImage(named: "glass")
}else{
glass.image = UIImage(named: "test")
}
}
func clickedOn(){
owned = true//when selected, change the glass color
glass.image = UIImage(named: "glass")
}
}
Then I have the UICollectionView class
import UIKit
class ShopViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
struct ball{
var price = Int()
var texture = String()
var owned = Bool()
}
var balls = Array<ball>()//This is assigned values, just taken off of the code because it is really long
override func viewDidLoad() {
super.viewDidLoad()
balls = makeBalls(
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return (balls.count - 1)
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! Shop1CollectionViewCell
cell.initiate(texture: balls[indexPath.item].texture, price: 1)
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath) as! Shop1CollectionViewCell
cell.clickedOn()
}
}
I am wondering why the variables stored in one class of a cell are being switched to another.
Please ask if you need me to add any additional information or code.
You should definitely implement prepareForReuse, and set the cell back to its default state - which in this case would be with the black glass, and unowned.
You can still change the glass in the same way as you're doing in didSelectItemAt, but I'd recommend having the view controller track the state of each ball.
For example, when didSelectItemAt gets called - the view controller would update the ball stored in self.balls[indexPath.row] to have owned = true.
That way, the next time cellForItemAt gets called, you'll know what colour the glass should be by checking the value in self.balls[indexPath.row].owned.
Lastly, you're returning balls.count - 1 in numberOfItems, is this intentional?
In the case where have 10 balls, you're only going to have 9 cells. If you want a cell for each of your objects you should always return the count as is.
Sometimes, you may have to override the following function
override func prepareForReuse(){
super.prepareForReuse()
// reset to default value.
}
in class Shop1CollectionViewCell to guarantee cells will behave correctly. Hope you got it.
The title might be a little hard to understand, but this situation might help you with it.
I'm writing a multiple image picker. Say the limit is 3 pictures, after the user has selected 3, all other images will have alpha = 0.3 to indicate that this image is not selectable. (Scroll all the way down to see a demo)
First of all, this is the code I have:
PickerPhotoCell (a custom collection view cell):
class PickerPhotoCell: UICollectionViewCell {
#IBOutlet weak var imageView: UIImageView!
var selectable: Bool {
didSet {
self.alpha = selectable ? 1 : 0.3
}
}
}
PhotoPickerViewController:
class PhotoPickerViewController: UICollectionViewController {
...
var photos: [PHAsset]() // Holds all photo assets
var selected: [PHAsset]() // Holds all selected photos
var limit: Int = 3
override func viewDidLoad() {
super.viewDidLoad()
// Suppose I have a func that grabs all photos from photo library
photos = grabAllPhotos()
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell ...
let asset = photos[indexPath.row]
...
// An image is selectable if:
// 1. It's already selected, then user can deselect it, or
// 2. Number of selected images are < limit
cell.selectable = cell.isSelected || selected.count < limit
return cell
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath) as! PickerPhotoCell
if cell.isSelected {
// Remove the corresponding PHAsset in 'selected' array
} else {
// Append the corresponding PhAsset to 'selected' array
}
// Since an image is selected/deselected, I need to update
// which images are selectable/unselectable now
for visibleCell in collectionView.visibleCells {
let visiblePhoto = visibleCell as! PickerPhotoCell
visiblePhoto.selectable = visiblePhoto.isSelected || selected.count < limit
}
}
}
This works almost perfectly, except for one thing, look at the GIF:
The problem is
After I've selected 3 photos, all other visible photos have alpha = 0.3, but when I scroll down a little more, there are some photos that still have alpha = 1. I know why this is happening - Because they were off-screen, calling collectionView.visibleCells wouldn't affect them & unlike other non-existing cells, they did exist even though they were off-screen. So I wonder how I could access them and therefore make them unselectable?
The problem is that you are trying to store your state in the cell itself, by doing this: if cell.isSelected.... There are no off screen cells in the collection view, it reuses cells all the time, and you should actually reset cell's state in prepareForReuse method. Which means you need to store your data outside of the UICollectionViewCell.
What you can do is store selected IndexPath in your view controller's property, and use that data to mark your cells selected or not.
pseudocode:
class MyViewController {
var selectedIndexes = [IndexPath]()
func cellForItem(indexPath) {
cell.isSelected = selectedIndexes.contains(indexPath)
}
func didSelectCell(indexPath) {
if selectedIndexes.contains(indexPath) {
selectedIndexes.remove(indexPath)
} else if selectedIndexes.count < limiit {
selectedIndexes.append(indexPath)
}
}
}
I'm simply desperate, searched for 6 hours now and can't seem to find an answer.
I have a collection view with images loaded from a remote server and while scrolling the cells are being refreshed with previous images for a few seconds before settling.
Tried overriding "prepare for reuse" and setting the imageview image to nil but it is still not working..
Would appreciate an example from someone who got it working,
thanks a lot!
EDIT - ADDING THE CODE
CollectionView:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath:indexPath) as! PictureCell
cell.pictureCD = GalleryCD().fetchTable()[indexPath.row]
return cell
}
CollectionViewCell:
class PictureCell: UICollectionViewCell {
#IBOutlet weak var picture: UIImageView!
var pictureCD: NSManagedObject! {
didSet { self.setupData() }
}
override func prepareForReuse() {
super.prepareForReuse()
self.picture.image = nil
self.picture.setNeedsDisplay() // tried adding after some recommendations
self.setNeedsDisplay() // tried adding after some recommendations
}
func setupData(){
self.picture.image = UIImage(named: "blank")
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
let URL = (NSURL (string: url.pictureSquareGET(picture: self.pictureCD)))!
let data = NSData(contentsOfURL: URL)!
dispatch_async(dispatch_get_main_queue()) {
self.picture.image = UIImage(data: data)
}
})
}
}
You can update the prepareForReuse method
override func prepareForReuse() {
myImageView.image = nil
super.prepareForReuse()
}
Your cells have previous images loaded into them because of cell reuse so you are correct there.
All you should need to do is set the cells image as nil in your cellForItemAtIndexPath BEFORE fetching the updated ones from your server.
I'm creating online tutorial app.In that i have 40 questions.I want to display the result for that questions using green image for correct and red color image for incorrect answers.I need to display this 40 images inside the single prototype cell.I want to know in swift.
A table view is designed to show multiple items in a scrolling list, not just one item. It sounds more like you want to have a table view with 40 rows, each of which displays the answer given for the question. You could set that up easily like so:
// This is your prototype cell configured in interface builder
class ResultTableViewCell: UITableViewCell {
#IBOutlet weak var answerImageView: UIImageView!
var correct: Bool = false {
didSet {
let imageName = self.correct ? "correct_image" : "incorrect_image"
if let image = UIImage(named: imageName ) {
self.answerImageView.image = image
}
}
}
}
class MyTableViewCell: UITableViewController {
#IBOutlet weak var collectionView: UICollectionView!
struct Answer {
let isCorrect: Bool
}
var answers = [Answer]() {
didSet {
self.tableView.reloadData()
}
}
// MARK: - UITableViewDataSource
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCellWithIdentifier( "resultCell", forIndexPath: indexPath ) as? ResultTableViewCell {
cell.correct = self.answers[ indexPath.row ].isCorrect
return cell
}
fatalError( "Could not load cell" )
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.answers.count
}
}
Im facing the strangest problem i have experienced using Swift, Im developing a game and im using a collection view cell to show the different add ons that ill have, like clothes and stuff, however, im loading the image names that every collectionviewcell is going to have within an String List, The problem appears when I want to get a check image inside the selected "thing" when i click in one cell, and if i click in other cell, the check goes to that by first deselecting all the cells, everything works fine! but when i put more than 8 items in the String list the following error appears "fatal error: unexpectedly found nil while unwrapping an Optional value" its weird because the items are shown in the collection view fine but the problem appears when i click in one of them, with more than 8 items I repeat.
This is my view controller:
//
// WeaponSelectorViewController.swift
// swiftSpriteAwesomeProject
//
// Created by Mauri C. on 3/2/15.
// Copyright (c) 2015 WANT. All rights reserved.
//
import UIKit
class WeaponSelectorViewController: UIViewController {
var images = [NSString]()
let defaults = NSUserDefaults.standardUserDefaults()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
images = ["chancla", "chancle", "chancle2", "chancle3", "chancle4", "chancle5", "chancle7"]
images.append("chancla")
images.append("chancla")
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return images.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
var cell = collectionView.dequeueReusableCellWithReuseIdentifier("CollectionViewCell", forIndexPath: indexPath) as WeaponCollectionViewCell
cell.checkImageView.hidden = true
if(defaults.stringForKey("chancla") != nil){
if(defaults.stringForKey("chancla")! == images[indexPath.row]){
cell.checkImageView.hidden = false
cell.checkImageView.image = UIImage(named: "check")
}
}
cell.imageView.image = UIImage(named:images[indexPath.row])
cell.imageView.contentMode = UIViewContentMode.ScaleAspectFit
return cell
}
// Uncomment this method to specify if the specified item should be selected
func collectionView(collectionView: UICollectionView, shouldSelectItemAtIndexPath indexPath: NSIndexPath) -> Bool {
NSLog("\(indexPath)")
let cell = collectionView.cellForItemAtIndexPath(indexPath) as WeaponCollectionViewCell
NSLog("\(self.images.count)")
for var i = 0; i < self.images.count; i++ {
var celli = collectionView.cellForItemAtIndexPath(NSIndexPath(forItem: i, inSection: 0)) as WeaponCollectionViewCell
celli.checkImageView.hidden = true
}
if(cell.checkImageView.hidden){
cell.checkImageView.hidden = false
cell.checkImageView.image = UIImage(named: "check")
defaults.setObject(images[indexPath.row], forKey: "chancla")
} else {
cell.checkImageView.hidden = true
}
return true
}
}