swift uitableviewCell repeat subviews - uitableview

I have a UIButton in a uitableviewcell associated to a target:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("Cell") as! ProCell
cell.btn.tag = indexPath.row
cell.btn.addTarget(self, action: "buttonClicked:", forControlEvents: UIControlEvents.TouchUpInside)
return cell
}
This is the buttonClicked function:
func buttonClicked(sender:UIButton) {
let boton = sender as UIButton
let index = boton.tag
let buttonPosition: CGPoint = boton.convertPoint(CGPointZero, toView: self.tableView)
var indexPath: NSIndexPath = self.tableView.indexPathForRowAtPoint(buttonPosition)!
let cell = self.tableView.cellForRowAtIndexPath(indexPath) as! ProductoCell
cell.btn.setImage(UIImage (named: "rotacion-Null"), forState: UIControlState.Normal)
let indicador = UIActivityIndicatorView()
indicador.frame = CGRect(x: 0, y: 0, width: 25, height: 25)
indicador.color = UIColor(red: 153.0/255.0, green: 0.0, blue: 0.0, alpha: 1.0)
indicador.startAnimating()
cell.btn.addSubview(indicador)
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
let datosEd = ed.search(product)
dispatch_async(dispatch_get_main_queue(), {
//update UI in main thread once the loading is completed.
indicador.stopAnimating()
indicador.hidesWhenStopped = true
let label2 = UILabel(frame: CGRect(x: 15 , y: -5, width: 16, height: 16))
label2.textAlignment = NSTextAlignment.Center
label2.font = UIFont.boldSystemFontOfSize(13.0)
label2.backgroundColor = UIColor (red: 0.85, green: 0.20, blue: 0.33, alpha: 1.0)
label2.textColor = UIColor.whiteColor()
label2.layer.masksToBounds = true
label2.layer.cornerRadius = 8
let rowData = datosEd[0] as! NSDictionary
if rowData["art"] as! String == "No Results" {
label2.text = "0"
cell.contentView.addSubview(label2)
cell.btn.setImage(UIImage (named: "ed-25G"), forState: UIControlState.Normal)
} else {
label2.text = String(datosEd.count)
cell.btn.addSubview(label2)
cell.btn.setImage(UIImage (named: "ed-25R"), forState: UIControlState.Normal)
}
});
})
}
The problem is when I scroll down and scroll up back again, the subview(label2) is repeated in some cells.
Reading some responses think it has to do with the reuse of the cells, but I do not how to make the subviews are not repeated.
Some help, please... :-)

Related

How do I resize the header of a uitableview?

I have a uitableview
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let width = tableView.frame.width - CGFloat((start*2))
let headerView = UIView()
headerView.frame.origin.x = 0
headerView.frame.origin.y = -45
headerView.frame.size.width = tableView.frame.width
let desc = UILabel()
desc.frame.origin.x = label.frame.origin.x
desc.frame.origin.y = line.frame.maxY + 10
desc.frame.size.width = width
desc.numberOfLines = 0
desc.font = UIFont(name: "Lato-Regular", size: 17);
desc.textColor = UIColor(red: 0.53, green: 0.53, blue: 0.53, alpha: 1.00)
desc.text = self.data.desc
desc.backgroundColor = UIColor.clear
desc.textAlignment = .left
desc.adjustsFontForContentSizeCategory = true
if (loadMoreDesc) {
desc.sizeToFit()
} else {
desc.frame.size.height = 110
}
headerView.addSubview(desc)
let moreButtonDesc = UIButton(frame: CGRect(x: desc.frame.minX, y: desc.frame.maxY, width: 80, height: 15))
moreButtonDesc.contentVerticalAlignment = UIControl.ContentVerticalAlignment.center
moreButtonDesc.titleLabel?.textAlignment = .left
if (loadMoreDesc) {
moreButtonDesc.setTitle("Less", for: .normal)
} else {
moreButtonDesc.setTitle("More", for: .normal)
}
moreButtonDesc.titleLabel?.font = UIFont(name: "Lato-Regular", size: 15);
moreButtonDesc.setTitleColor(UIColor(red: 0.00, green: 0.48, blue: 1.00, alpha: 1.00), for: .normal)
moreButtonDesc.addTarget(self, action:#selector(self.expandDesc(sender:)), for: .touchUpInside)
headerView.addSubview(moreButtonDesc)
When people click on "More" button the description should expand and the height of the table view header should increase to fit the description (desc). How can I accomplish this? Here's my expandDesc function
#objc func expandDesc(sender: UIButton) {
loadMoreDesc = !loadMoreDesc
tableView.reloadData()
}
Please note that the description is of dynamic height. I won’t know the height to set for the header unless I know the height of the description.
please can you try this
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
if loadMoreDesc {
return 100
} else {
return 50.0
}
}

Unable to position UIElement(Switch) in Expandable table View Cell

Referring Above Image :
I want to place UISwitch in Subcell of cell4.
I did this code to do this inside cellForRowAt indexPath
if(indexPath.section == 3) {
if(indexPath.row == 0) {
let mySwitch = UISwitch()
let xpos = cell.frame.width - 60
let ypos = cell.frame.origin.y + 6
mySwitch.frame = CGRect(x: xpos, y: ypos, width:50, height: 26)
mySwitch.setOn(true, animated: false)
mySwitch.onTintColor = UIColor.init(red: 0.91, green: 0.30, blue: 0.24, alpha: 1.0)
mySwitch.addTarget(self, action: #selector(switchChanged(sender:)), for: UIControlEvents.valueChanged)
menuTableView.addSubview(mySwitch)
}
}
Now What happening is :
Initially Switch appearing on cell 1 when table view loads. After expanding and collapsing cell4 once , it appears at submenu of cell4. How to resolve this incorrect position issue?
You should append your switch to your cell instead of the tableView.

Last Button in UIScrollView add target doesn't effect

I have a list of category add I created buttons for each category in a scroll view
and a last button is ALL button for all products. But some how it didn't have any action I added.
this is my code
First I make a function to create buttons to add to view
func catButtonView(buttonSize:CGSize) -> UIView {
let buttonView = UIView()
buttonView.backgroundColor = UIColor(colorLiteralRed: 1, green: 1, blue: 1, alpha: 0)
buttonView.frame.origin = CGPoint(x: 0,y: 0)
let padding = CGSize(width:0, height:0)
buttonView.frame.size.width = (buttonSize.width + padding.width) * CGFloat(categories.count)
buttonView.frame.size.height = (buttonSize.height + 2.0 * padding.height )
//add buttons to the view
var buttonPosition = CGPoint(x:padding.width * 0.5, y:padding.height)
let buttonIncrement = buttonSize.width + padding.width
let hueIncrement = 1.0 / CGFloat(categories.count)
var newHue = hueIncrement
for i in 0...(categories.count) {
let button = UIButton.init(type: .custom) as UIButton
button.frame.size = buttonSize
button.frame.origin = buttonPosition
button.setBackgroundImage(R.image.button(), for: .normal)
button.setBackgroundImage(R.image.button_selected(), for: .selected)
if(i==categories.count) {
button.setTitle("ALL", for: .normal)
} else {
button.setTitle(categories[i].name, for: .normal)
}
button.setTitleColor(UIColor.white, for: .normal)
buttonPosition.x = buttonPosition.x + buttonIncrement
newHue = newHue + hueIncrement
button.tag = i+1
button.addTarget(self, action: #selector(catButtonPressed(sender:)), for: .touchUpInside)
buttonView.addSubview(button)
}
return buttonView
}
this is action func
func catButtonPressed(sender:UIButton){
print(sender.tag)
if(self.selectedCat != sender.tag-1) {
let lastBtn = catScrollView.viewWithTag(selectedCat+1) as? UIButton
lastBtn?.setBackgroundImage(R.image.button(), for: .normal)
self.selectedCat = sender.tag-1
self.itemsCollection.reloadData()
sender.setBackgroundImage(R.image.button_selected(), for: .normal)
}
}
then add to scroll view
let catScrollingView = catButtonView(buttonSize: CGSize(width: 200.0, height:50.0))
catScrollView.contentSize = catScrollingView.frame.size
catScrollView.subviews.forEach({ $0.removeFromSuperview() })
catScrollView.addSubview(catScrollingView)
catScrollView.showsHorizontalScrollIndicator = true
catScrollView.indicatorStyle = .default
self.itemsCollection.reloadData()
Anyone know what I missed?
It is because the if statement in your catButtonPressed function is false with the last button's tag, which makes the code inside never be executed.
Let's say you have 5 categories so your categories.count = 5. So your self.selectedCat ranges from 0 to 4. In your for i in 0...(categories.count) the last button's tag is button.tag = 5
Now in your catButtonPressed function. If the last button is the last category, then your self.selectedCat will be 4 and sender.tag will be 5
func catButtonPressed(sender:UIButton){
print(sender.tag)
if(4 != 5-1) {
// Any code in here will never be executed because 4 != 4 is false
}
}

UITableView mixing values because of reusable cells

I have a problem when I scroll in my tableview which contains elements that can be scrolled horizontal it is mixing the values.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
var cell : RoundWorkoutCell! = tableView.dequeueReusableCellWithIdentifier("Cell") as! RoundWorkoutCell
let tmpCell = cell
print(tmpCell)
if(cell == nil)
{
cell = NSBundle.mainBundle().loadNibNamed("Cell", owner: self, options: nil)[0] as! RoundWorkoutCell;
}
let exerviseName = RoundLabels[indexPath.row]
if(indexPath.row == 0){
for countMe in 0..<self.round_1_exercises.count {
if(countMe<1){
roundPosition1.append(5)
}else{
roundPosition1.append(115+roundPosition1[countMe-1])
}
scrollerSize = 115+roundPosition1[countMe]
}
}else if(indexPath.row == 1){
for countMe in 0..<self.round_2_exercises.count {
if(countMe<1){
roundPosition2.append(5)
}else{
roundPosition2.append(115+roundPosition2[countMe-1])
}
scrollerSize = 115+roundPosition2[countMe]
}
}else if(indexPath.row == 2){
for countMe in 0..<self.round_3_exercises.count {
if(countMe<1){
roundPosition3.append(5)
}else{
roundPosition3.append(115+roundPosition3[countMe-1])
}
scrollerSize = 115+roundPosition3[countMe]
}
}......
cell.RoundExercise_Cell_ScrollView.contentSize = CGSizeMake(CGFloat(scrollerSize),115)
cell.RoundExercise_Cell_ScrollView.showsHorizontalScrollIndicator = true
cell.RoundExercise_Cell_ScrollView.indicatorStyle = .Default
if(indexPath.row==0){
for index in 0..<self.round_1_exercises.count {
print("Round position 1 \(self.roundPosition1[index])")
var imageView : UIImageView
imageView = UIImageView(frame:CGRect(x:roundPosition1[index],y: 5, width:110, height: 110 ))
imageView.backgroundColor = UIColor.whiteColor()
cell.RoundExercise_Cell_ScrollView.addSubview(imageView)
let label1: UILabel = UILabel()
label1.frame = CGRect(x:roundPosition1[index],y: 5, width:110, height: 20 )
label1.textColor = UIColor(red:17/255.0, green: 22/255.0, blue: 40/255.0, alpha:1.0)
label1.textAlignment = NSTextAlignment.Center
label1.font = UIFont(name: "OpenSans-CondensedLight", size: 14)
label1.text = exerciseInfo.exercise_name(self.round_1_exercises[index] as! String)
cell.RoundExercise_Cell_ScrollView.addSubview(label1)
let frame1 = CGRect(x:roundPosition1[index]+10,y:25, width:90, height: 90 )
let button = UIButton(frame: frame1)
button.backgroundColor = UIColor.redColor()
button.setBackgroundImage(UIImage(named: (self.round_1_exercises[index] as? String)!) as UIImage?, forState: .Normal)
button.setTitleColor(UIColor.blackColor(), forState: .Normal)
button.setTitle(self.round_1_exercises[index] as? String, forState: .Normal)
button.setTitleColor(UIColor(red:0/255,green:0/255,blue:0/255,alpha:0.0), forState: .Normal)
button.addTarget(self, action: "buttonClick:", forControlEvents: .TouchUpInside)
cell.RoundExercise_Cell_ScrollView.addSubview(button)
let label: UILabel = UILabel()
label.frame = CGRect(x:roundPosition1[index],y: 115, width:110, height: 20 )
label.font = UIFont(name: "OpenSans", size: 14)
label.textColor = UIColor.whiteColor()
label.textAlignment = NSTextAlignment.Center
label.text = self.round_1_decoration[index] as? String
cell.RoundExercise_Cell_ScrollView.addSubview(label)
}
}else if(indexPath.row == 1){
for index in 0..<self.round_2_exercises.count {
print("Round position 2 \(self.roundPosition2[index])")
var imageView : UIImageView
imageView = UIImageView(frame:CGRect(x:roundPosition2[index],y: 5, width:110, height: 110 ))
imageView.backgroundColor = UIColor.whiteColor()
cell.RoundExercise_Cell_ScrollView.addSubview(imageView)
let label1: UILabel = UILabel()
label1.frame = CGRect(x:roundPosition2[index],y: 5, width:110, height: 20 )
label1.textColor = UIColor(red:17/255.0, green: 22/255.0, blue: 40/255.0, alpha:1.0)
label1.textAlignment = NSTextAlignment.Center
label1.font = UIFont(name: "OpenSans-CondensedLight", size: 14)
label1.text = exerciseInfo.exercise_name(self.round_2_exercises[index] as! String)
cell.RoundExercise_Cell_ScrollView.addSubview(label1)
let frame1 = CGRect(x:roundPosition2[index]+10,y:25, width:90, height: 90 )
let button = UIButton(frame: frame1)
button.backgroundColor = UIColor.redColor()
button.setBackgroundImage(UIImage(named: (self.round_2_exercises[index] as? String)!) as UIImage?, forState: .Normal)
button.setTitleColor(UIColor.blackColor(), forState: .Normal)
button.setTitle(self.round_2_exercises[index] as? String, forState: .Normal)
button.setTitleColor(UIColor(red:0/255,green:0/255,blue:0/255,alpha:0.0), forState: .Normal)
button.addTarget(self, action: "buttonClick:", forControlEvents: .TouchUpInside)
cell.RoundExercise_Cell_ScrollView.addSubview(button)
let label: UILabel = UILabel()
label.frame = CGRect(x:roundPosition2[index],y: 115, width:110, height: 20 )
label.font = UIFont(name: "OpenSans", size: 14)
label.textColor = UIColor.whiteColor()
label.textAlignment = NSTextAlignment.Center
label.text = self.round_2_decoration[index] as? String
cell.RoundExercise_Cell_ScrollView.addSubview(label)
}
}.....
cell.RoundExercise_Cell_Label.text = exerviseName
return cell as RoundWorkoutCell
}
Here is the custom cell class
class RoundWorkoutCell: UITableViewCell {
#IBOutlet var RoundExercise_Cell_Label: UILabel!
#IBOutlet var RoundExercise_Cell_ScrollView: UIScrollView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
self.RoundExercise_Cell_Label.text = ""
self.RoundExercise_Cell_ScrollView.contentSize = CGSizeMake(CGFloat(0),115)
}
I have placed this thread before but no one answered.I need to fix this.I have finished my whole app and this is left.I know that i have to use somehow prepareForReuse() but am not sure how,or if i could disable this reusable cells.
Thanks
The cells are reused to save on memory, this means that you need to recycle them properly to stop old data from being shown. You can do this by adding the prepareForReuse() function into your tableviewCell. In here you will need to set image outlets to be empty i.e by setting it to UIImage(). You will need to do the same with all outlets. This will ensure that old data that is not relevant will not be shown.
Example:
override func prepareForReuse() {
//myOutletName = myNilValue
super.prepareForReuse()
}
If you don't want to reuse cells, you can simply remove the call to dequeueReusableCellWithIdentifier. Try replacing these lines:
var cell : RoundWorkoutCell! = tableView.dequeueReusableCellWithIdentifier("Cell") as! RoundWorkoutCell
let tmpCell = cell
print(tmpCell)
if(cell == nil)
{
cell = NSBundle.mainBundle().loadNibNamed("Cell", owner: self, options: nil)[0] as! RoundWorkoutCell;
}
With this:
cell = NSBundle.mainBundle().loadNibNamed("Cell", owner: self, options: nil)[0] as! RoundWorkoutCell;
This approach doesn't reuse cells and will be less performant and will leak memory.
A better approach would be to construct the cells once and then reuse them, instead of rebuilding them in cellForRowAtIndexPath method. For example, if you design the cells in the NIB (as you are doing now), there's no need to add buttons and labels again by code, you can simply change the contents and hide those that are not needed.
Then, on prepareForReuse (or even at the beginning of cellForRowAtIndexPath), you reset the content of the row to the initial state.
class RoundWorkoutCell: UITableViewCell {
#IBOutlet var RoundExercise_Cell_Label: UILabel!
#IBOutlet var RoundExercise_Cell_ScrollView: UIScrollView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
self.RoundExercise_Cell_Label.text = ""
self.RoundExercise_Cell_ScrollView.contentSize = CGSizeMake(CGFloat(0),115)
}
override func prepareForReuse() {
//myOutletName = myNilValue
self.RoundExercise_Cell_Label.text = ""
self.RoundExercise_Cell_ScrollView.contentSize = CGSizeMake(CGFloat(0),115)
for subview in RoundExercise_Cell_ScrollView.subviews {
print(subview)
subview.removeFromSuperview()
}
super.prepareForReuse()
}
}
#Swinny89 was at right point thank you for that, but I can add more detail about prepareForReuse method. If you remove all your reusing cell data in that method, the performance will reduce. On the other hand, you can hide your variables in prepareForReuse method, and make them visible in your cell init method.
For example as the way I did:
override func prepareForReuse() {
if(commentLabels != nil) {
for item in commentLabels {
item.hidden = true
}
}
super.prepareForReuse()
}
In other method I make the visible with if check:
if(commentLabels == nil) {
// creating new labels and adding to commentLabels
} else { // it means reuse cell data and it has been hidden
// hidden = false
for item in commentLabels {
item.hidden = false
}
}

custom UITableViewCell exception

What can it be?
Failed to set (identifier) user defined inspected property on (UIView): [ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key identifier.
On iOS 8 it works, but spamming in debugger, in prior versions it crash app.
All connections in interface builder i checked and reconnected.
My code cellForRowAtIndexPath:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier(self.identifier, forIndexPath: indexPath) as PostCell
cell.backgroundColor = UIColor.clearColor()
cell.likeButton.setBackgroundImage(UIImage(named: "post_like_active"), forState: UIControlState.Selected)
cell.dislikeButton.setBackgroundImage(UIImage(named: "post_dislike_active"), forState: UIControlState.Selected)
var storageManager: PostStorageManager = PostStorageManager.sharedManager()
var model: PostModel = storageManager.storageObjects()[indexPath.row] as PostModel
cell.likeButton.selected = model.likeManager.likeState!.liked
cell.dislikeButton.selected = model.likeManager.likeState!.disliked
cell.textView.text = model.text
cell.textView.font = UIFont(name: "HelveticaNeue-Light", size: fontSize)!
cell.textView.contentInset = UIEdgeInsets(top: self.contentInsetTop, left: 0, bottom: 0, right: 0)
cell.likeLabel.text = String(format: "%#", model.amountOfLikes)
cell.dislikeLabel.text = String(format: "%#", model.amountOfDislikes)
var date: NSDate = model.date
cell.timeLabel.text = date.timeAgo()
var tapRecog: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "tapOccure:")
tapRecog.numberOfTapsRequired = 1
cell.textView.addGestureRecognizer(tapRecog)
var isMan = model.isMan.boolValue
cell.trollfaceImage.image = UIImage(named: String(format: "%#_%i", isMan ? "man" : "woman", model.experiance.integerValue))
var manColor = UIColor(red: 41/255, green: 86/255, blue: 115/255, alpha: 1)
var womanColor = UIColor(red: 206/255, green: 68/255, blue: 96/255, alpha: 1)
cell.ageLabel.textColor = isMan ? manColor : womanColor
cell.ageLabel.text = String(format: "%i", model.age.integerValue)
cell.textView.userInteractionEnabled = false
return cell
}
Check all views in the cell, I think you put your identifier in the wrong place.

Resources