Reusable UICollectionViewCell not changing UIImageView property (showing duplicates) - swift

I have a UICollectionView with a reusable cell that contains a UIImageView but the collection view displays the same image in the image view for each cell item in the collection.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let path = indexPath.item
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "friendAvatar", for: indexPath) as! AvatarCollectionViewCell
cell.avatarView.image = friends[path].userAvatar
return cell
}
class AvatarCollectionViewCell: UICollectionViewCell {
var avatarView = UIImageView()
override init(frame: CGRect) {
super.init(frame: frame)
prepareForReuse()
config()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func prepareForReuse() {
avatarView.image = nil
avatarView.removeFromSuperview()
}
func config() {
avatarView.frame = CGRect(x: 0, y: 0, width: 64, height: 64)
avatarView.layer.cornerRadius = 64 / 4
avatarView.clipsToBounds = true
avatarView.contentMode = .scaleAspectFill
addSubview(avatarView)
}
}

First of all, you are removing the image view from its superview in prepareForReuse() but you never add it back. init() will not be called when reusing a cell, and neither will config(). Unless you have a specific reason for it, you shouldn't need to remove the image view from its superview. Just setting its image to nil should be enough.
Also, set a breakpoint and verify that friends[path].userAvatar returns a valid path to an image.

Related

ScrollTo indexPath of a Collection View inside Collection view Cell (Nested CollectionView)

I am using a collection view inside another collection view cell. Now I want to scroll to an indexPath of inner collection View. Help me if you know this.
Based on the above image, I want to auto scroll the collection view to the red cell which is inside the nested collection view. Assume the nested collection view is a section in the Main collectionView.
Try using a reference to this collection view.
Say that you UICollectionView containing the inner UICollectionView is named YourInnerCollectionViewCell, it will looks something like:
let innerCollectionViewCellId = "innerCollectionViewCellId"
class MainCollectionView : UICollectionViewController {
var innerCollectionViewCell: YourInnerCollectionViewCell?
override func viewDidLoad() {
super.viewDidLoad()
collectionView?.delegate = self
collectionView?.dataSource = self
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
switch indexPath.row {
case 2:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: innerCollectionViewCellId, for: indexPath) as! YourInnerCollectionViewCell
self.innerCollectionViewCell = cell
return cell
default:
// return other cell
}
}
....
}
class YourInnerCollectionViewCell: UICollectionViewCell {
override init(frame: CGRect){
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Now that you have a reference to this cell you can access the collectionView in it and perform the scrollTo.
Hope it help.

Complex Image based Button Layout

I'm fairly new to programming in general, I'm trying to figure out how to create numerous buttons in a complex layout. My layout is basically a transparent PNG of a body cut into about 24 sections and I want each segment of the body to be a separate button.
I've tried a few layouts in the view controller. Setting up a ton of buttons overlaying an image (couldn't keep the layout straight when launching in the simulator) and I've tried giving the buttons images, I've tried large image sized buttons but I could only use the top most button.
Is there any way to do this, or is it going to need code to be doable?
UICollectionViewController or UICollectionView is a better choice for you. You can set the UICollectionViews background image and regard the cells as your buttons.
Here is a quick example.
import UIKit
class Collection: UICollectionViewController {
private let cellId = "cell"
override init(collectionViewLayout layout: UICollectionViewLayout) {
if let l = layout as? UICollectionViewFlowLayout{
l.minimumInteritemSpacing = 0
l.sectionInset = UIEdgeInsetsZero
l.scrollDirection = .Vertical
l.footerReferenceSize = CGSize.zero
l.headerReferenceSize = CGSize.zero
let screenWidth = UIScreen.mainScreen().bounds.width
let itemWidth = CGFloat(Int(screenWidth/4))
l.itemSize = CGSize(width: itemWidth, height: itemWidth)
}
super.init(collectionViewLayout: layout)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.whiteColor()
collectionView?.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: cellId)
}
}
extension Collection{
override func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 4
}
override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 4
}
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(cellId, forIndexPath: indexPath)
cell.backgroundColor = UIColor.redColor()
return cell
}
}
If you want to add touch action to a cell.
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
}

UITableViewCell with a UIView subclass creates multiple layers on cell

I have an custom UITableViewCell created with (.xib) and have UIView subclass instance inside cell created from code
table delegate method :
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("CustomCellOne", forIndexPath: indexPath) as! CustomOneCell
let woView = ModuleView(frame: CGRect(x: 10, y: 10, width: 400, height: 400))
woView.addBehavior(self.modulesForSubjects[indexPath.row])
// remove subviews
for subview in cell.subviews{
subview.removeFromSuperview();
}
// then add your view
cell.wiView = woView
return cell
}
my full UIView subclass :
class ModuleView: UIView {
override init (frame : CGRect) {
super.init(frame : frame)
}
convenience init () {
self.init(frame:CGRect.zero)
}
required init(coder aDecoder: NSCoder) {
fatalError("This class does not support NSCoding")
}
func addBehavior (ArrayOfmodulesForSubject: [SubjectsModules]) {
var number :CGFloat = 30
var number2 :CGFloat = 30
print(ArrayOfmodulesForSubject.count)
for (i, index) in ArrayOfmodulesForSubject.enumerate() {
let yourLabel1 = UILabel(frame: CGRectMake(number, 40 , 35 , 30))
let yourLabel2 = UILabel(frame: CGRectMake(number2, 60 , 140 , 30))
yourLabel1.textColor = UIColor.whiteColor()
yourLabel1.backgroundColor = UIColor.redColor()
yourLabel1.text = String(index.score)
yourLabel2.textColor = UIColor.whiteColor()
yourLabel2.backgroundColor = UIColor.blackColor()
yourLabel2.text = index.date
self.addSubview(yourLabel1)
self.addSubview(yourLabel2)
number += 30
number2 += 70
}
}
here is what i get after some scrolling:
UPDATE rnsjtngus solution, unfortunately also didn't helped (maybe im doing something wrong)
class CustomOneCell: UITableViewCell {
var arr = [SubjectsModules]()
#IBOutlet weak var wiView: ModuleView!
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?){
// Initialize your custom cell
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.setupWoView(self.arr)
}
override func awakeFromNib() {
print("AWAKED FROM NIB")
for subview in subviews{
subview.removeFromSuperview()
if superview != nil {
superview!.removeFromSuperview()
}
}
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func setupWoView(arrayOfmodulesForSubject: [SubjectsModules]) {
let woView = ModuleView(frame: CGRect(x: 10, y: 10, width: 400, height: 400))
woView.backgroundColor = UIColor.blueColor()
self.addSubview(woView)
}
}
Simple but, bad solution is
just remove subviews from cell before you add your own view
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("CustomCellOne", forIndexPath: indexPath) as! CustomOneCell
let woView = ModuleView(frame: CGRect(x: 10, y: 10, width: 400, height: 400))
woView.addBehavior(self.modulesForSubjects[indexPath.row])
// remove subviews
for subview in cell.subviews{
subview.removeFromSuperview();
}
// then add your view
cell.addSubview(woView)
return cell
}
When you call dequeue the method dequeues an existing cell if one is available or creates a new one using the class or nib if not.
This means you may well get one that has already had a subview added to it and when you dequeue it again your code would then add a second one. You need to start by removing any existing subviews.

custom UICollectionViewCell class recognize but not working

I implemented a custom class for my collectionview cells.
The class recognize the attributes like labels but when i run my app the label text doesn't display.
Class is register like this :
self.collectionView!.registerClass(StatsCollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)
here is the init method of the custom cell class:
var textlabel = UILabel()
override init(frame: CGRect) {
let width = frame.size.width
let height = frame.size.height
textlabel = UILabel(frame: CGRectMake(0, 0, width,height))
super.init(frame: frame)
}
and the implementation :
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! StatsCollectionViewCell
// Configure the cell
cell.textlabel.text = "test"
return cell
}
Could someone point me to my mistake please, i'm a bit lost here, cannot see what's wrong.
Note that i can use the cell properties (meaning the cell is in fact here).
You didn't put textlabel in a view.
override init(frame: CGRect) {
let width = frame.size.width
let height = frame.size.height
textlabel = UILabel(frame: CGRectMake(0, 0, width,height))
super.init(frame: frame)
addSubview(textlabel) // add text label to view
}

Why can't I change custom view background in cell of UICollectionView

I have a UICollectionView and a custom UICollectionViewCell.
The UICollectionViewCell contains a custom UIView.
I need to change the color of the UIView according to a property in my array.
I have created the custom UIView in the storyboard, assigned appropriate class to it and even a tag.
I am trying to change the color of the my custom circleView in cellForItemAtIndexPath
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
var cell = collectionView.dequeueReusableCellWithReuseIdentifier("circleCell", forIndexPath: indexPath) as! BRGameCollectionViewCell
var circle = BRGameManager.sharedInstance.gameArray[indexPath.section][indexPath.row] as BRCircle!
cell.circleView.circleColor = UIColor.redColor()
return cell
}
I have tried it even with getting the circleView via tag but it doesn't work either.
What Am I doing wrong?
My custom view Class looks like this:
class BRCircleView: UIView {
var circleSize : CGFloat = 10
var circleColor : UIColor!
override init(frame: CGRect) {
if( frame == CGRectZero){
var newFrame = CGRectMake(0, 0, self.circleSize, self.circleSize)
}
self.circleColor = UIColor(rgba: GlobalConstants.colors.hexColorGreen)
super.init(frame: frame)
}
convenience init(frame: CGRect, circleColor : UIColor){
self.init(frame: frame)
self.circleColor = circleColor
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func drawRect(rect: CGRect) {
self.layer.cornerRadius = self.frame.size.width/2
self.clipsToBounds = true
self.backgroundColor = self.circleColor
}
}
If you want to reflect your circleView's background color change,you need to redraw your view's content.Use setNeedsDisplay method of UIView would do this trick.More about setNeedsDisplay
So before returning cell, add this line of code.
...
cell.circleView.circleColor = UIColor.redColor()
cell.circleView.setNeedsDisplay() // add this line.
return cell