I am trying number cell from 0-X for a uitableview. Currently I am using a label to do it and I just want the labels text to be 0,1,2,3,4,...X.
//label for the cell
let cellFrame: CGRect = CGRectMake(0, 0, 90, 32)
var cellLabel = UILabel(frame: cellFrame)
cellLabel.textAlignment = .Center
cellLabel.font = UIFont.MDFont.regularFourteen
cellLabel.text = ("\(indexPath.row)")
I have tried this approach and it just does 0,1,2,3,4 but when I scroll it prints 0,1,2,3,4 on top of the other numbers as well.
This is the whole code for the function
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier("cell") as! UITableViewCell
if cell == null {
//label for the cell
let cellFrame: CGRect = CGRectMake(0, 0, 90, 32)
var cellLabel = UILabel(frame: cellFrame)
cellLabel.textAlignment = .Center
cellLabel.font = UIFont.MDFont.regularFourteen
cellLabel.text = ("\(indexPath.row)")
cell.contentView.addSubview(cellLabel)
}
//print("Table data is \(tableData[5])")
return cell
}
I think there is issue related reusable cell. kindly try below code. may it help you.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier("cell") as! UITableViewCell
if cell == null {
//label for the cell
let cellFrame: CGRect = CGRectMake(0, 0, 90, 32)
var cellLabel = UILabel(frame: cellFrame)
cellLabel.textAlignment = .Center
cellLabel.font = UIFont.MDFont.regularFourteen
cellLabel.text = ("\(indexPath.row)")
cell.contentView.addSubview(cellLabel)
}
else {
for obj : AnyObject in cell.contentView.subviews {
if let label = obj as? UILabel {
label.text = ("\(indexPath.row)")
}
}
}
//print("Table data is \(tableData[5])")
return cell
}
Try this:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier("cell") as! UITableViewCell
if let cellLabel = cell.contentView.viewWithTag(10) as? UILabel {
cellLabel.text = ("\(indexPath.row)")
}
else {
let cellLabel = UILabel(frame: CGRectMake(0, 0, 90, 32))
cellLabel.tag = 10
cellLabel.textAlignment = .Center
cellLabel.font = UIFont.MDFont.regularFourteen
cellLabel.text = ("\(indexPath.row)")
cell.contentView.addSubview(cellLabel)
}
//print("Table data is \(tableData[5])")
return cell
}
When you compare variables you have to use nil.
Also in your case if the cell was nil, you should have created one. Because as you have it you try to add a label to a cell that doesn't exist.
See, when your table is loaded, your cells are nil for the visible region of screen... Here, its 4 cells, so your cell is nil condition will be satisfied for all 4 cells and you will get 4 cells having 0,1,2,3 text. But now when you scroll down, your cell will be reused and it wont go inside the condition so, it will show the old value that you've added in one of the above cells and hence will get wrong values.. You can use a simple approach:
Give tag (say, 1234) to your label when you allocate it when your cell is nil and access it outside the if condition, using that tag get that label and set text to it outside the if condition.. So, it will be called everytime and you will get 0,1,2,3,....X as you wanted...
Replace cellForRowAtIndexPath with this.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
var cell : UITableViewCell = UITableViewCell(frame: CGRectMake(0, 0, tableView.frame.size.width, 44))
let cellLabel = UILabel(frame: CGRectMake(0, 0, 90, 32))
cellLabel.tag = 10
cellLabel.textAlignment = .Center
cellLabel.text = ("\(indexPath.row)")
cell.addSubview(cellLabel)
return cell
}
Hope this helps you. :)
I think the problem is getting your row index using indexPath.row. Just create a local variable with the index thats added to the cell in the function cellForRowAtIndexPath() before the cell is returned. Then just reset the cellIndex=0 before calling reloadData(). I believe that would work
i.e
var cellIndex = 0
func ..cellForRowAtIndexPath ...()
{
//set the index to the cell label.
cell.label = cellIndex++
return cell
}
Related
I've made an UITableView and filled it with JSON data I get inside my API. I get and place all correctly but when I scroll or delete a row everything gets messed up!
Labels and images interfere; this is my code:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
var dict = productsArrayResult[indexPath.row]
let cellImage = UIImageView(frame: CGRect(x: 5, y: 5, width: view.frame.size.width / 3, height: 90))
cellImage.contentMode = .scaleAspectFit
let productMainImageString = dict["id"] as! Int
let url = "https://example.com/api/DigitalCatalog/v1/getImage?id=\(productMainImageString)&name=primary"
self.downloadImage(url, inView: cellImage)
cell.addSubview(cellImage)
let cellTitle = UILabel(frame: CGRect(x: view.frame.size.width / 3, y: 5, width: (view.frame.size.width / 3) * 1.9, height: 40))
cellTitle.textColor = UIColor.darkGray
cellTitle.textAlignment = .right
cellTitle.text = dict["title"] as? String
cellTitle.font = cellTitle.font.withSize(self.view.frame.height * self.relativeFontConstantT)
cell.addSubview(cellTitle)
let cellDescription = UILabel(frame: CGRect(x: view.frame.size.width / 3, y: 55, width: (view.frame.size.width / 3) * 1.9, height: 40))
cellDescription.textColor = UIColor.darkGray
cellDescription.textAlignment = .right
cellDescription.text = dict["description"] as? String
cellDescription.font = cellDescription.font.withSize(self.view.frame.height * self.relativeFontConstant)
cell.addSubview(cellDescription)
return cell
}
You are adding subviews multiple times while dequeuing reusable cells. What you can do is make a prototype cell either in storyboard or as xib file and then dequeue that cell at cellForRowAtIndexPath.
Your custom class for cell will look similar to this where outlets are drawn from prototype cell.
Note: You need to assign Reusable Identifier for that prototype cell.
class DemoProtoTypeCell: UITableViewCell {
#IBOutlet var titleLabel: UILabel!
#IBOutlet var descriptionLabel: UILabel!
#IBOutlet var titleImageView: UIImageView!
}
Now you can deque DemoProtoTypeCell and use accordingly.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: DemoProtoTypeCell.self), for: indexPath) as! DemoProtoTypeCell
cell.titleImageView.image = UIImage(named: "demoImage")
cell.titleLabel.text = "demoTitle"
cell.descriptionLabel.text = "Your description will go here."
return cell
}
That's because you are adding subviews to reused (so that it may already have subviews added previously) cells.
Try to check if the cell has subviews and fill in information you need, if there're no subviews then you add them to the cell.
Option 1
if let imageView = cell.viewWithTag(1) {
imageView.image = //your image
} else {
let imageView = UIImageView(//with your settings)
imageView.tag = 1
cell.addSubview(imageView)
}
Option 2
Crete UITableViewCell subclass that already has all the subviews you need.
I have used below method to remove all subviews from cell:
override func prepareForReuse() {
for views in self.subviews {
views.removeFromSuperview()
}
}
But I have created UITableViewCell subclass and declared this method in it.
you can also do one thing as #sCha has suggested. Add tags to the subviews and then use the same method to remove subview from cell:
override func prepareForReuse() {
for view in self.subviews {
if view.tag == 1 {
view.removeFromSuperview()
}
}
}
Hope this helps.
I think the other answers already mentioned a solution. You should subclass the tableview cell and just change the values of your layout elements for each row.
But I want to explain why you get this strange behaviour.
When you call
tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
it tries to reuse an already created cell with the passed identifier #"cell". This saves memory and optimises the performance. If not possible it creates a new one.
So now we got a cell with layout elements already in place and filled with your data. Your code then adds new elements on top of the old ones. Thats why your layout is messed up. And it only shows if you scroll, because the first cells got no previous cells to load.
When you subclass the cell try to create the layout only once on first initialisation. Now you can pass all values to the respective layout element and let the tableview do its thing.
Try this:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell:UITableViewCell! = tableView.dequeueReusableCell(withIdentifier: "cell")
if cell == nil
{
cell = UITableViewCell.init(style: UITableViewCellStyle.default, reuseIdentifier: "cell")
}
for subView in cell.subviews
{
subView.removeFromSuperview()
}
// Your Code here
return cell
}
I'm making a timetable app using swift.
I load my data from website and put it on a collectionView.
In the first section, I put the day of the week and in the first row, I put the classes and in other cells, I put the data from the web (subject Name, class room...)
If I enter the timetable view, everything is fine at first.
However, if I scroll down and scroll up, some text are printed where they shouldn't be.
This is my collectionView(collectionView: , cellForItemAtIndexPath: )
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
print("\(indexPath.section), \(indexPath.row)")
let dayArray = ["", "월", "화", "수", "목", "금"]
if indexPath.section == 0 {
// Day
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as UICollectionViewCell
var titleLabel = UILabel(frame: CGRectMake(0, 0, cell.bounds.width, cell.bounds.height))
cell.contentView.addSubview(titleLabel)
titleLabel.text = dayArray[indexPath.row]
titleLabel.textAlignment = NSTextAlignment.Center
cell.backgroundColor = mainColor
print("day")
return cell
}
if indexPath.row == 0 {
// index
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as UICollectionViewCell
var titleLabel = UILabel(frame: CGRectMake(0, 0, cell.bounds.width, cell.bounds.height))
cell.contentView.addSubview(titleLabel)
titleLabel.text = String(indexPath.section)
titleLabel.textAlignment = NSTextAlignment.Center
cell.backgroundColor = mainColor
print("time")
return cell
}
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! TimeTableCell
if let timeTableElement = self.timeTable[indexPath.section-1][indexPath.row-1] {
cell.subjectNameLabel.text = timeTableElement.subjectName
cell.subjectNameLabel.adjustsFontSizeToFitWidth = true
cell.classRoomLabel.text = timeTableElement.classRoom
cell.classRoomLabel.adjustsFontSizeToFitWidth = true
} else {
cell.subjectNameLabel.text = ""
cell.classRoomLabel.text = ""
}
cell.backgroundColor = mainColor
print("class")
return cell
}
I'm using a default UICollectionViewCell with adding a label subview to show the day and class time and using a custom TimeTableCell to show the class data.
How can I solve this problem?
Try to use a different 'reuseIdentifier' for TimeTableCell:
change reuse identifier in attributes inspector:
change your code:
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(yourReuseIdentifier, forIndexPath: indexPath) as! TimeTableCell
ps. I suggest to remove the existed titleLabel first and then add the new one, otherwise it will be add again when scrolling down and up.
EDIT
You can 'delete' the titleLabel in two ways:
add a custom cell as well as TimeTableCell(different name and different ReuseIdentifier). as you can see,subjectNameLabel in TimeTableCell will not be add again and again.
set a tag for titleLabel after initialization, and remove it according to the tag.
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as UICollectionViewCell
cell.contentView.viewWithTag(999)!.removeFromSuperview()
var titleLabel = UILabel(frame: CGRectMake(0, 0, cell.bounds.width, cell.bounds.height))
titleLabel.tag = 999
cell.contentView.addSubview(titleLabel)
titleLabel.text = dayArray[indexPath.row]
titleLabel.textAlignment = NSTextAlignment.Center
cell.backgroundColor = mainColor
print("day")
return cell
You need to Remove Title Label before you addd it
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as UICollectionViewCell
// Here find view with tag 999 and remove it from superview
var titleLabel = UILabel(frame: CGRectMake(0, 0, cell.bounds.width, cell.bounds.height))
cell.contentView.addSubview(titleLabel)
titleLabel.tag = 999;
titleLabel.text = String(indexPath.section)
titleLabel.textAlignment = NSTextAlignment.Center
cell.backgroundColor = mainColor
print("time")
return cell
I need to present a UIStepper in a row of a UITableView(only the second row - see the image below).
Therefore I implemented func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell like below:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("OptionCell")!
let debugModeOptionType = DebugModeOptionsType(rawValue: indexPath.row)
switch(debugModeOptionType!) {
case .DummyCurrentLocation:
cell.textLabel!.text = "Dummy current location"
case .StepLength:
cell.textLabel!.text = "Step Length: \(stepLength)"
// create a UIStepper
let stepper = UIStepper(frame: CGRectMake(220, 10, 100, 10))
// customize UIStepper
stepper.autorepeat = true
stepper.value = stepLength
stepper.minimumValue = 0.1
stepper.stepValue = 0.02
stepper.maximumValue = 1.5
stepper.addTarget(self, action: #selector(adjustStepLength(_:)), forControlEvents: UIControlEvents.AllEvents)
// add UIStepper into the cell
stepper.translatesAutoresizingMaskIntoConstraints = false
cell.contentView.addSubview(stepper)
case .TrueHeading:
cell.textLabel?.text = "True Heading: \(trueHeading)"
case .MagneticHeading:
cell.textLabel?.text = "Magnetic Heading: \(magneticHeading)"
case .HeadingAccuracy:
cell.textLabel?.text = "Heading Accuracy: \(headingAccuracy)"
case .CurrentDirection:
cell.textLabel?.text = "Current Direction: \(currentDirection)"
case .DrawWalking:
cell.textLabel?.text = "Draw walking while navigating"
}
if selectedDebugModeOptions.contains(debugModeOptionType!) {
cell.accessoryType = UITableViewCellAccessoryType.Checkmark
} else {
cell.accessoryType = UITableViewCellAccessoryType.None
}
return cell
}
However when I touch the UIStepper on a real device(this does not happen inside the simulator) the following happens:
When this happens, the other cells' UISteppers start flashing as well. Why does such a problem occurs?
I can't say why this happening only on a real device, but because table view cells are reused, you have to be careful when adding elements to the cells programmatically, because those elements (such as your stepper) will be spread to other cells as the cells are reused.
There are (at least) two ways you can deal with this:
Check for the presence of a stepper after you dequeue a reusable cell and remove it if it is on a row that doesn't need a stepper. You could do this by giving the stepper a unique tag number (such as 123) and then search for subviews with that tag and remove them.
let stepperTagNumber = 123
let cell = tableView.dequeueReusableCellWithIdentifier("OptionCell")!
let debugModeOptionType = DebugModeOptionsType(rawValue: indexPath.row)
if let stepper = cell.contentView.viewWithTag(stepperTagNumber) {
// We have a stepper but don't need it, so remove it.
if debugModeOptionType != .StepLength {
stepper.removeFromSuperview()
}
} else {
// We don't have a stepper, but need one.
if debugModeOptionType == .StepLength {
// create a UIStepper
let stepper = UIStepper(frame: CGRectMake(220, 10, 100, 10))
stepper.tag = stepperTagNumber // This is key, don't forget to set the tag
// customize UIStepper
stepper.autorepeat = true
stepper.value = stepLength
stepper.minimumValue = 0.1
stepper.stepValue = 0.02
stepper.maximumValue = 1.5
stepper.addTarget(self, action: #selector(adjustStepLength(_:)), forControlEvents: UIControlEvents.AllEvents)
// add UIStepper into the cell
stepper.translatesAutoresizingMaskIntoConstraints = false
cell.contentView.addSubview(stepper)
}
}
OR:
Create a second prototype cell for your tableview (called "OptionCellWithStepper"). Add the stepper to that cell in your storyboard. Then, when you call dequeueReusableCellWithIdentifier, use "OptionCellWithStepper" for case .StepLength and use identifier "OptionCell" for all the other cases. Doing it this way, you don't have to programmatically add the stepper, and you don't have to remember to remove it for the other cells.
let debugModeOptionType = DebugModeOptionsType(rawValue: indexPath.row)
let cellID = (debugModeOptionType == .StepLength) ? "OptionCellWithStepper" : "OptionCell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellID)!
I am creating a UITableViewCell object and returning it inside cellForRowAtIndexPath function in tableView. I have a UIView in the cell which I want to make circular. Using the code from this link, I had written following code:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = UITableViewCell()
let containerDP = UIView()
containerDP.backgroundColor = UIColor.redColor()
// some code
let firstLetter = UILabel()
firstLetter.backgroundColor = UIColor.yellowColor()
firstLetter.text = (data[indexPath.row].UserObject.FirstName! as String).uppercaseString[0]
firstLetter.font = UIFont(name: firstLetter.font.fontName, size: 50)
firstLetter.adjustsFontSizeToFitWidth = true
firstLetter.textAlignment = NSTextAlignment.Center
firstLetter.layer.cornerRadius = firstLetter.frame.size.width / 2;
firstLetter.clipsToBounds = true
containerDP.addSubview(firstLetter)
firstLetter.snp_makeConstraints { (make) -> Void in
make.center.equalTo(containerDP)
make.edges.equalTo(containerDP).inset(UIEdgeInsetsMake(10, 10, 10, 10))
}
// some code
return cell
}
But there is still no circular mask:
Try this :
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = UITableViewCell()
let containerDP = UIView()
containerDP.backgroundColor = UIColor.redColor()
// some code
let firstLetter = UILabel()
firstLetter.backgroundColor = UIColor.yellowColor()
firstLetter.text = (data[indexPath.row].UserObject.FirstName! as String).uppercaseString[0]
firstLetter.font = UIFont(name: firstLetter.font.fontName, size: 50)
firstLetter.adjustsFontSizeToFitWidth = true
firstLetter.textAlignment = NSTextAlignment.Center
firstLetter.layer.cornerRadius = firstLetter.frame.size.width / 2;
firstLetter.layer.masksToBounds = true
firstLetter.clipsToBounds = true
containerDP.addSubview(firstLetter)
firstLetter.snp_makeConstraints { (make) -> Void in
make.center.equalTo(containerDP)
make.edges.equalTo(containerDP).inset(UIEdgeInsetsMake(10, 10, 10, 10))
}
// some code
return cell
}
Use dequeueReusableCellWithIdentifier for tablewView cell creating and caching
Make subview setups for tableViewCell in awakeFromNib method
With clipsToBounds = true it should work
first you should create a customtableviewCell class for your tableview.
then make IBOutlet connection to your cutomtablviewCell
then #import your customtablviewCell to your tableviewController
then inside the cellForRowAtIndexPath method(I'm well in objectiveC, not in swift) call to your cutomTableviewcell like below
customTableviewCell *cell = [your code here];
after that do your styles like
cell.fisrtLetter.layer.cornerRadius = cell.firstletter.frame.size.width/2;
cell.firstLetter.layer.masksToBounds = true;
please get the idea.
I have a tableview in my app. it's on the detail view of my split view. Whenever i populate my tableview with UItextviews, the cells seem to overlap each other. this is not what i want. Does anyone have any suggestions to fix this?
here's my vc code:
import UIKit
class DetailViewController: UIViewController, UITableViewDelegate, UITextViewDelegate {
#IBOutlet weak var messagesTableView: UITableView!
var initVar = 0
var row: Int?
var firstLoad = true
var detailItem = {}
var convo = ["hello", "hellohello", "hellohellohellohello", "hellohellohellohellohellohellohellohello", "hellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohello", "hellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohello", "hellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohello", "hellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohello", "hellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohello", "hellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohello"]
override func viewDidLoad() {
super.viewDidLoad()
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem()
print("hello")
messagesTableView.separatorColor = UIColor.whiteColor()
print(row)
messagesTableView.reloadData()
print(firstLoad)
let numberOfSections = messagesTableView.numberOfSections
let numberOfRows = messagesTableView.numberOfRowsInSection(numberOfSections-1)
if numberOfRows > 0 {
print(numberOfSections)
let indexPath = NSIndexPath(forRow: numberOfRows-1, inSection: (numberOfSections-1))
messagesTableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: UITableViewScrollPosition.Bottom, animated: false)
}
messagesTableView.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return convo.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("detailCell", forIndexPath: indexPath)
var textView = UITextView()
textView.delegate = self
textView.editable = false
textView.text = convo[indexPath.row]
textView.textAlignment = .Center
textView.sizeToFit()
if indexPath.row % 2 == 0 {
textView = UITextView(frame: CGRect(x: cell.frame.width * (2/5), y: 4, width: cell.frame.width * (3/5), height: cell.frame.height))
textView.backgroundColor = UIColor.blueColor()
} else {
textView = UITextView(frame: CGRect(x: 0, y: 4, width: cell.frame.width * (3/5), height: cell.frame.height))
textView.backgroundColor = UIColor.greenColor()
}
textView.textColor = UIColor.whiteColor()
textView.delegate = self
textView.editable = false
textView.text = convo[indexPath.row]
textView.textAlignment = .Center
textView.sizeToFit()
tableView.rowHeight = textView.frame.height + 7
cell.addSubview(textView)
return cell
}
}
The cells are being re-used in a UITableView.
You are adding TextView's on it, so you are keep on adding TextView's every time it's being re-used.
Your code should be modified so that the TextView is only added IF it's not already present on the cell.
The easiest way, is to add a TAG (unique) to the TextView, then if the View from Tag is nil (AKA not present) add it, else get it from the ViewFromTag
As for an example, although I'm still using obj-c and with that in mind, my code might have an error, here is the code:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("detailCell", forIndexPath: indexPath)
var textView: UITextView
if (cell.viewWithTag(10000) != nil) {
textView = (cell.viewWithTag(10000) as? UITextView)!
}
else {
textView = UITextView()
textView.tag = 10000
textView.delegate = self
textView.editable = false
textView.textAlignment = .Center
cell.addSubview(textView)
}
textView.text = convo[indexPath.row]
if indexPath.row % 2 == 0 {
textView.frame = CGRectMake(cell.frame.width * (2/5) , 4, cell.frame.width * (3/5), cell.frame.height)
textView.backgroundColor = UIColor.blueColor()
} else {
textView.frame = CGRectMake(0 , 4, cell.frame.width * (3/5), cell.frame.height)
textView.backgroundColor = UIColor.greenColor()
}
textView.sizeToFit()
tableView.rowHeight = textView.frame.height + 7
return cell
}
To explain the code, as you didn't understood:
The UITableView is re-using the cells.
This means, whenever a cell is moved outside the visible part of the screen, it is been re-used (as it is) and is displayed as a new cell for the TableView.
The reason for this, is memory efficiency.
So imagine a UITableView with 1000 row. If for each row a new cell was created, we will have to allocate memory for each cell.
But in a typical application usually only a few cells are visible each time (usually less than 10).
So the trick here is that we only need to create that many cells.
Once a cell gets out of sight, it is been served as a new cell for the TableView.
So if you add a UITextView every time the tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell delegate method is called, and the cell is been re-used, you end up adding UITextViews to a cell that already has one. So you end up with the problem you showed.
The code I provided does two things differently:
It does assign a unique Tag number on the UITextView when it's added to the cell (textView.tag = 10000)
It does check if a UITextView has already been added to the cell and if it has been added we use that UITextView and we don't add it again (if (cell.viewWithTag(10000) != nil))