UITableViewAutomaticDimension is not working - ios

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
])
}
}

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)
}
}

AutoResizing header & Cell in Programmatically UITableView

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.

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.

UITableViewCell from Xib, cell hight and cell selection area

I have a UITableViewController, which has a custom cell that I want to display an image and labels. screenshots can explain my problem very well, it looks like this
.
And when I select any cell it looks like
In tableviewcontroller cell is not visible in proper shape according to constraints
here is my custom cell with autolayout constraints
How I can fix this issue? ... I created this tableviewcontroller programmatically without using storyboard.
here is code sample of data source and delegates of tableviewcontroller
override func numberOfSections(in tableView: UITableView) -> Int {
var numOfSections: Int = 0
let count = conversations.count
if count > 0 {
// tableView.separatorStyle = .none
numOfSections = 1
tableView.backgroundView = nil
}
else
{
let frame = CGRect(x: 0,
y: 0,
width: tableView.bounds.size.width,
height: tableView.bounds.size.height)
let noDataLabel: UILabel = UILabel(frame: frame)
noDataLabel.text = "You don't have any messages. 🙃"
noDataLabel.textColor = UIColor.black
noDataLabel.textAlignment = .center
tableView.backgroundView = noDataLabel
tableView.separatorStyle = .none
}
return numOfSections
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return conversations.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "inboxCell", for: indexPath) as! InboxCell
cell.conversation = conversations[indexPath.row]
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let uids = conversations[indexPath.row].conversationUseruids
for uid in uids{
if uid == Account.account.user.uid{
}
else{
User.getUser(with: uid, completion: { (user) in
self.selectedUser.append(user!)
})
}
}
tableView.deselectRow(at: indexPath, animated: true)
let index = indexPath.row as Int
messageVC.conversationIndex = index
messageVC.conversation = self.conversations[index]
navigationController?.pushViewController(messageVC, animated: true)
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 80
}
it happen because your image not have upper lower constraint if not working than let me know

ios 11 UITableViewHeaderFooterView not properly scroll in animation

I have collapse and expand animation in UITableView. Tableview has two section in which first section data is collapse and expand. This thing perfectly working with ios 10 but in ios 11 Section view repeated or overlapped with cell data which is expanded.
Below is my code
//MARK: -Table View delegate Method
func numberOfSections(in tableView: UITableView) -> Int {
return read_Localizable("titleHelpSection").components(separatedBy: ",").count
}
//MARK: -Table View Datasource Method
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat{
return 44.0
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
var headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "headerView")
let arrSection = read_Localizable("titleHelpSection").components(separatedBy: ",")
if headerView == nil
{
headerView = UITableViewHeaderFooterView(reuseIdentifier: "headerView")
headerView?.contentView.backgroundColor = UIColor.white
let lblResult = UILabel()
lblResult.tag = 123456
lblResult.font = AppCommonSNMediumFont()
lblResult.textColor = UIColor.black
lblResult.translatesAutoresizingMaskIntoConstraints = false
headerView?.contentView.addSubview(lblResult)
let seperator = UIView()
seperator.translatesAutoresizingMaskIntoConstraints = false
seperator.backgroundColor = UIColor.black
headerView?.contentView.addSubview(seperator)
headerView?.contentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[seperator]|", options: [], metrics: nil, views: ["seperator":seperator]))
headerView?.contentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-[lable]-(>=8)-|", options: [], metrics: nil, views: ["lable":lblResult]))
headerView?.contentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-[lable]-[seperator(1)]|", options: [], metrics: nil, views: ["lable":lblResult,"seperator":seperator]))
}
if let lblResult = headerView?.contentView.viewWithTag(123456) as? UILabel
{
lblResult.text = arrSection[section]
}
return headerView
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 20.0
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0
{
return (arrHelpData.count)
}
else
{
return 1
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0
{
var cell = tableView.dequeueReusableCell(withIdentifier: "HelpCell") as? CellHelp;
if cell == nil {
cell = CellHelp(style: .default, reuseIdentifier: "HelpCell")
cell?.selectionStyle = .none
cell?.txtContain.delegate = self
}
if let objModel = arrHelpData.object(at: indexPath.row) as? HelpModel
{
cell?.lblTitle.text = objModel.helpTitle
if objModel.isExpanded == true
{
cell?.txtContain.text = objModel.helpDesc
}
else
{
cell?.txtContain.text = ""
}
cell?.imgArrow.isHighlighted = !objModel.isExpanded
}
return cell!
}
else
{
var cell = tableView.dequeueReusableCell(withIdentifier: "DefultCell")
if cell == nil
{
cell = UITableViewCell(style: .default, reuseIdentifier: "DefultCell")
cell?.textLabel?.textColor = color1F87A3()
cell?.textLabel?.font = AppCommonSNRegularFont()
cell?.selectionStyle = .none
cell?.textLabel?.numberOfLines = 0
}
cell?.textLabel?.text = read_Localizable("titleSettings")
return cell!
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.section == 0 && indexPath.row < (arrHelpData.count)
{
if let objModel = arrHelpData.object(at: indexPath.row) as? HelpModel
{
if objModel.isExpanded == true
{
objModel.isExpanded = false
}
else
{
objModel.isExpanded = true
}
tableView.reloadData()
}
}
}
Actual view
Section overlapped on cell data
This is very frustrating iOS11 issue, something to do around estimatedHeight issue, If you really want to keep the self sized row and header then u need to go with the below approach.
Declare variable which holds the height of the cell/header and store height into that and used it as below:
var cellHeightDictionary: NSMutableDictionary // To overcome the issue of iOS11.2
override func viewDidLoad() {
super.viewDidLoad()
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 125
}
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cellHeightDictionary.setObject(cell.frame.size.height, forKey: indexPath as NSCopying)
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
if cellHeightDictionary.object(forKey: indexPath) != nil {
let height = cellHeightDictionary.object(forKey: indexPath) as! CGFloat
return height
}
return UITableViewAutomaticDimension
}
This is the only solution which worked for me for iOS11 issues with auto sizing cells. Otherwise people suggest to keep estimatedHeight 0 to get rid off such issues.
In your case first try doing this for cell and that doesn't solve the issue completely then do same for header height also. Hope this helps!
Don't forget to test in both iOS11.1 and iOS11.2.

Resources