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.
Related
I have a problem with some TextField inside a UITableViewCell; i got two textfield inside of the table cell, when I tap on the the textField everything works fine as you can see in this two screenshots
1.
The number in red squares are my UITextField, when I tap on one of them it works fine
But when i click on the other textField the entire cell disappear like this
I have an empty space after the click on the other textfield
I have no function implemented, only a function that change font and textColor
func setPickers() {
self.hourPicker.delegate = self
self.minutePicker.delegate = self
hourPicker.textColor = theme.grey
minutePicker.textColor = theme.grey
hourPicker.background = UIImage()
minutePicker.background = UIImage()
hourPicker.textAlignment = .center
minutePicker.textAlignment = .center
hourPicker.font = UIFont(name: "Roboto-Regular", size: 48)
minutePicker.font = UIFont(name: "Roboto-Regular", size: 48)
}
This the cell in my storyboard
EDIT 2
Look my graphic debug what shows before the bug
And after it
The cell is called EventDetailFooterTableViewCell
EDIT 3
Here is where I initialize the cellView for the footer
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let cell = tableView.dequeueReusableCell(withIdentifier: "footerCell") as! EventDetailFooterTableViewCell
cell.event = self.event
cell.delegate = self
cell.setView()
cell.backgroundColor = theme.mainColor
return cell
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
var height: CGFloat = 180.0
var calendar = NSCalendar.current
calendar.timeZone = TimeZone(abbreviation: "UTC")! //OR NSTimeZone.localTimeZone()
let dateAtMidnight = calendar.startOfDay(for: Date())
let todayLong = dateAtMidnight.millisecondsSince1970
if let eventDay = event.dateTime?.millisecondsSince1970 {
if eventDay >= todayLong {
height = 280
}
}
return height
}
I see a problem. You are using regular cell as section footer and there is why you see unpredictable behaviour. You should use UITableViewHeaderFooterView instead. It is if you really need such design. Better solution will be to remove footer and make it cell instead.
I am making UITableView custom cell because height also changed per cell.
This is my code for initialize cell and after that i want to add UITextView as Subview.
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
let dictAd = self.arrAllQuestions[indexPath.row] as! NSDictionary
let fontNew = UIFont(name: "AvenirNext-Regular", size: 19.0)
let strA = "\(indexPath.row+1). \(dictAd.object(forKey: "Title")!)"
let heightTitle = self.heightForView(text: strA, font: fontNew!, width: tableView.frame.size.width-16)
return heightTitle+5;
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let dictAd = self.arrAllQuestions[indexPath.row] as! NSDictionary
let cell = tableView.dequeueReusableCell(withIdentifier: "quesionCell", for: indexPath) as! QuestionCell
let fontNew = UIFont(name: "AvenirNext-Regular", size: 19.0)
let strA = "\(indexPath.row+1). \(dictAd.object(forKey: "Title")!)"
cell.lblName.font = fontNew
cell.lblName.text = strA
cell.lblName.numberOfLines = 0
let heightTitle = self.heightForView(text: strA, font: fontNew!, width: tableView.frame.size.width-16)
var frame = cell.lblName.frame as CGRect
frame.size.height = heightTitle; //you need to adjust this value
cell.lblName.frame = frame;
let txtView = AnimatableTextView(frame: CGRect(x: 8, y: cell.lblName.frame.origin.y+cell.lblName.frame.size.height+5, width: tableView.frame.size.width-16, height: 25))
txtView.borderWidth = 1.0
txtView.borderColor = UIColor.lightGray
txtView.cornerRadius = 4.0
cell.contentView.addSubview(txtView)
return cell
}
You can see output below.
It seems that the height calculation in your heightForRowAtIndexPath is not proper. Consider using self-sizing cells using UITableViewAutomaticDimension and Autolayout to solve your issues. Here is a great tutorial that can help you to get started. One more suggestion if you are using UITextView or subclass of the same in a cell and you want it to take the height of the content set its scrollable property to false.
Declare this in the viewDidLoad
Hope this will help you
tableView.estimatedRowHeight = 44
I have a collectionView with custom cells.
I am trying to add dynamic labels in each cell, but they are only added to the last cell shown. If i make scroll, labels disappear of that cell and appear in the new cell shown.
The number and text of labels will be achieved with a web service.
This is my cellForItemAtIndexPath function:
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! UndatedCell
cell.titleLabel.text = "Sacar al perro"
cell.locationLabel.text = "Casa"
var aux: CGFloat = 0
for label in labelsArray {
let labelWidht = calculateLabelWidht(label) + 20
cell.labelsView.addSubview(label)
label.leftAnchor.constraintEqualToAnchor(cell.labelsView.leftAnchor, constant: aux).active = true
label.centerYAnchor.constraintEqualToAnchor(cell.labelsView.centerYAnchor).active = true
label.widthAnchor.constraintEqualToConstant(labelWidht).active = true
aux = aux + labelWidht + 8
}
return cell
}
In viewDidLoad i create the demo labels:
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView!.registerClass(UndatedCell.self, forCellWithReuseIdentifier: reuseIdentifier)
self.collectionView?.alwaysBounceVertical = true
let label1 = LabelLabel()
label1.text = "Zara"
labelsArray.append(label1)
let label2 = LabelLabel()
label2.text = "Perro"
labelsArray.append(label2)
let label3 = LabelLabel()
label3.text = "Amigo"
labelsArray.append(label3)
}
Finally, this is a pic of the result:
collectionViewPhoto
Thank you very much for your time!
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))
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
}