I'm getting a weird jerking motion whenever I reload my row and scroll up. It's fine if it's scrolling down, but scrolling back up is causing a horrible jerking effect, rendering the app useless.
I've attached the code for not only the cellforrowatindex path, but the buttons as well.
cell for row:
override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!, object: PFObject!) -> PFTableViewCell! {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! TableViewCell
cell.nopebutton.tag = indexPath.row
cell.nicebutton.tag = indexPath.row
cell.killText.text = object.valueForKey("text") as! String
cell.layoutMargins = UIEdgeInsetsZero
cell.killText.numberOfLines = 0
let score = object.valueForKey("count") as! Int
cell.count.text = "\(score)"
if cell.count.text == "\(0)"
{
cell.count.textColor = UIColor.grayColor()
}
if cell.count.text > "\(0)"
{
cell.count.textColor = UIColor(red: 42.0/255, green: 204.0/255, blue: 113.0/255, alpha: 1)
}
if cell.count.text < "\(0)"
{
cell.count.textColor = UIColor(red: 231.0/255, green: 76.0/255, blue: 50.0/255, alpha: 1)
}
if cell.count.text == "\(50)"
{
cell.count.textColor = UIColor(red: 249.0/255, green: 191.0/255, blue: 59.0/255, alpha: 1)
}
if let dict : NSDictionary = NSUserDefaults.standardUserDefaults().objectForKey("userNiceNopeDictionary") as? NSDictionary {
cell.nicebutton.enabled = true
cell.nopebutton.enabled = true
if let nice = dict[object.objectId] as? Bool{
if nice {
cell.nicebutton.enabled = false
}
else {
cell.nopebutton.enabled = false
}
}
}
let dateUpdated = object.createdAt as NSDate
let dateFormat = NSDateFormatter()
dateFormat.dateFormat = "h:mm a"
cell.time.text = (NSString(format: "%#", dateFormat.stringFromDate(dateUpdated)) as String) as String
let replycnt = object.objectForKey("replies") as! Int
if cell.count.text == "\(-10)"
{
object.deleteInBackground()
}
return cell
}
buttons
#IBAction func topButton(sender: AnyObject) {
var button = sender as! UIButton
// var view = button.superview
//
// var otherButton = view?.viewWithTag(102) as! UIButton
// var label = button.superview!.viewWithTag(110) as! UILabel
// otherButton.enabled = true
// button.enabled = false
var rowNumber = button.tag
var mutableDict = NSMutableDictionary()
if let dict = NSUserDefaults.standardUserDefaults().objectForKey("userNiceNopeDictionary") {
mutableDict = dict.mutableCopy() as! NSMutableDictionary
}
let obj = self.objects[rowNumber] as! PFObject
mutableDict.setValue(true, forKey: obj.objectId)
NSUserDefaults.standardUserDefaults().setObject(mutableDict, forKey: "userNiceNopeDictionary")
NSUserDefaults.standardUserDefaults().synchronize()
let hitPoint = sender.convertPoint(CGPointZero, toView: self.tableView)
let hitIndex = self.tableView.indexPathForRowAtPoint(hitPoint)
let object = objectAtIndexPath(hitIndex)
object.incrementKey("count")
//label.text = object.objectForKey("count") as! String
// self.tableView.reloadData()
object.save()
self.tableView.reloadRowsAtIndexPaths([hitIndex!], withRowAnimation: UITableViewRowAnimation.None)
}
#IBAction func bottomButton(sender: AnyObject) {
var button = sender as! UIButton
var rowNumber = button.tag
var mutableDict = NSMutableDictionary()
if let dict = NSUserDefaults.standardUserDefaults().objectForKey("userNiceNopeDictionary") {
mutableDict = dict.mutableCopy() as! NSMutableDictionary
}
let obj = self.objects[rowNumber] as! PFObject
mutableDict.setValue(false, forKey: obj.objectId)
NSUserDefaults.standardUserDefaults().setObject(mutableDict, forKey: "userNiceNopeDictionary")
NSUserDefaults.standardUserDefaults().synchronize()
let hitPoint = sender.convertPoint(CGPointZero, toView: self.tableView)
let hitIndex = self.tableView.indexPathForRowAtPoint(hitPoint)
let object = objectAtIndexPath(hitIndex)
object.incrementKey("count", byAmount: -1)
self.tableView.reloadRowsAtIndexPaths([hitIndex!], withRowAnimation: UITableViewRowAnimation.None)
object.save()
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier == "killDetail"){
let indexPath = self.tableView.indexPathForSelectedRow()
let obj = self.objects[indexPath!.row] as! PFObject
let detailVC = segue.destinationViewController as! DetailViewController
detailVC.kill = obj
}
}
}
I'm under the impression that there's an issue in my heights so I've included that code as well.
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.separatorInset = UIEdgeInsetsZero
self.tableView.separatorInset = UIEdgeInsetsMake(0, 0, 0, 0)
self.tableView.separatorColor = UIColor(red: 236.0/255, green: 240.0/255, blue: 241.0/255, alpha: 1)
navigationController?.tabBarController?.tabBar.hidden = true
tabBarController?.tabBar.hidden = true
self.tableView.estimatedRowHeight = 60
self.tableView.rowHeight = UITableViewAutomaticDimension
locationManager.desiredAccuracy = 1000
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
}
I can't for the life of me figure out what's going on causing this jerk. Like I said I think it might have to do with the automaticdimension in the row height, but when I change that the issue is still apparent.
Don't read that dictionary from user defaults every time you dequeue a cell. Do it once, outside of tableView(cellForRowAtIndexPath:. Do it in viewDidLoad or something. Picking out an element from the dictionary once it's in memory is fine though... You just don't want to read from disk (or flash, I guess) every time a cell is dequeued.
If the dictionary is being changed, for any reason, in other places and you want to maintain a consistent state, read the dictionary in once and just pass it around between controllers/view controllers (through, e.g. prepareForSegue) and write it to user defaults when it's changed.
The date formatter is probably not that big or complex of an object to make, but you only need to make one once, and then can reuse it, so I suggest you only create one once too.
edit: If you have a problem just scrolling up, it could be that the estimated row height doesn't match the actual row height. Try removing the estimated height.
Related
I'm creating an app where users will send messages. I have the messenger working but the front end isn't updating instantly when a new comment is entered. You have to back out and then come back in to get it to show up.
I've researched examples and got the code from a course I took on udemy. I've tried with tableview.reload() and tableview.insertrows(). I'm sending the data using JSON to PHP and MySQL. It's showing in the db immediately but my code has it updating the UI first, it's just not working.
let messagetext = replyTxt.text.trimmingCharacters(in: .whitespacesAndNewlines)
hhmessages.insert(messagetext as AnyObject, at: hhmessages.endIndex)
let indexPath = IndexPath(row: self.hhmessages.count - 1, section: 0)
// update tableView
tableView.beginUpdates()
tableView.insertRows(at: [indexPath], with: .automatic)
tableView.endUpdates()
// scroll to the bottom
tableView.scrollToRow(at: indexPath, at: .bottom, animated: true)
// empty textView and reload it
replyTxt.text = ""
textViewDidChange(replyTxt)
let recipient = messages["username"] as! String
let rid = String(describing: messages["recipient_id"]!)
let uuid = messages["uuid"] as! String
puuid = UUID().uuidString
// prepare request
let url = URL(string: "http://localhost/messagepost.php")!
let body = "sender_id=\(user_id)&sender=\(username)&text=\(messagetext)&recipient_id=\(rid)&recipient=\(recipient)&uuid=\(uuid)&puuid=\(puuid)"
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = body.data(using: .utf8)
The code should instantly update the UITableView with the latest comment and then commit to the database. I've been trying for two days with no luck. Any help is welcomed.
UPDATE WITH TABLE SOURCE CODE
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return hhmessages.count
}
// Return cell to display on the tableView
// How many sections. Means numberOfSections * rows = view
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let colorSmoothGray = UIColor(red: 229/255, green: 229/255, blue: 234/255, alpha: 1)
let colorBrandBlue = UIColor(red: 148 / 255, green: 33 / 255, blue: 147 / 255, alpha: 1)
let pictureURL = hhmessages[indexPath.row]["uploadpath"] as? String
// no picture in the post
if pictureURL?.isEmpty == true {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! ConversationCell
cell.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi));
isLoading = true
let hhpost = hhmessages[indexPath.row]
let smimages = hhpost["path"] as? UIImage
let text = hhmessages[indexPath.row]["messagetext"] as! String
cell.messageLbl.text = text
cell.smavaImg.image = smimages
cell.messageLbl.textAlignment = .right
cell.messageLbl.backgroundColor = colorSmoothGray
cell.messageLbl.textColor = .black
cell.messageLbl.font = UIFont.preferredFont(forTextStyle: UIFontTextStyle.body)
cell.messageLbl.font?.withSize(25)
cell.messageLbl.clipsToBounds = true
// get main queue to this block of code to communicate back
DispatchQueue.main.async {
cell.messageLbl.sizeToFit()
tableView.transform = CGAffineTransform(rotationAngle: -CGFloat.pi)
cell.transform = CGAffineTransform(rotationAngle: CGFloat.pi)
}
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "PicCell", for: indexPath) as! PicConversationCell
cell.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi));
cell.smavaImg.image = smimages
//if let message = messageData {
for i in 0 ..< self.incoming.count {
// Confiture the constraints for cell
if self.incoming[indexPath.row] == 1 {
// Constraints
cell.lefBubbleConstraint.isActive = true
cell.rightBubbleConstraint.isActive = false
if cell.postpictureImg.image == nil {
cell.postpictureImg.backgroundColor = colorwhite
cell.postpictureImg.clipsToBounds = true
}
else {
cell.postpictureImg.backgroundColor = .clear
cell.postpictureImg.clipsToBounds = true
}
}
else if self.incoming[indexPath.row] == 0 {
// Constraints
cell.lefBubbleConstraint.isActive = false
cell.rightBubbleConstraint.isActive = true
if cell.postpictureImg.image == nil {
cell.postpictureImg.backgroundColor = colorwhite
cell.postpictureImg.clipsToBounds = true
}
else {
cell.postpictureImg.backgroundColor = .clear
cell.postpictureImg.clipsToBounds = true
}
}
// pictures logic
let pictureString = hhmessages[indexPath.row]["uploadpath"] as? String
let pictureURL = URL(string: pictureString!)!
// if there are still pictures to be loaded
if hhmessages.count != pictures.count {
URLSession(configuration: .default).dataTask(with: pictureURL) { (data, response, error) in
// downloaded
if let image = UIImage(data: data!) {
self.pictures.append(image)
DispatchQueue.main.async {
cell.postpictureImg.image = image
}
}
}.resume()
// cached picture
} else {
DispatchQueue.main.async {
cell.postpictureImg.image = self.pictures[indexPath.row]
}
}
}
return cell
}
}
Are you adding the element to what your numberOfRowsForSection calls? Before you call insertRows the data source needs to be update.
In my app I have to show multiple progress views in a single tableViewCell, the progress as per actual to goal and it showing correctly when cell is loaded for the first time as per image1
but after scrolling the table the cell is visible like image2.
The progress of the progress views is altered after scrolling the tableview. I have printed the progress values in cellForRowAt method and they are correct but the progress in progress view is being altered. I am setting the progressview progress in cellForRowAt method.
Can anybody help me to resolve this issue?
#Bhavin Kansagara here is my code in cellForRowAt method.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cellIdentifier = "myIdentifier"
var cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier) as? MyTableViewCell
if cell == nil {
tableView.register(UINib.init(nibName: "MyTableViewCell", bundle: nil), forCellReuseIdentifier: cellIdentifier)
cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier) as? MyTableViewCell
}
let myDict = self.myArray[indexPath.row]
let goalDict = myDict["goal"]!
let actualDict = myDict["actual"]!
for label in cell!.actualValueLabels {
switch label.tag {
case 0:
label.text = String(actualDict["value1"]!)
case 1:
label.text = String(actualDict["value2"]!)
case 2:
label.text = String(actualDict["value3"]!)
case 3:
label.text = String(actualDict["value4"]!)
case 4:
label.text = String(actualDict["value5"]!)
case 5:
label.text = String(actualDict["total"]!)
default:
break
}
}
for label in cell!.goalValueLabels {
switch label.tag {
case 0:
label.text = String(goalDict["value1"]!)
case 1:
label.text = String(goalDict["value2"]!)
case 2:
label.text = String(goalDict["value3"]!)
case 3:
label.text = String(goalDict["value4"]!)
case 4:
label.text = String(goalDict["value5"]!)
case 5:
label.text = String(goalDict["total"]!)
default:
break
}
}
let greenColor = UIColor(red: 146/255, green: 209/255, blue: 78/255, alpha: 1)
let yellowColor = UIColor(red: 1, green: 122/255, blue: 0, alpha: 1)
let value1Goal = goalDict["value1"]!
let value1Actual = actualDict["value1"]!
cell?.value1ProgressView.progressTintColor = value1Actual >= value1Goal ? greenColor : yellowColor
if value1Goal == 0 {
DispatchQueue.main.async {
cell?.value1ProgressView.setProgress(Float(value1Actual), animated: true)
}
} else {
DispatchQueue.main.async {
cell?.value1ProgressView.setProgress(Float(value1Actual)/Float(value1Goal), animated: true)
}
}
let value2Goal = goalDict["value2"]!
let value2Actual = actualDict["value2"]!
cell?.value2ProgressView.progressTintColor = value2Actual >= value2Goal ? greenColor : yellowColor
if value2Goal == 0 {
DispatchQueue.main.async {
cell?.value2ProgressView.setProgress(Float(value2Actual), animated: true)
}
} else {
DispatchQueue.main.async {
cell?.value2ProgressView.setProgress(Float(value2Actual)/Float(value2Goal), animated: true)
}
}
let value3Goal = goalDict["value3"]!
let value3Actual = actualDict["value3"]!
cell?.value3ProgressView.progressTintColor = value3Actual >= value3Goal ? greenColor : yellowColor
if value3Goal == 0 {
DispatchQueue.main.async {
cell?.value3ProgressView.setProgress(Float(value3Actual), animated: true)
}
} else {
DispatchQueue.main.async {
cell?.value3ProgressView.setProgress(Float(value3Actual)/Float(value3Goal), animated: true)
}
}
let value4Goal = goalDict["value4"]!
let value4Actual = actualDict["value4"]!
cell?.value4ProgressView.progressTintColor = value4Actual >= value4Goal ? greenColor : yellowColor
if value4Goal == 0 {
DispatchQueue.main.async {
cell?.value4ProgressView.setProgress(Float(value4Actual), animated: true)
}
} else {
DispatchQueue.main.async {
cell?.value4ProgressView.setProgress(Float(value4Actual)/Float(value4Goal), animated: true)
}
}
let value5Goal = goalDict["value5"]!
let value5Actual = actualDict["value5"]!
cell?.value5ProgressView.progressTintColor = value5Actual >= value5Goal ? greenColor : yellowColor
if value5Goal == 0 {
DispatchQueue.main.async {
cell?.value5ProgressView.setProgress(Float(value5Actual), animated: true)
}
} else {
DispatchQueue.main.async {
cell?.value5ProgressView.setProgress(Float(value5Actual)/Float(value5Goal), animated: true)
}
}
let totalGoal = goalDict["total"] as! Int
let totalActual = actualDict["count"]!
cell?.totalProgressView.progressTintColor = totalActual >= totalGoal ? greenColor : yellowColor
if totalGoal == 0 {
DispatchQueue.main.async {
cell?.totalProgressView.setProgress(Float(totalActual), animated: true)
}
} else {
DispatchQueue.main.async {
cell?.totalProgressView.setProgress(Float(totalActual)/Float(totalGoal), animated: true)
}
}
return cell!
}
else {
//another cells are used in other sections
}
}
here myArray = [[String: [String: Int]]]
Thanks in advance.
There is one way to handle this situations, You should try setting the different identifier for the cell's but that will affect your performance. after setting this approach, you should check for the performance of scrolling on your device.
let cellIdentifier = "myIdentifier_\(indexPath.section)_\(indexPath.row)"
var cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier) as? MyTableViewCell
if cell == nil {
tableView.register(UINib.init(nibName: "MyTableViewCell", bundle: nil), forCellReuseIdentifier: cellIdentifier)
cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier) as? MyTableViewCell
}
This is not the best approach, but can help avoid the repeating process issue.
Try and share results.
I am facing this issue and I am not getting any clear answer. I have a UITableView which works fine when it loads for the first time but when it scrolls, it is not selectable, didSelectRowAtIndexPath never gets a call. Also I've button in my cell, it's not clickable either. But I can still scroll tableview. This is my code :
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell : ContactTableViewCell = tableView.dequeueReusableCell(withIdentifier: "ContactCell") as! ContactTableViewCell
cell.selectionStyle = .none
cell.backgroundColor = UIColor.clear
cell.delegate = self
let randomNumber = Int(arc4random_uniform(UInt32(colorsArray!.count)))
if(!shouldUseFilteredResults) {
cell.setFilteredContents(_with: addressBookArray![indexPath.row], theme: themeStyle!, randomColor: colorsArray![randomNumber])
}
else {
cell.setFilteredContents(_with: filteredAddressBook[indexPath.row], theme: themeStyle!, randomColor: colorsArray![randomNumber])
cell.contactNameLabel.attributedText = self.highlightSearchResult(resultString: cell.contactNameLabel.text!)
}
return cell
}
In cell :
public func setFilteredContents (_with contact : [String : Any], theme : Theme, randomColor : UIColor)
{
contactDictionary = contact;
contactNameLabel.text = String(describing: contact["FullName"]!)
self.setTheme(theme: theme, randomColor: randomColor)
if (contact["ImageDataString"] != nil)
{
let imageData = Data(base64Encoded: contact["ImageDataString"] as! String)
let image = UIImage(data: imageData!)
let imageView = UIImageView(frame: thumbnailView.bounds)
imageView.contentMode = .scaleAspectFill
imageView.layer.masksToBounds = true
imageView.layer.cornerRadius = CGFloat(imageView.height()/2)
imageView.image = image
thumbnailView.addSubview(imageView)
}
else {
self.setThumbnail(fullName: contactNameLabel.text!)
}
}
private func setThumbnail(fullName : String)
{
let vibrancy = UIVibrancyEffect(blurEffect: UIBlurEffect(style: .light))
let backgroundView = UIVisualEffectView(effect: vibrancy)
backgroundView.frame = thumbnailView.bounds
thumbnailView.addSubview(backgroundView)
let thumbNailLabel = UILabel(frame: thumbnailView.bounds)
thumbNailLabel.font = UIFont.systemFont(ofSize: 13)
thumbNailLabel.textColor = UIColor.white
thumbNailLabel.textAlignment = .center
var initialLettersString = String()
let wordsArray = fullName.components(separatedBy: NSCharacterSet.whitespaces)
for word in wordsArray
{
if(word != "")
{
initialLettersString.append(String(describing: word.characters.first!))
}
}
if(initialLettersString.characters.count == 1)
{
initialLettersString = String(initialLettersString[..<initialLettersString.index(initialLettersString.startIndex, offsetBy: 1)]).uppercased()
}
if(initialLettersString.characters.count > 1)
{
initialLettersString = String(initialLettersString[..<initialLettersString.index(initialLettersString.startIndex, offsetBy: 2)]).uppercased()
}
thumbNailLabel.text = initialLettersString as String
backgroundView.contentView.addSubview(thumbNailLabel)
}
private func setTheme(theme : Theme, randomColor : UIColor)
{
let isContactFavorite = contactDictionary?[Constants.TTCIsContactFavoriteKey] as? Bool
thumbnailView.backgroundColor = randomColor
if(theme == Theme.Light)
{
contactNameLabel.textColor = UIColor.black
lineView.backgroundColor = UIColor.lightGray
if(!isContactFavorite!)
{
favoritesButton.setImage(UIImage(named: "favorite_dark.png"), for: .normal)
}
else
{
favoritesButton.setImage(UIImage(named: "favorite.png"), for: .normal)
}
}
else if(theme == Theme.Dark)
{
contactNameLabel.textColor = UIColor.white
lineView.backgroundColor = UIColor.gray
if(!isContactFavorite!)
{
favoritesButton.setImage(UIImage(named: "favorite_white.png"), for: .normal)
}
else
{
favoritesButton.setImage(UIImage(named: "favorite.png"), for: .normal)
}
}
for view in thumbnailView.subviews
{
view.removeFromSuperview()
}
}
Custom Cell :
What could be the issue?
This may also because of overriding default touch events with UITapRecognizers in the View Hierarchy
Remove any tap recognizers set to to UITableview Parent View
Thanks everyone for help. Issue was with SwipeCellKit which I was using for CustomCell. Removing it solved it!
You are doing everything right.
Just check your button frame does lies inside your cell.
Some times your cell height is less and button is outside the bounds of cell.
So I have a tableView with a set of buttons in each cell. These are the options for a user to vote from.
When a user presses an option, a chart loads that shows the poll results.
However, when I scroll down, the chart appears inexplicably on another tableView cell. None of the buttons in that cell were ever pressed. Additionally, the chart loads in the second cell with the data of the first. I have been stuck on this for hours and have no idea why that is.
EDIT: Here is the code for the tableView
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "pollCell") as! PollCell
let titled = titles[indexPath.row]
cell.configure(polltitled: titled, num: indexPath.row)
return cell
}
And here are the methods for the Poll Cell:
var ref = FIRDatabase.database().reference()
var options = [String]()
var counts = [Int]()
self.loadedChart = false
#IBOutlet weak var chart: HorizontalBarChartView!
func configure(polltitled: String, num: Int) {
self.pollTitle.text = polltitled
self.row = num
self.runRemove() { (success) -> Void in
if success {
if (loadedChart == false) {
self.loadChart()
}
}
else {
}
}
}
func runRemove(completion:(_ success: Bool) -> Void) {
self.pollTitle.tag = 999
self.chart.tag = 998
for object in self.contentView.subviews {
if ((object.tag != 999) && (object.tag != 998)) {
object.removeFromSuperview()
}
}
completion(true)
}
func loadChart(){
ref.child("poll").child(StaticVariables.currentEventQR).child(self.pollTitle.text!).observe(.value) { (snapshot: FIRDataSnapshot!) in
self.counts.removeAll()
self.options.removeAll()
for item in snapshot.children {
let childSnapshot = snapshot.childSnapshot(forPath: (item as AnyObject).key)
let option = childSnapshot.key
self.options.append(option)
}
self.loadCounts()
self.createButtons()
}
}
func loadCounts() {
for i in self.options {
self.ref.child("poll").child(StaticVariables.currentEventQR).child(self.pollTitle.text!).child(i).observe(.value) { (snapshot: FIRDataSnapshot!) in
for item in snapshot.children {
let childSnapshot = snapshot.childSnapshot(forPath: (item as AnyObject).key)
let countsValue = childSnapshot.value as? NSDictionary
let count = countsValue?["Counter"] as! Int
self.counts.append(count)
}
}
}
}
func createButtons() {
var i = 1
var height = 0
if ((self.pollTitle.text?.characters.count)! > 37){
height = 22
}
for option in self.options{
let btn: UIButton = UIButton(frame: CGRect(x: Int(self.contentView.frame.size.width - 320)/2, y: 59+60*(i-1)+height, width: 320, height: 33))
if ((i)%2 == 1){
btn.backgroundColor = UIColor.init(red: 253/255, green: 185/255, blue: 39/255, alpha: 1.0)
} else {
btn.backgroundColor = UIColor.init(red: 0/255, green: 107/255, blue: 182/255, alpha: 1.0)
}
btn.addTarget(self, action: #selector(PollCell.optionOne(_:)), for: .touchUpInside)
btn.tag = i
self.contentView.addSubview(btn)
btn.setTitle(option, for: .normal)
i += 1
}
}
#IBAction func optionOne(_ sender: UIButton) {
self.loadedChart = true
delegate.refresh(self.row)
self.options.reverse()
self.counts.reverse()
self.setChart(dataPoints: self.options, values: self.counts)
ref.child("poll").child(StaticVariables.currentEventQR).child(pollTitle.text!).child((sender.titleLabel?.text!)!).observeSingleEvent(of: .value, with: { (snapshot) in
let item = snapshot.children.allObjects[0]
let childSnapshot = snapshot.childSnapshot(forPath: (item as AnyObject).key)
let responseID = childSnapshot.key
let reponseValue = childSnapshot.value as? NSDictionary
var response = reponseValue?["Counter"] as! Int
response += 1
self.ref.child("poll").child(StaticVariables.currentEventQR).child(self.pollTitle.text!).child((sender.titleLabel?.text!)!).child("count").setValue(["Counter": response])
})
self.contentView.bringSubview(toFront: self.chart)
}
func setChart(dataPoints: [String], values: [Int]) {
self.chartHeight.constant = CGFloat((RowHeightCounter.sharedInstance.counters[row])*62+39)
chart.chartDescription?.text = ""
chart.noDataText = ""
var dataEntries: [BarChartDataEntry] = []
for i in 0..<dataPoints.count {
let dataEntry = BarChartDataEntry(x: Double(i), y: Double(counts[i]))
dataEntries.append(dataEntry)
}
let chartDataSet = BarChartDataSet(values: dataEntries, label: "Votes")
let chartData = BarChartData(dataSet: chartDataSet)
chart.data = chartData
chart.xAxis.valueFormatter = IndexAxisValueFormatter(values: options)
chart.xAxis.granularity = 1
self.chart.alpha = 1.0
chart.animate(xAxisDuration: 2.0, yAxisDuration: 2.0, easingOption: .easeInBounce)
}
The issue is that UITableView reuses cells rather than creating new ones all the time. If the table had enough rows in it you would see that chart appear numerous times as you scrolled.
Once you add a chart to a cell it is there until removed so every time that cell gets used again the chart will be there.
UITableViewCell has a convient method that gets celled when it is about to be reused, prepareForReuse(). Implement this method and reset anything in the cell that needs to be reset before it appears again.
This does mean that you might need to rethink the interface between the cell and the data source. Maybe create a model object that holds the questions and result data along with wether the user has answered it or not. The data source could then hold an array of questions and pass the correct question to each cell. The cell could then configure itself based on the question
On a side note, I wouldn't remove the various views when changing from the question to the results. I would contain all the question stuff in one container view and all the chart stuff in another. Then I would set isHidden on the two containers as needed. This will keep your scrolling frame rate higher.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! StackingCell
let data = stack[indexPath.row]
cell.stackDeatils = data
cell.floorNumber_Label.text = data.floorNo
let floorDetails = data.floorDetails!
if floorDetails == "NA"{
cell.floor_View.backgroundColor = UIColor.lightGrayColor()
}
else {
for items in floorDetails
{
let floorArr = items.1
cell.floor_View.backgroundColor = UIColor.orangeColor()
//Number of Units passing value to cell
cell.secitons = floorArr.count
for units in floorArr {
let unit = units.1
let compName = unit["companyName"].string!
if compName == "Vacant" {
cell.floor_View.backgroundColor = UIColor(red: 94/255, green: 198/255, blue: 162/255, alpha: 1.0)
}
}
}
}
}
let shadowPath = UIBezierPath(rect: cell.floor_View.bounds)
cell.floor_View.layer.masksToBounds = false
cell.floor_View.layer.shadowColor = UIColor.blackColor().CGColor
cell.floor_View.layer.shadowOffset = CGSize(width: 1, height: 0.5)
cell.floor_View.layer.shadowOpacity = 0.2
cell.floor_View.layer.shadowPath = shadowPath.CGPath
return cell
}
CustomTableCell method for adding vertical line to TableViewCell
var stackDeatils:StackingModel!{
didSet
{
dispatch_async(dispatch_get_main_queue()) {
self.updateData()
}
}
}
func updateData(){
let unit = self.stackDeatils.isUnitsDrawn
if unit == true {
self.stackDeatils.isUnitsDrawn = false
let stack_width = self.floor_View.frame.width
let stack_height = self.floor_View.frame.height
xCor = stack_width/CGFloat(self.secitons)
var x = xCor
for var i = 1;i < self.secitons; i++ {
let line = UIView(frame: CGRectMake(x, 0, 2,stack_height))
line.backgroundColor = UIColor.whiteColor()
//print(xCor)
self.floor_View.addSubview(line)
x += xCor
}
}
else {
print(self.stackDeatils.isUnitsDrawn)
}
}