AutoResizing header & Cell in Programmatically UITableView - ios

I have UIViewTable created programmatically
I customised the headers and cell look via Extension.
All I need is to make the large amount of texts displayed in header/cell to be viewed with:
lineBreakMode = NSLineBreakMode.byWordWrapping // enable multi line
numberOfLines = 0 // for Automatic size
I nearly used everything, but nothing is working.
I used:
self.tableView.estimatedRowHeight = 200.0
self.tableView.rowHeight = UITableView.automaticDimension
I put:
override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
I also did:
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
Nothing seems to work
here is my Extension:
extension indexController {
override func numberOfSections(in tableView: UITableView) -> Int {
return sections.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let subDatas = sections[section].sub_catigories // [1]
return subDatas?.count ?? 0
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let currentSection = sections[indexPath.section]
let currentSubdata = currentSection.sub_catigories?[indexPath.row]
//print(currentSubdata!.id)
let vc = indexControllerTwo()
vc.catNumber = currentSubdata!.id
vc.sectionTitle = currentSubdata?.name
navigationController?.pushViewController(vc, animated: true)
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellid", for: indexPath)
// [2]
let currentSection = sections[indexPath.section]
let currentSubdata = currentSection.sub_catigories![indexPath.row]
// use listCell
guard let titleCell = cell as? listCell else {
return cell
}
titleCell.titleLabel.text = currentSubdata.name
titleCell.listCount.text = "\(currentSubdata.number_of_subcatigories ?? 0)"
// titleCell.titleLabel.numberOfLines = 3
// titleCell.titleLabel.lineBreakMode = NSLineBreakMode.byWordWrapping
// titleCell.titleLabel.baselineAdjustment = .alignCenters
// titleCell.titleLabel.adjustsFontSizeToFitWidth = true
// self.tableView.estimatedRowHeight = 200.0
// self.tableView.rowHeight = UITableView.automaticDimension
cell.layer.backgroundColor = UIColor.clear.cgColor
return cell
}
Please note that: listCell is just for customization and constraint
and here it is:
import UIKit
class listCell: UITableViewCell {
var safeArea: UILayoutGuide!
let imageCell = UIImageView()
let titleLabel = UILabel()
let subTitleLabel = UILabel()
let listCount = UILabel()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupView()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupView(){
safeArea = layoutMarginsGuide
setupTitleLabel()
setupListCount()
}
func setupTitleLabel(){
addSubview(titleLabel)
titleLabel.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
titleLabel.leadingAnchor.constraint(equalTo: safeArea.leadingAnchor),
titleLabel.topAnchor.constraint(equalTo: topAnchor, constant: 7)
])
titleLabel.font = UIFont(name: "verdana-Bold", size: 16)
}
func setupListCount(){
addSubview(listCount)
listCount.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
listCount.leadingAnchor.constraint(equalTo: safeArea.trailingAnchor, constant: -30),
listCount.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: -11)
])
listCount.font = UIFont(name: "verdana", size: 10)
}
}
Please help me make the header and cell text field to be auto resizing.
thanks for your time.

Related

Swift: height of tableView row whose tableView cell has nested tableView with dynamic number of rows

I have been looking around for a solution or a best way to determine the height of a tableView row in heightForRowAt, that has a tableView based on some conditions in the data model.
When my data model has a data type called MULTISELECT, I need to display a cell with a tableView inside it. There are no problems in doing so. The inner tableView's data is assigned in outer tableView's cellForRowAt.
The question here is how to get the height of my outer tableView row for the MULTISELECT type cells, after the data is populated for the inner tableView rows?
Outer tableView code (inside a ViewController) -
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let preferenceCategories = self.preferenceCategories else {
return UITableViewCell()
}
let categoryCode = preferenceCategories[indexPath.section].code
let filteredPreferenceSet = self.preferenceSet.filter({$0.categoryCode == categoryCode}).filter({$0.dataType == "BOOLEAN"/* || $0.dataType == "MULTISELECT"*/})
if let preferenceDataType = filteredPreferenceSet[indexPath.row].dataType {
if preferenceDataType == "BOOLEAN" {
let cell = self.tableView.dequeueReusableCell(withIdentifier: "CustPrefSetCell", for: indexPath) as! CustPrefSetCell
cell.preferenceName.text = filteredPreferenceSet[indexPath.row].name
cell.preferenceDescription.text = filteredPreferenceSet[indexPath.row].description
cell.switchDelegate = self
let propertyValue = ((filteredPreferenceSet[indexPath.row].value ?? "false") as NSString).boolValue
propertyValue ? cell.preferenceSwitch.setOn(true, animated: true) : cell.preferenceSwitch.setOn(false, animated: true)
cell.preferenceCode = filteredPreferenceSet[indexPath.row].code
return cell
}
else if preferenceDataType == "MULTISELECT" {
let multiSelectCell = self.tableView.dequeueReusableCell(withIdentifier: "CustPrefMultiSelectTableViewCell", for: indexPath) as! CustPrefMultiSelectTableViewCell
multiSelectCell.preferenceValues = filteredPreferenceSet[indexPath.row].preferenceValues
// self.rowHeight = multiSelectCell.tableView.contentSize.height
return multiSelectCell
}
else {
return UITableViewCell()
}
}
else {
return UITableViewCell()
}
}
public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
The inner tableView is inside the multiSelectCell, whose code is below -
class CustPrefMultiSelectTableViewCell: UITableViewCell {
#IBOutlet weak var tableViewHeightConstraint: NSLayoutConstraint!
#IBOutlet weak var preferenceDescription: UILabel!
#IBOutlet weak var preferenceTitle: UILabel!
#IBOutlet weak var tableView: UITableView!
var preferenceValues: [PreferenceValue]?
override func awakeFromNib() {
super.awakeFromNib()
self.tableView.delegate = self
self.tableView.dataSource = self
guard let frameworkBundle = Bundle(identifier: "com.frameworkbundle.asdf") else {
fatalError("Framework bundle identifier is incorrect.")
}
let custPrefHeaderCell = UINib(nibName: "CustPrefMultiSelectPreferenceTableViewCell", bundle: frameworkBundle)
self.tableView.register(custPrefHeaderCell, forCellReuseIdentifier: "CustPrefMultiSelectPreferenceTableViewCell")
self.tableView.rowHeight = UITableView.automaticDimension
self.tableView.estimatedRowHeight = 64.0
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
extension CustPrefMultiSelectTableViewCell: UITableViewDataSource, UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
guard let preferenceValues = self.preferenceValues else {
return 0
}
return preferenceValues.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let preferenceCategories = self.preferenceValues else {
return UITableViewCell()
}
let cell = self.tableView.dequeueReusableCell(withIdentifier: "CustPrefMultiSelectPreferenceTableViewCell", for: indexPath) as! CustPrefMultiSelectPreferenceTableViewCell
cell.preferenceName.text = preferenceCategories[indexPath.row].name
cell.preferenceDescription.text = preferenceCategories[indexPath.row].description
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
}
I thought of an approach by having a height constraint for the inner tableView, and update the outer tableView height when it is ready/reloaded with data. But where should I implement that logic? With a fixed height of inner tableView, I get an unwanted behavior of scrolling. That need to be avoided.
How do I go further with this?
Thanks in advance!
I think using nested tableView is not the best solution, anyway, I hope this example will help you.
struct Foo {
let strings: [String]
}
class NestedViewController: UIViewController {
let dataSource = [Foo(strings: ["String1", "String2"]),
Foo(strings: ["Long long long long long long long long long long long long long string"])]
let tableView: UITableView = {
let tableView = UITableView()
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.register(NestedCell.self, forCellReuseIdentifier: NestedCell.identifier)
tableView.tableFooterView = UIView()
return tableView
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(tableView)
setupConstraints()
tableView.dataSource = self
tableView.delegate = self
tableView.reloadData()
}
func setupConstraints() {
NSLayoutConstraint.activate([
tableView.topAnchor.constraint(equalTo: view.topAnchor),
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
])
}
}
extension NestedViewController: UITableViewDelegate & UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
dataSource.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: NestedCell.identifier, for: indexPath) as? NestedCell else {
return UITableViewCell()
}
cell.setup(foo: dataSource[indexPath.row])
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
NestedCell.heightFor(foo: dataSource[indexPath.row])
}
}
class NestedCell: UITableViewCell {
static let identifier = "NestedCell"
let nestedTableView: UITableView = {
let tableView = UITableView()
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.register(TextCell.self, forCellReuseIdentifier: TextCell.identifier)
tableView.tableFooterView = UIView()
return tableView
}()
private var foo = Foo(strings: [""])
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(nestedTableView)
setConstraints()
nestedTableView.dataSource = self
nestedTableView.delegate = self
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setup(foo: Foo) {
self.foo = foo
nestedTableView.reloadData()
}
static func heightFor(foo: Foo) -> CGFloat {
foo.strings.reduce(0) { $0 + TextCell.heightFor(text: $1) }
}
private func setConstraints() {
NSLayoutConstraint.activate([
nestedTableView.topAnchor.constraint(equalTo: contentView.topAnchor),
nestedTableView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
nestedTableView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
nestedTableView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor)
])
}
}
extension NestedCell: UITableViewDelegate & UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
foo.strings.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: TextCell.identifier, for: indexPath) as? TextCell else {
return UITableViewCell()
}
cell.setup(text: foo.strings[indexPath.row])
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
TextCell.heightFor(text: foo.strings[indexPath.row])
}
}
class TextCell: UITableViewCell {
static let identifier = "TextCell"
static let labelOffset: CGFloat = 10
private let label: UILabel = {
let label = UILabel()
label.numberOfLines = 0
label.font = .systemFont(ofSize: 15, weight: .medium)
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(label)
setConstraints()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setup(text: String) {
label.text = text
}
static func heightFor(text: String) -> CGFloat {
text.height(width: UIScreen.main.bounds.width - 2 * TextCell.labelOffset,
font: .systemFont(ofSize: 15, weight: .medium)) + 2 * TextCell.labelOffset
}
private func setConstraints() {
NSLayoutConstraint.activate([
label.topAnchor.constraint(equalTo: contentView.topAnchor, constant: TextCell.labelOffset),
label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -TextCell.labelOffset),
label.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: TextCell.labelOffset),
label.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -TextCell.labelOffset)
])
}
}
extension String {
func height(width: CGFloat, font: UIFont) -> CGFloat {
let rect = CGSize(width: width, height: .greatestFiniteMagnitude)
let boundingBox = self.boundingRect(with: rect, options: .usesLineFragmentOrigin, attributes: [.font: font], context: nil)
return ceil(boundingBox.height)
}
}

Expandable/Collapsable TableView with Custom Cell for FAQs

I wanted to implement expandable/collapsable UITableView with Custom UITableViewCell that adjusts its side according to the question/answer text. I have tried with different methods but none of it worked as I desire. If there is anyone who has implemented the same thing then kindly share the project link or let me know how it's done. Any kind of help would be greatly appreciated. I am sharing the screenshot of what I wanted.
Here's what I have tried. When I scroll the table view, it adds extra spaces between the cells and also messed up the UITextView.
enter code here
// Mark: Table View Delegate Methods
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let questionTextView = UITextView(frame:CGRect(x: 0, y: 0, width: 265.0, height: 30))
let answerTextView = UITextView(frame:CGRect(x: 0, y: 0, width: 265.0, height: 30))
questionTextView.text = questionStringArray[indexPath.row]
answerTextView.text = answerStringArray[indexPath.row]
Common.adjustUITextViewHeight(questionTextView)
Common.adjustUITextViewHeight(answerTextView)
let cellHeightExpanded:CGFloat = CGFloat(3 + Double(questionTextView.frame.size.height) + 5 + Double(answerTextView.frame.size.height) + 10)
let cellHeightCollapsed:CGFloat = CGFloat(3 + Double(questionTextView.frame.size.height) + 5)
if (indexPath.row == selectedQuestion)
{
return cellHeightExpanded
}
else
{
return cellHeightCollapsed
}
}
// number of rows in table view
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
// create a cell for each table view row
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! FAQsCell
cell.backgroundColor = UIColor.white
cell.tvQuestion.text = questionStringArray[indexPath.row]
cell.tvAnswer.text = answerStringArray[indexPath.row]
Common.adjustUITextViewHeight(cell.tvQuestion)
Common.adjustUITextViewHeight(cell.tvAnswer)
cell.tvAnswer.frame = CGRect(origin: CGPoint(x: cell.tvAnswer.frame.origin.x, y : cell.tvQuestion.frame.origin.y + cell.tvQuestion.frame.size.height), size: CGSize(width: cell.tvAnswer.frame.size.width, height: cell.tvAnswer.frame.size.height))
if indexPath.row == selectedQuestion {
cell.backgroundColor = UIColor.okapiCellGrayColorForPendingAppLevel()
cell.tvQuestion.textColor = UIColor.white
cell.tvAnswer.textColor = UIColor.white
}
else {
cell.backgroundColor = UIColor.clear
cell.tvQuestion.textColor = UIColor.blue_grey_700()
cell.tvAnswer.textColor = UIColor.blue_grey_700()
}
return cell
}
// method to run when table view cell is tapped
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedQuestion = indexPath.row
faqsTableView.reloadData()
}
Add a vertical stackview in the custom cell and show/hide answer based on selected cell
class ViewController: UITableViewController {
var questions = [(question:String,answer:String)]()
var selectedQuestion = -1
override func viewDidLoad() {
super.viewDidLoad()
questions = [(question:"Question 1",answer:"Answer 1"),(question:"Question 2",answer:"Answer 2"),
(question:"Question 3",answer:"Answer 3"),(question:"Question 4",answer:"Answer 4"),
(question:"Question 5",answer:"Answer 5")]
self.view.backgroundColor = .white
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 50
tableView.register(FAQsCell.self, forCellReuseIdentifier: "FAQsCell")
}
}
extension ViewController {
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 50
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return questions.count
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "FAQsCell") as! FAQsCell
cell.questionLbl.text = questions[indexPath.row].question
cell.answerLbl.text = questions[indexPath.row].answer
if indexPath.row == selectedQuestion {
cell.backgroundColor = .groupTableViewBackground
cell.dropDownImgView.image = //upimage
cell.answerView.isHidden = false
} else {
cell.backgroundColor = .white
cell.dropDownImgView.image = //downimage
cell.answerView.isHidden = true
}
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedQuestion = indexPath.row
tableView.reloadData()
}
}
class FAQsCell: UITableViewCell {
let stackView = UIStackView()
let questionLbl = UILabel()
let dropDownImgView = UIImageView()
let answerView = UIView()
let answerLbl = UILabel()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
func commonInit() {
stackView.axis = .vertical
stackView.distribution = .fillProportionally
stackView.spacing = 5
stackView.alignment = .fill
stackView.translatesAutoresizingMaskIntoConstraints = false
addSubview(stackView)
let questionView = UIView()
questionView.translatesAutoresizingMaskIntoConstraints = false
questionView.heightAnchor.constraint(equalToConstant: 35).isActive = true
stackView.addArrangedSubview(questionView)
questionLbl.font = UIFont.boldSystemFont(ofSize: 18)
questionLbl.translatesAutoresizingMaskIntoConstraints = false
questionView.addSubview(questionLbl)
dropDownImgView.contentMode = .scaleAspectFit
dropDownImgView.translatesAutoresizingMaskIntoConstraints = false
questionView.addSubview(dropDownImgView)
answerView.translatesAutoresizingMaskIntoConstraints = false
answerView.heightAnchor.constraint(greaterThanOrEqualToConstant: 35).isActive = true
stackView.addArrangedSubview(answerView)
answerLbl.numberOfLines = 0
answerLbl.lineBreakMode = .byWordWrapping
answerLbl.font = UIFont.systemFont(ofSize: 17)
answerLbl.translatesAutoresizingMaskIntoConstraints = false
answerView.addSubview(answerLbl)
questionView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-(10)-[questionLbl]-(10)-[dropDownImgView(25)]-(10#999)-|", options: [.alignAllCenterY], metrics: nil, views: ["questionLbl":questionLbl, "dropDownImgView": dropDownImgView]))
dropDownImgView.heightAnchor.constraint(equalTo: dropDownImgView.widthAnchor).isActive = true
questionView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-(5)-[questionLbl(25)]-(5)-|", options: [], metrics: nil, views: ["questionLbl":questionLbl]))
answerView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-(10)-[answerLbl]-(10)-|", options: [], metrics: nil, views: ["answerLbl":answerLbl]))
answerView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-(5)-[answerLbl(>=25)]-(5)-|", options: [], metrics: nil, views: ["answerLbl":answerLbl]))
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-(5)-[stackView]-(5#999)-|", options: [], metrics: nil, views: ["stackView":stackView]))
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-(5)-[stackView]-(5)-|", options: [], metrics: nil, views: ["stackView":stackView]))
}
}
you can achieve through constraint.
give title and description constraint to bottom to superview.
after that change priority of constraint accordingly.
let me know if you want to understand through imagee.

UITableViewAutomaticDimension is not working

I had set estimatedheight and height of tableview to UIAutomaticDimension but i am getting increased label height.
I tried changing label.preferredMaxLayoutWidth but still not working.
I had set estimatedheight and height of tableview to UIAutomaticDimension but i am getting increased label height.
I tried changing label.preferredMaxLayoutWidth but still not working.
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let buildingArr = buildingViolationArray {
return buildingArr.count
}
return 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: Language.sharedInstance.isEnglish ? "CELL" : "CELL_AR", for: indexPath) as! BuildingViolationHeaderTableViewCell
if let buildingViolationsDict = buildingViolationArray?[indexPath.row] {
cell.followUpNoLbl.text = buildingViolationsDict["followupNo"] as? String
cell.violationTypeLbl.text = buildingViolationsDict[Language.sharedInstance.isEnglish ? "violationType" : "violationTypeArb"] as? String
cell.bvBtn.addTarget(self, action: #selector(BuildinVioClicked), for: .touchUpInside)
if buildingViolationsDict[kIsSelectedKey] as? Bool == true {
cell.isCellSelected = true
let buildingVioView = getZoneRegView(buildingViolationsDict)
buildingVioView.tag = 1
for removeSubViews in cell.bvStackView.subviews {
removeSubViews.removeFromSuperview()
cell.bvStackView.removeArrangedSubview(removeSubViews)
}
cell.bvStackView.addArrangedSubview(buildingVioView)
cell.expandImage.image = UIImage(named: "minus-256")
} else {
cell.isCellSelected = false
for removeSubViews in cell.bvStackView.subviews {
removeSubViews.removeFromSuperview()
cell.bvStackView.removeArrangedSubview(removeSubViews)
}
cell.expandImage.image = UIImage(named: "plus-256")
}
cell.violationTypeLbl.preferredMaxLayoutWidth = cell.violationTypeLbl.frame.size.width
}
cell.selectionStyle = .none
return cell
}
func BuildinVioClicked(sender: UIButton){
let location = sender.convert(CGPoint.zero, to: bvTableView)
let indexPath = bvTableView.indexPathForRow(at: location)!
if var buildingViolationsDict = buildingViolationArray?[indexPath.row] {
if let isSelect = buildingViolationsDict[kIsSelectedKey] as? Bool, isSelect {
(buildingViolationArray[indexPath.row])[kIsSelectedKey] = false
} else {
(buildingViolationArray[indexPath.row])[kIsSelectedKey] = true
}
bvTableView.reloadData()
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
Beside setting the estimatedRowHeight to UITableViewAutomaticDimension (In Swift 4, UITableViewAutomaticDimension has been renamed into UITableView.automaticDimension). You ought to properly set your cell constraint.
class YourCell: UITableViewCell {
lazy var label: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont.systemFont(ofSize: 12)
label.numberOfLines = 0 // This property will allow the label according to his content
return label
}()
func addLabelIntoView() {
contentView.addSubview(label)
let margin = contentView.layoutMarginsGuide
NSLayoutConstraint.activate([
label.leadingAnchor.constraint(equalTo: margin.leadingAnchor),
label.trailingAnchor.constraint(equalTo: margin.trailingAnchor),
label.topAnchor.constraint(equalTo: margin.topAnchor),
label.bottomAnchor.constraint(equalTo: margin.bottomAnchor) // Pins bottom of label into the bottom of the view
])
}
}

Swift: Table with cells (same properties different content; clickable )

I need to create a table with 50 rectangular cells and:
All of the cells must have the same properties but different contents;
Each cell has to be clickable;
Cells must have different items inside of them (images, labels etc).
I started programming recently and I'm 16 so please don't bite my head off if I wasn't clear or whatever...
By the way I tried to create a table view with custom cells but I'm not sure it's working, plus I'm in landscape mode so maybe I need to create them programmatically... Can you just please tell me if I'm doing it right using the custom cells and maybe give me some advice or send me some tutorials for these things I need to do?
Don't worry. Go ahead in your achieve. Here are some examples for you.
Your ViewController
class MyViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
let tableReuseIdentifier = "TableCell"
let tableView: UITableView! = {
let table = UITableView(frame: .zero, style: UITableViewStyle.grouped)
table.backgroundColor = .clear
table.translatesAutoresizingMaskIntoConstraints = false
table.isUserInteractionEnabled = true
table.isMultipleTouchEnabled = true
return table
}()
var items: [U]? = []
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
//registering your customCell into tableView
self.tableView!.register(MyCustomCell.self, forCellReuseIdentifier: tableReuseIdentifier)
}
public func setupViews() {
tableView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
}
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items?.count ?? 0
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: MyCustomCell = tableView.dequeueReusableCell(withIdentifier: tableReuseIdentifier, for: indexPath) as! MyCustomCell
//here you can manipulate some data to insert on cell
return cell
}
public func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 60
}
public func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 0
}
public func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 0
}
public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("When cell has been selected")
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
return true
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
return nil
}
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
return nil
}
}
Your Custom Cell:
class MyCustomCell: UITableViewCell {
// attribute example
let lblCompanyName: UILabel = {
let label = UILabel()
label.textColor = .lightGray
label.font = UIFont.systemFont(ofSize: 17, weight: .bold)
label.adjustsFontSizeToFitWidth = true
label.minimumScaleFactor = 0.6
label.numberOfLines = 2
label.setContentHuggingPriority(UILayoutPriority.defaultHigh, for: UILayoutConstraintAxis.vertical)
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
// attribute example
let lblFrequencies: UILabel = {
let label = UILabel()
label.textColor = .black
label.font = UIFont.systemFont(ofSize: 13, weight: .bold)
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
label.setContentHuggingPriority(UILayoutPriority.defaultLow, for: UILayoutConstraintAxis.vertical)
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
// attribute like imageView example
let imageLogo: UIImageView = {
let image = UIImageView()
image.translatesAutoresizingMaskIntoConstraints = false
image.contentMode = .scaleAspectFit
image.setContentCompressionResistancePriority(UILayoutPriority.defaultHigh, for: UILayoutConstraintAxis.vertical)
image.setContentHuggingPriority(UILayoutPriority.defaultHigh, for: UILayoutConstraintAxis.horizontal)
return image
}()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
[imageLogo, lblCompanyName, lblFrequencies].forEach { (view) in contentView.addSubview(view) }
let top: CGFloat = 20, bottom: CGFloat = -20, leading: CGFloat = 20, trailing: CGFloat = -20
self.imageLogo.topAnchor.constraint(equalTo: contentView.topAnchor, constant: top).isActive = true
self.imageLogo.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: bottom).isActive = true
self.imageLogo.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: leading).isActive = true
self.imageLogo.widthAnchor.constraint(equalTo: imageLogo.heightAnchor).isActive = true
self.lblCompanyName.topAnchor.constraint(equalTo: contentView.topAnchor, constant: top).isActive = true
self.lblCompanyName.leadingAnchor.constraint(equalTo: self.imageLogo.trailingAnchor, constant: 20).isActive = true
self.lblCompanyName.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: trailing).isActive = true
self.lblFrequencies.topAnchor.constraint(equalTo: self.lblCompanyName.bottomAnchor, constant: 5).isActive = true
self.lblFrequencies.leadingAnchor.constraint(equalTo: self.imageLogo.trailingAnchor, constant: 20).isActive = true
self.lblFrequencies.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: trailing).isActive = true
}
}
Hope it helped you. Cheers.

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)

Resources