ios 14 Tableview cell with textField not working - uitableview

In iOS 14 TableView with textField is not working. Is someone have solution ?
Here is sample code:
class TestController: UIViewController {
let tableView: UITableView = {
let tableView = UITableView(frame: .zero, style: .grouped)
return tableView
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .green
view.addSubview(tableView)
tableView.edgesToSuperview()
tableView.backgroundColor = .gray
tableView.register(TestCell.self, forCellReuseIdentifier: TestCell.reuseID)
tableView.dataSource = self
}
}
extension TestController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: TestCell.reuseID, for: indexPath)
return cell
}
}
class TestCell: UITableViewCell {
let textField = UITextField()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
backgroundColor = .red
addSubview(textField)
textField.height(50)
textField.backgroundColor = .blue
textField.edgesToSuperview()
selectionStyle = .none
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
The same code works on iOS 13 but is not working on iOS 14. Is someone fixed this issue ? (Xcode Version 12.0 (12A7209))

You should not use directly addSubview in a cell but instead add it inside the ContentView:
contentView.addSubview(textField)
This should work and solve your problem

In iOS 14 the UITableViewCellContentView hierarchy is different.
In tableView(_:cellForRowAt:), instead of doing something like this:
cell.addSubview(textField)
Change it to:
cell.contentView.addSubview(textField)

Related

iOS Swift, how to delete a UIView in a TableViewCell and adjustment cell height?

I want to add or delete some view in a TableViewCell dynamically
And I want the cell Height could be adjusted to the cell content height when I delete the UIView in cell.
below is my demo, I use the
self.frame.size.height -= 100
to adjust cell height, but the result is not so good.
import UIKit
import SnapKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let table = UITableView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 1200))
table.dataSource = self
table.delegate = self
table.estimatedRowHeight = 1
table.rowHeight = UITableView.automaticDimension
table.separatorColor = UIColor.blue
table.register(CustomCell.self, forCellReuseIdentifier: "identifierid")
view.addSubview(table)
}
}
class CustomCell:UITableViewCell {
let btn:UIButton = {
let btn = UIButton()
btn.layer.borderColor = UIColor.black.cgColor
btn.layer.borderWidth = 1
btn.setTitle("delete red view", for: .normal)
btn.setTitleColor(UIColor.black, for: .normal)
return btn
}()
let v:UIView = {
let v = UIView()
v.backgroundColor = UIColor.red
return v
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.contentView.addSubview(btn)
btn.snp.makeConstraints { (make) in
make.top.equalToSuperview().offset(10)
make.size.equalTo(CGSize(width: 150,height: 50))
}
btn.addTarget(self, action: #selector(deleteCellImg), for: .touchUpInside)
self.contentView.addSubview(v)
v.snp.makeConstraints { (make) in
make.top.equalTo(btn.snp.bottom)
make.left.equalTo(btn)
make.size.equalTo(CGSize(width: 100, height: 100))
make.bottom.equalToSuperview().offset(-10)
}
}
#objc func deleteCellImg() {
v.removeFromSuperview()
self.frame.size.height -= 100 //100 is the red view height
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension ViewController:UITableViewDelegate,UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 6
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "identifierid", for: indexPath) as! CustomCell
return cell
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
}
The result is showed below
When I delete a view in a cell,I don't want the other cell height would be influenced.So is there some detail I ignore?
call removeFromSuperview() while removing the view. This will be done in your Custom Cell class.
Then reload table view through table.reloadData().
If the row height is still misleading use constraints or height for row.

NSContiguousString Leak on UITableView Cell

I'm getting NSContiguousString leak on Instruments in a ViewController which has only UITableView and a UINavigationBar. When viewController appears texts on UITableViewCells doesn't shown, only blank cells.
If I change it to;
cell.textLabel?.text = NSString(string: dataSource[indexPath.row]) as String
Texts seen on cells.
Controller Class:
class FirstSupportedServicesViewController: BaseViewController {
let bTableView = UITableView()
let dataSource = ["Cell Text 1","Cell Text 2"]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
bTableView.delegate = self
bTableView.dataSource = self
bTableView.frame = self.view.frame
bTableView.register(BaseCell.self, forCellReuseIdentifier: "SupportedServicesBaseCell")
bTableView.tableFooterView = UIView()
//Prevent TableView Scroll Bug
if #available(iOS 11.0, *) {
bTableView.contentInsetAdjustmentBehavior = .never
} else {
// Fallback on earlier versions
}
self.view.addSubview(bTableView)
let leftButton = UIBarButtonItem(title: "< Geri", style: .plain, target: self, action: #selector(self.backBtnTapped))
self.navigationItem.leftBarButtonItem = leftButton
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#objc func backBtnTapped(){
self.dismiss(animated: true, completion: nil)
}}
extension FirstSupportedServicesViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat{
return 44
}
}
extension FirstSupportedServicesViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SupportedServicesBaseCell", for: indexPath) as! BaseCell
cell.textLabel?.text = dataSource[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let controller = SupportedServicesViewController()
self.navigationController?.pushViewController(controller, animated: true)
tableView.deselectRow(at: indexPath, animated: true)
}
}
Custom TableView Cell:
class BaseCell: UITableViewCell {
let cellText: UILabel = {
let label = UILabel()
label.textColor = UIColor.black
label.font = Fonts.font
label.adjustsFontSizeToFitWidth = true
return label
}()
override init(style: UITableViewCellStyle, reuseIdentifier: String?){
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupViews()
}
func setupViews() {
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

Tableview error when using custom cell class

I am trying to make a tableViewController with a custom cell class programmatically but I am getting this error:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'unable to dequeue a cell with identifier cellId - must register a nib or a class for the identifier or connect a prototype cell in a storyboard'
*** First throw call stack:
I have several UItableViews in my app with custom cells and they all work fine but for some reason, this one isn't working. I've spent the last few hours trying to work it out but can't see the problem, can someone help me please?
This is my tableview class:
var tableView = UITableView()
var twoDimensionalArray = [
cameraInfoStruct(cameraInfo: ["Camera Body","Lens", "FPS", "Shutter Angle", "Colour Temperature", "Resolution Width", "Resolution Height", "Format", "Camera Rig"]),
cameraInfoStruct(cameraInfo:["Focus Length", "F - Stop", "Camera Height", "Camera Tilt", "Camera Roll", "Filter"])
]
let cellId = "cellId"
let screenHeight = UIScreen.main.bounds.height
let screenWidth = UIScreen.main.bounds.width
let sectionHeaders = ["General", "Advanced"]
override func viewDidLoad() {
super.viewDidLoad()
addTableView()
}
func addTableView() {
tableView = UITableView(frame: CGRect(x: 0, y: 0, width: screenWidth, height: screenHeight))
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "MyCell")
tableView.dataSource = self
tableView.delegate = self
tableView.tableFooterView = UIView()
self.view.addSubview(tableView)
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if let sectionHeaderArray = sectionHeaders as? [String] {
return sectionHeaderArray[section]
}
return "unknown"
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return twoDimensionalArray[section].cameraInfo.count
}
func numberOfSections(in tableView: UITableView) -> Int {
return sectionHeaders.count
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cell.backgroundColor = UIColor.white
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! cameraInfoCell
let shotNumber = twoDimensionalArray[indexPath.section].cameraInfo[indexPath.row]
cell.textLabel?.text = shotNumber
return cell
}
}
And this is my custom cell class:
class cameraInfoCell: UITableViewCell {
override func layoutSubviews() {
super.layoutSubviews()
self.textLabel?.frame.origin.x = 20
self.detailTextLabel?.frame.origin.x = 20
self.detailTextLabel?.textColor = UIColor(red:0.73, green:0.73, blue:0.73, alpha:1.0)
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: .subtitle, reuseIdentifier: reuseIdentifier)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
You use two different cellIDs:
In your class, you define a cellId variable,
let cellId = "cellId"
which you use in cellForRowAt:
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! cameraInfoCell
In addTableView, you use the hardcoded string "MyCell":
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "MyCell")
To fix it, use the cellId in both places, so change the code in your addTableView method to:
tableView.register(cameraInfoCell.self, forCellReuseIdentifier: cellId)
You have to register the table inviewDidLoad either
tableView.register(cellClassName.self, forCellReuseIdentifier: "cellId")

Remove top padding from UITableView

I have a UITableView as a cell of another UITableView (nested UITableViews).
There is a top padding that I can't reason for, the top padding only appears when I make the CustomTableCell has a UITableView.
class CustomTableCell: UITableViewCell, UITableViewDelegate, UITableViewDataSource {
private let cellId = "cellId"
lazy var tableView: UITableView = {
let tv = UITableView(frame: .zero, style: .grouped)
tv.translatesAutoresizingMaskIntoConstraints = false
tv.backgroundColor = .green
tv.delegate = self
tv.dataSource = self
tv.alwaysBounceVertical = false
tv.isScrollEnabled = false
tv.separatorColor = .red;
tv.separatorStyle = .none;
tv.register(InnerTableCell.self, forCellReuseIdentifier: self.cellId)
return tv
}()
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 50
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! InnerTableCell
return cell
}
func setupAutoLayout() {
tableView.leftAnchor.constraint(equalTo: contentView.leftAnchor).isActive = true
tableView.rightAnchor.constraint(equalTo: contentView.rightAnchor).isActive = true
tableView.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.backgroundColor = .white
contentView.addSubview(tableView)
setupAutoLayout()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Here is the link to entire code: https://ideone.com/QAxkPR
Here is how it looks in reveal
Change style to .plain instead of .grouped
let tv = UITableView(frame: .zero, style: .plain)

Why UITableView does not call my customCell?

I've created UITableView and UITableViewCell programmatically. In my ViewController - viewDidLoad I do:
self.tableView.delegate = self
self.tableView.dataSource = self
self.tableView.registerClass(newsCell.self, forCellReuseIdentifier: "newsCell")
later use it as:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("newsCell", forIndexPath: indexPath) as! newsCell
return cell
}
My newsCell class(shortly):
class newsCell: UITableViewCell {
let scoreLabel = UILabel()
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
print("init")
self.addSubview(self.scoreLabel)
}
}
but I do not even get init on logs, so it does not call my custom cell at all. What is a problem?
Try this code below:
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: restorationIdentifier)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
and forced unwrapping is dangerous. You should do it like this:
if let cell = self.tableView.dequeueReusableCellWithIdentifier("newsCell", forIndexPath: indexPath) as? newsCell{}

Resources