TableviewCell: set constraints programmatically inside ContentView using autoresize - swift

I am trying to constraint elements (UIView or UITextfield) in a TableViewCell. If i am using a frame like
UITextField(frame: CGRect(x: 150, y: 0, width: 500, height: 110))
everything works fine.
But i am trying to use autoresize and somehow my UITextfield added as SubView in my Cell don't have the same ancestor. The error message is: "they have no common ancestor. Does the constraint or its anchors reference items in different view hierarchies?"
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var Testtext: UITextField{
let test = UITextField(frame: CGRect(x: 150, y: 0, width: 500, height: 110))
test.textColor = .red
test.font = .boldSystemFont(ofSize: 22)
test.text = "Hello World"
return test
}
var cell:UITableViewCell {
let createdCell = UITableViewCell()
createdCell.contentView.addSubview(Testtext)
// Testtext.translatesAutoresizingMaskIntoConstraints = false
// NSLayoutConstraint.activate([
// Testtext.topAnchor.constraint(equalTo: createdCell.topAnchor),
// Testtext.bottomAnchor.constraint(equalTo: createdCell.bottomAnchor),
// Testtext.trailingAnchor.constraint(equalTo: createdCell.trailingAnchor),
// Testtext.leadingAnchor.constraint(equalTo: createdCell.leadingAnchor)
// ])
return createdCell
}
BTW: I don't want to create a Cellclass, because i need to adjust the number of Textfields and UIViews depending on the input arrayscount.

You need
var cell:UITableViewCell {
let createdCell = UITableViewCell()
createdCell.contentView.addSubview(Testtext)
Testtext.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
Testtext.topAnchor.constraint(equalTo: createdCell.contentView.topAnchor),
Testtext.bottomAnchor.constraint(equalTo: createdCell.contentView.bottomAnchor),
Testtext.trailingAnchor.constraint(equalTo: createdCell.contentView.trailingAnchor),
Testtext.leadingAnchor.constraint(equalTo: createdCell.contentView.leadingAnchor)
])
return createdCell
}
but this isn't the correct way you need to dequeueResuableCell inside cellForRowAt to generate the cells instead of creating vars
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! CustomCell
return cell
}

Related

Add UIView To Tableview cell not updating

I am trying to add a UIView to an existing IBOutlet in a tableview cell. However this does not appear until I have scrolled away from the cell and scroll back to it.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let stockCell = tableView.dequeueReusableCell(withIdentifier: "stockCell", for: indexPath) as! customStockCell
let progressBar = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
progressBar.backgroundColor = .green
stockCell.progressContainerView.addSubview(progressBar)
return cell
}
class customStockCell: UITableViewCell {
#IBOutlet var progressContainerView: UIView!
}
Using contentView instead of containerView works fine for me.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let stockCell = tableView.dequeueReusableCell(withIdentifier: "stockCell", for: indexPath)
let progressBar = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
progressBar.backgroundColor = .green
stockCell.containerView.addSubview(progressBar)
return cell
}
You can also create a custom cell class and add this logic inside its' initialiser.
Alternatively, if the above solution doesn't work, you can add this logic inside willDisplayCell:
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
let progressBar = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
progressBar.backgroundColor = .green
cell.containerView.addSubview(progressBar)
}

Swift TableView Cell [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
I am trying to create tableView cells and customize the layout. But it seems anything I add inside my cells get stuck being the same size height and width as the cell itself. How can I make it to where I can design my cells however I like? i.e, make my images a specific size with margins and paddings. Even my text height is being stretched out to the cells height. I added the borders so that it's visible for what I mean. The height of my label should be just the size of the text itself but it is still stretching.
I am stuck on tableview cells and want to design my cell layout fully programmatically without storyboarding. I've been trying to teach myself all day and just keep going in circles.
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
let tableView = UITableView()
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
self.tableView.delegate = self
self.tableView.dataSource = self
self.view.addSubview(self.tableView)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
tableView.frame = view.bounds
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 200
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 8
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = "Here is some text"
cell.textLabel?.layer.cornerRadius = 10
cell.textLabel?.layer.borderWidth = 5
cell.textLabel?.layer.borderColor = UIColor.black.cgColor
cell.imageView?.image = UIImage(named: "spiderman")!
cell.imageView?.layer.cornerRadius = 10
cell.imageView?.layer.borderWidth = 5
cell.imageView?.layer.borderColor = UIColor.black.cgColor
return cell
}
}
Thats because you are using UITableViewCell's default textLabel
If you open a storyboard and play around with cell with 'basic' style, you will see that the text is always aligned to center.
I dont think you can adjust height or position of these two predefined properties (.textLabel and .imageView) directly.
Try to create imageView and label manually, and dont use cell.textLabel directly.
Example:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let label = UITextView(frame: CGRect(x: 200, y: 0, width: 500, height: 50))
label.text = "Here is some text"
label.layer.cornerRadius = 10
label.layer.borderWidth = 5
label.layer.borderColor = UIColor.black.cgColor
cell.addSubview(label)
let image = UIImage(named: "spiderman")!
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
imageView.image = image
imageView.layer.cornerRadius = 10
imageView.layer.borderWidth = 5
imageView.layer.borderColor = UIColor.black.cgColor
cell.addSubview(imageView);
return cell
}

Print indexpath row on label in each table view cell

In my swift code below each table view cell features a label. In that label I want to print the index path row. So in cell one the label should be 1 in cell to it should read 2. I tried to code cell.textLabel?.text = "(indexPath.row)" but that code is not complying. The code uses no storyboards all code.
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var numberOfRows = 3
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { numberOfRows }
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 118 }
var tableView = UITableView()
var selectedIndexPath = IndexPath(row: 0, section: 0)
override func viewDidLoad() {
super.viewDidLoad()
setTableVIew()
}
func setTableVIew(){
let VCframe = view.frame
let height = VCframe.height * 0.8
let widthx = VCframe.width
tableView.frame = CGRect(x: 10, y: 0, width: widthx - 20, height: height)
tableView.delegate = self
tableView.dataSource = self
view.addSubview(tableView)
tableView.register(customtv.self, forCellReuseIdentifier: "cell")
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! customtv
cell.textLabel?.text = "\(indexPath.row)"
return cell
}
}
class customtv: UITableViewCell {
lazy var backView : UIView = {
let view = UIView(frame: CGRect(x: 10, y: 6, width: self.frame.width , height: 110))
view.backgroundColor = .green
print(self.frame.width)
return view
}()
override func layoutSubviews() {
backView.clipsToBounds = true
backView.frame = CGRect(x: 0, y: 6, width: bounds.maxX , height: 110)
}
lazy var lbl : UILabel = {
let press = UILabel(frame: CGRect(x: 0, y: 3, width: 120 , height: 50))
press.backgroundColor = .yellow
press.text = String("1")
return press
}()
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(animated, animated: true)
addSubview(backView)
backView.addSubview(lbl)
}
}
You are almost there :)
You have a custom cell, so you need to set the value of custom label you created, instead of cell.textLabel?.text.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! customtv
//cell.textLabel?.text = "\(indexPath.row)" // Don't Do this.
cell.lbl.text = "\(indexPath.row)" // Do this.
return cell
}
To clarify, your cells will start with values 0, 1, 2. IndexPath.row is 0 based.

Put a UIButton in tableView

I made a code for added a array of UIView in my TableView, but when I add them, it doesn't show them row by row while I made a loop for it to add each item in my TableView but it adds them one above the other, another solution?
my view controller :
class mainViewController: UIViewController {
private var myArray: [UIView] = []
private var myTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
let barHeight: CGFloat = UIApplication.shared.statusBarFrame.size.height
let displayWidth: CGFloat = self.view.frame.width
let displayHeight: CGFloat = self.view.frame.height
myTableView = UITableView(frame: CGRect(x: 50, y: barHeight, width: displayWidth, height: displayHeight - barHeight))
myTableView.register(UITableViewCell.self, forCellReuseIdentifier: "MyCell")
myTableView.dataSource = self
myTableView.delegate = self
self.view.addSubview(myTableView)
let DoneBut: UIButton = UIButton(frame: CGRect(x: 50, y: 0, width: 150, height: 50))
DoneBut.setTitle("Done", for: .normal)
DoneBut.backgroundColor = UIColor.blue
let DoneBut2: UIButton = UIButton(frame: CGRect(x: 50, y: 0, width: 50, height: 50))
DoneBut2.setTitle("Done2", for: .normal)
DoneBut2.backgroundColor = UIColor.blue
let view1 = UIView()
view1.addSubview(DoneBut)
myArray.append(view1)
let view2 = UIView()
view2.addSubview(DoneBut2)
myArray.append(view2)
}
}
extension mainViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath:
IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier:
"MyCell", for: indexPath as IndexPath)
for array in myArray {
cell.contentView.addSubview(array)
}
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection
section: Int) -> Int {
return myArray.count
}
}
extension mainViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath:
IndexPath) {
print("Num: \(indexPath.row)")
print("Value: \(myArray[indexPath.row])")
}
}
Your issue is that each time the cellForRowAt function is asking for a cell, you are looping through ALL the views and adding them to each cell. Instead you should be indexing in it using the indexPath. See the following:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath as IndexPath)
// check if there is a view at the indexPath
if indexPath.row < myArray.count {
// there is a view, add it to the cells contentView
cell.contentView.addSubview(myArray[indexPath.row])
} else {
print("no view at index")
}
return cell
}

Add view dynamically to cells produce issues in table

I have this function:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier)!
let label = UILabel(frame: CGRect(x: 100, y: 14, width: 400, height: 30))
label.text = "\(data[indexPath.row])"
label.tag = indexPath.row
cell.contentView.addSubview(label)
return cell
}
Well, with this function I'm adding a list of rows dynamically.
Why dynamically? Because, the number of columns depends of the data.
Don't take focus on that.
The list has 244 elements.
The result is displayed ok, but once I started scrolling, I get this:
How I can add elements dynamically without get this error?
Cells get reused. You keep adding more and more labels to each cell.
The proper solution is to create a custom cell class that contains the desired label. Then simply set that label's text in cellForRowAt. Don't create and add subviews in cellForRowAt.
But keep in mind that you may just want to use the provided textLabel property of UITableViewCell. No need for a custom cell or your own label.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier)!
cell.textLabel?.text = "\(data[indexPath.row])"
return cell
}
I found a solution, hope this works to you!!!
You have to add to your cellForRowAt this code:
for item in cell.contentView.subviews
{
item.removeFromSuperview()
}
Just after to get the cell.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier)!
for item in cell.contentView.subviews
{
item.removeFromSuperview()
}
let label = UILabel(frame: CGRect(x: 100, y: 14, width: 300, height: 30))
label.text = "\(data[indexPath.row])"
label.tag = indexPath.row
let btn = UIButton(type: UIButtonType.custom) as UIButton
btn.backgroundColor = UIColor.red
btn.setTitle("boton", for: .normal)
btn.frame = CGRect(x:0, y:5, width: 80, height:40)
//btn.addTarget(self, action: "buttonPressed:", for: UIControlEvents.touchUpInside)
btn.tag = indexPath.row
cell.contentView.addSubview(btn)
cell.contentView.addSubview(label)
cell.tag = indexPath.row
return cell
}
UITableview create 10 cell at scroll down recreate cell view
You can using
cell.contentView.removeFromSuperview() before cell.contentView.addSubview(label) or using cell.textLabel?.text
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier)!
cell.contentView.removeFromSuperview()
let label = UILabel(frame: CGRect(x: 100, y: 14, width: 400, height: 30))
label.text = "\(data[indexPath.row])"
label.tag = indexPath.row
cell.contentView.addSubview(label)
return cell
}
Note This solution will delete All subview in cell