Is there any way to resize UIImageView inside UITableViewCell - ios

I'm trying to add image inside of UITableViewCell with UIImageView, and really added "normally", but when i change the size of UIImageView. I get this error message:
[LayoutConstraints] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one
you don't want. Try this: (1) look at each constraint and try to
figure out which you don't expect; (2) find the code that added the
unwanted constraint or constraints and fix it. (
"<NSLayoutConstraint:0x600001a30b40 UIImageView:0x7fad5ed0fd90.height == 90 (active)>",
"<NSLayoutConstraint:0x600001a30b90 V:|-(0)-[UIStackView:0x7fad5ed10360] (active, names:
'|':Music.MusicsCell:0x7fad5ed0ec20'cellId' )>",
"<NSLayoutConstraint:0x600001a30d70 UIStackView:0x7fad5ed10360.bottom ==
Music.MusicsCell:0x7fad5ed0ec20'cellId'.bottom (active)>",
"<NSLayoutConstraint:0x600001a31270 'UISV-canvas-connection' UIStackView:0x7fad5ed10360.top == UIImageView:0x7fad5ed0fd90.top
(active)>",
"<NSLayoutConstraint:0x600001a312c0 'UISV-canvas-connection' V:[UIImageView:0x7fad5ed0fd90]-(0)-| (active, names:
'|':UIStackView:0x7fad5ed10360 )>",
"<NSLayoutConstraint:0x600001a314f0 'UIView-Encapsulated-Layout-Height'
Music.MusicsCell:0x7fad5ed0ec20'cellId'.height == 90.5 (active)>" )
Will attempt to recover by breaking constraint
but i've tried many things, like simple things, just image with background and size, example:
let imageView: UIImageView = UIImageView()
imageView.size(size: CGSize(width: 40, height: 40))
imageView.backgroundColor = .purple
imageView.layer.cornerRadius = 6
imageView.clipsToBounds = true
and I don't know what I have to disappear this warning message.
Follow the code below:
MusicsVC (UITableViewController):
class MusicsVC: UITableViewController {
let cellId = "cellId"
override func viewDidLoad() {
super.viewDidLoad();
tableView.register(MusicsCell.self, forCellReuseIdentifier: cellId)
}
}
extension MusicsVC {
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5;
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! MusicsCell
return cell;
}
}
UITableViewCell:
class MusicsCell: UITableViewCell {
let tituloLabel: UILabel = .textLabel(text: "Teste", fontSize: 16);
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
let imageView: UIImageView = UIImageView()
imageView.size(size: CGSize(width: 60, height: 60))
imageView.layer.cornerRadius = 6
imageView.clipsToBounds = true
imageView.load(url: "https://studiosol-a.akamaihd.net/uploadfile/letras/fotos/d/7/4/2/d74238794c3024afbcba997e444fd2cb.jpg")
let stackView = UIStackView(arrangedSubviews: [
imageView,
tituloLabel
])
stackView.spacing = 12
addSubview(stackView)
stackView.inset(view: stackView, insets: UIEdgeInsets(top: 6, left: 12, bottom: 6, right: 12))
}
required init?(coder: NSCoder) {
fatalError()
}
}

I suppose do you want this, but your code is a little bit confused to know what you really you want... Declare your table view, and add constraints :
class ViewController: UIViewController {
let tableView = UITableView()
let cellId = "cellId"
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
tableView.delegate = self
tableView.dataSource = self
tableView.register(MusicsCell.self, forCellReuseIdentifier: cellId)
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
tableView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
tableView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
tableView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
}
}
now delegate and datasource
extension ViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 72 // 60 image view height + 6x2 padding from top and bottom = 72
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! MusicsCell
return cell;
}
}
and this how your cell looks like:
class MusicsCell: UITableViewCell {
let tituloLabel: UILabel = {
let label = UILabel()
label.text = "Testo"
label.font = .systemFont(ofSize: 16, weight: .regular)
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let myImageView: UIImageView = {
let iv = UIImageView()
iv.contentMode = .scaleAspectFill
iv.layer.cornerRadius = 6
iv.clipsToBounds = true
iv.translatesAutoresizingMaskIntoConstraints = false
return iv
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
guard let url = URL(string: "https://studiosol-a.akamaihd.net/uploadfile/letras/fotos/d/7/4/2/d74238794c3024afbcba997e444fd2cb.jpg") else {return}
myImageView.downloadImage(from: url) // this is my extension to load image from url, you can use yours
contentView.addSubview(myImageView)
myImageView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 6).isActive = true
myImageView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 12).isActive = true
myImageView.widthAnchor.constraint(equalToConstant: 60).isActive = true
myImageView.heightAnchor.constraint(equalToConstant: 60).isActive = true
contentView.addSubview(tituloLabel)
tituloLabel.topAnchor.constraint(equalTo: myImageView.topAnchor).isActive = true
tituloLabel.leadingAnchor.constraint(equalTo: myImageView.trailingAnchor, constant: 10).isActive = true
tituloLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true
tituloLabel.bottomAnchor.constraint(equalTo: myImageView.bottomAnchor).isActive = true
}
required init?(coder: NSCoder) {
fatalError()
}
}
and this is the result

Related

NSLayoutConstraints to limit label width

I am struggling to set the necessary constraints to limit the width of a label to the leading anchor of a button in a tableview cell.
Desired Result
Label to the left, button to the right. Label wraps before button if needed.
Current Result
The label is pulling the red button to the left.
Code
[button.centerYAnchor constraintEqualToAnchor:cell.contentView.centerYAnchor constant:0].active = YES;
[button.trailingAnchor constraintEqualToAnchor:cell.contentView.trailingAnchor constant:-5].active = YES;
[label.leadingAnchor constraintEqualToAnchor:cell.contentView.leadingAnchor constant:10].active = YES;
[label.trailingAnchor constraintEqualToAnchor:button.leadingAnchor constant:0].active = YES;
I have tried various things like adding another label constraint to the right of the cell but that squeezed the button (I tried to fix by setting its compression resistance priority but that had no effect)
What constraints do I need to achieve the desired result please?
Just change
[label.trailingAnchor constraintEqualToAnchor:button.leadingAnchor constant:0].active = YES;
into
[label.trailingAnchor constraintLessThanOrEqualToAnchor:button.leadingAnchor constant:0].active = YES;
import UIKit
final class ViewController: UIViewController {
lazy var tableView: UITableView = {
let val = UITableView(frame: self.view.bounds, style: .plain)
val.dataSource = self
val.delegate = self
val.estimatedRowHeight = 44
val.register(MyCell.self, forCellReuseIdentifier: "MyCell")
return val
}()
let data: [String] = [
"LayoutDemo",
"LayoutDemo LayoutDemo LayoutDemo LayoutDemo LayoutDemo LayoutDemo LayoutDemo LayoutDemo LayoutDemo LayoutDemo LayoutDemo LayoutDemo",
"LayoutDemoLayoutDemoLayoutDemoLayoutDemo"
]
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(tableView)
}
}
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
data.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) as? MyCell else { fatalError() }
cell.dataText = data[indexPath.row]
return cell
}
}
extension ViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
}
class MyCell: UITableViewCell {
var dataText: String? {
didSet {
label.text = dataText
}
}
lazy var label: UILabel = {
let val = UILabel(frame: .zero)
val.translatesAutoresizingMaskIntoConstraints = false
val.numberOfLines = 0
val.backgroundColor = .gray
return val
}()
lazy var button: UIButton = {
let val = UIButton(type: .custom)
val.translatesAutoresizingMaskIntoConstraints = false
val.backgroundColor = .red
return val
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(label)
contentView.addSubview(button)
NSLayoutConstraint.activate([
button.centerYAnchor.constraint(equalTo: contentView.centerYAnchor),
button.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -5),
button.heightAnchor.constraint(equalToConstant: 20),
button.widthAnchor.constraint(equalToConstant: 20),
label.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 5),
label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -5),
label.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 10),
label.trailingAnchor.constraint(lessThanOrEqualTo: button.leadingAnchor, constant: -10)
])
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

How to create custom cells 100% programmatically in Swift?

I am trying to build a TableView programmatically, but I cannot get a basic standard label to display; all I see is basic empty cells. Here's my code:
TableView Cell:
class TableCell: UITableViewCell {
let cellView: UIView = {
let view = UIView()
view.backgroundColor = .systemRed
return view
}()
let labelView: UILabel = {
let label = UILabel()
label.text = "Cell 1"
return label
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setup()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setup() {
addSubview(cellView)
NSLayoutConstraint.activate([
cellView.topAnchor.constraint(equalTo: topAnchor),
cellView.bottomAnchor.constraint(equalTo: bottomAnchor),
cellView.leadingAnchor.constraint(equalTo: leadingAnchor),
cellView.trailingAnchor.constraint(equalTo: trailingAnchor)])
cellView.addSubview(labelView)
}
}
Data Source:
class TableDataSource: NSObject, UITableViewDataSource {
let cellID = "cell"
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellID, for: indexPath) as! TableCell
return cell
}
}
And this is the VC:
class TableViewController: UITableViewController {
let dataSource = TableDataSource()
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(TableCell.self, forCellReuseIdentifier: dataSource.cellID)
tableView.dataSource = dataSource
}
}
I am trying to keep the code as basic as possible for future references. I've set various breakpoints to see what could go wrong, but they all check out. Could it be the constraints that are wrong?
Any help is appreciated.
I see several errors in your cell.
Add subviews to contentView, not directly to cell:
contentView.addSubview(cellView)
cellView.addSubview(labelView)
The same is necessary for constraints:
NSLayoutConstraint.activate([
cellView.topAnchor.constraint(equalTo: contentView.topAnchor),
cellView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
cellView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
cellView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor)
])
Views created in code need to set translatesAutoresizingMaskIntoConstraints = false,
let cellView: UIView = {
let view = UIView()
view.backgroundColor = .systemRed
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let labelView: UILabel = {
let label = UILabel()
label.text = "Cell 1"
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
There are no constraints for your label.
Your constraints don't work, because you need to change translatesAutoresizingMaskIntoConstraints for cellView in your setup():
func setup() {
addSubview(cellView)
cellView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
cellView.topAnchor.constraint(equalTo: topAnchor),
cellView.bottomAnchor.constraint(equalTo: bottomAnchor),
cellView.leadingAnchor.constraint(equalTo: leadingAnchor),
cellView.trailingAnchor.constraint(equalTo: trailingAnchor)])
cellView.addSubview(labelView)
}

how to add custom view on UITableViewCell programatically?

UPD Resolved - see edited question below
Trying to add a custom view (button, to be more specific) to a custom subclass of UITableViewCell but unable to see any layout results on iOS 10.1 on the device. Did not see any changes on the layout, and tried to just fill the cell with a custom view with the red background but failed to achieve this result as well.
import UIKit
class Save: UITableViewCell {
let containerView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .red
return view
}()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupViews()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupViews() {
self.translatesAutoresizingMaskIntoConstraints = false
addSubview(containerView)
containerView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
containerView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
containerView.topAnchor.constraint(equalTo: topAnchor).isActive = true
containerView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
}
}
What I tried besides that: using plain addSubiew and constraint to the self anchors of the cell, and add to contentView in tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) but both approaches did nothing, the cell appears but it is empty.
UPD
attaching the TableView initiation code for the reference
class SettingsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
let settings = [
"setting1",
"setting2",
"setting3",
"setting4",
"setting5",
"setting6",
"setting7"
]
let overlay: UIView = {
var view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .gray
view.alpha = 0.3
view.isHidden = true
return view
}()
let tableView: UITableView = {
let tableView = UITableView(frame: .zero, style: .grouped)
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "commonCell")
tableView.register(Save.self, forCellReuseIdentifier: "btnCell")
tableView.register(Switcher.self, forCellReuseIdentifier: "switcherCell")
tableView.headerView(forSection: 0)?.textLabel?.text = "settings of app"
tableView.tableFooterView = UIView()
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = UITableViewAutomaticDimension
tableView.allowsSelection = false
return tableView
}()
override func viewDidLoad() {
super.viewDidLoad()
setupViews()
}
func setupViews() {
view.backgroundColor = .white
view.addSubview(tableView)
tableView.dataSource = self
tableView.delegate = self
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
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
tabBarController?.navigationItem.rightBarButtonItems = []
tabBarController?.navigationItem.title = "settings"
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return settings.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return "settings"
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "commonCell", for: indexPath)
cell.textLabel?.text = settings[indexPath.row]
if(indexPath.row == 6) {
cell.textLabel?.text = ""
cell = tableView.dequeueReusableCell(withIdentifier: "btnCell", for: indexPath)
}
return cell
}
}
RESOLVED
in addition to Sh_Khan answer, it was required to set
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 65
on the table
It doesn't look like it's anything wrong with the code in your cell class in my eyes. Can you please add your tableviewcode?
You should either implement
heightForRowAt
Or add
containerView.heightAnchor.constraint(equalToConstant:200).isActive = true
Also add any subview to contentView
contentView.addSubview(containerView)
NSLayoutConstraint.activate([
containerView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
containerView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
containerView.topAnchor.constraint(equalTo: contentView.topAnchor),
containerView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
containerView.heightAnchor.constraint(equalToConstant:200)
])

How to expand and collapse tableview cells with dynamic height programmatically?

Here is a video of my problem: https://imgur.com/a/qvGSLfD
My custom cell has 2 labels: one main label, and a subtitle label, both of which are constrained to the cell's contentView layoutMarginsGuide in all directions.
First of all, the whole expand collapse mechanism seems a bit clunky since I'm activating and deactivating constraints and then reloading the indexPaths.
I've tried this approach: When I select the cell, I deactivate the constraints that are responsible for setting only one label and activate the constraints for both, and when it collapses I do the opposite. I feel like this is not a good approach but I was not able to find anything that supported dynamic cell heights.
Basically, I could’ve done something like this:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.row == selectedRowIndex {
return 200 //Expanded
}
return tableView.rowHeight //Not expanded
}
but I can't just return the same number for cells that are sized differently.
Here is my tableView code in my viewController class:
var tableView: UITableView = {
let tv = UITableView(frame: .zero)
tv.register(CustomCell.self, forCellReuseIdentifier: CustomCell.reuseIdentifier())
tv.translatesAutoresizingMaskIntoConstraints = false
tv.rowHeight = UITableView.automaticDimension
tv.estimatedRowHeight = 60.0
tv.estimatedSectionHeaderHeight = 0
tv.estimatedSectionFooterHeight = 0
tv.showsVerticalScrollIndicator = false
tv.tableFooterView = UIView()
tv.alwaysBounceVertical = true
tv.decelerationRate = .fast
tv.bounces = false
tv.dataSource = self
tv.delegate = self
return tv
}()
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: CustomCell.reuseIdentifier(), for: indexPath) as! CustomCell
cell.bounds = CGRect(x: 0, y: 0, width: tableView.bounds.width, height: 99999)
cell.contentView.bounds = cell.bounds
cell.layoutIfNeeded()
cell.wordLabel.preferredMaxLayoutWidth = cell.wordLabel.frame.width
cell.descriptionLabel.preferredMaxLayoutWidth = cell.descriptionLabel.frame.width
//customize this later
cell.backgroundColor = .white
cell.set(content: datasource[indexPath.row])
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as! CustomCell
cell.toggle()
tableView.reloadRows(at: [indexPath], with: .automatic)
}
Here are the relevant custom Cell functions:
var isExpanded: Bool!
private var singleLabelConstraints: [NSLayoutConstraint]!
private var doubleLabelConstraints: [NSLayoutConstraint]!
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupLabels()
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupLabels()
}
func toggle() {
isExpanded = !isExpanded
if isExpanded == false {
print("collapsed")
self.descriptionLabel.isHidden = true
NSLayoutConstraint.activate(singleLabelConstraints)
NSLayoutConstraint.deactivate(doubleLabelConstraints)
} else if isExpanded == true {
print("expanded")
self.descriptionLabel.isHidden = false
NSLayoutConstraint.deactivate(singleLabelConstraints)
NSLayoutConstraint.activate(doubleLabelConstraints)
}
}
func setupLabels() {
isExpanded = false
descriptionLabel.isHidden = true
self.contentView.addSubview(wordLabel)
self.contentView.addSubview(descriptionLabel)
singleLabelConstraints = [
wordLabel.leadingAnchor.constraint(
equalTo: self.contentView.layoutMarginsGuide.leadingAnchor,
constant: labelInsets.left
),
wordLabel.topAnchor.constraint(
equalTo: self.contentView.layoutMarginsGuide.topAnchor,
constant: labelInsets.top
),
wordLabel.trailingAnchor.constraint(
equalTo: self.contentView.layoutMarginsGuide.trailingAnchor,
constant: labelInsets.right
),
wordLabel.bottomAnchor.constraint(
equalTo: self.contentView.layoutMarginsGuide.bottomAnchor,
constant: labelInsets.bottom
)
]
doubleLabelConstraints = [
wordLabel.leadingAnchor.constraint(
equalTo: self.contentView.layoutMarginsGuide.leadingAnchor,
constant: labelInsets.left
),
wordLabel.topAnchor.constraint(
equalTo: self.contentView.layoutMarginsGuide.topAnchor,
constant: labelInsets.top
),
wordLabel.trailingAnchor.constraint(
equalTo: self.contentView.layoutMarginsGuide.trailingAnchor,
constant: labelInsets.right
),
descriptionLabel.leadingAnchor.constraint(
equalTo: self.contentView.layoutMarginsGuide.leadingAnchor,
constant: labelInsets.left
),
descriptionLabel.topAnchor.constraint(
equalTo: self.wordLabel.bottomAnchor,
constant: labelInsets.top
),
descriptionLabel.trailingAnchor.constraint(
equalTo: self.contentView.layoutMarginsGuide.trailingAnchor,
constant: labelInsets.right
),
descriptionLabel.bottomAnchor.constraint(
equalTo: self.contentView.layoutMarginsGuide.bottomAnchor,
constant: labelInsets.bottom
)
]
NSLayoutConstraint.activate(singleLabelConstraints)
}
I expected the transition to be smoother and I want something that can easily toggle the cell while keeping the main label in place and just show then subtitle label.
You can use UIStackView for expand and collapse tableview. You can hide and show the description label when tableview cell is selected.
class ViewController: UIViewController {
var tableView: UITableView = {
let tv = UITableView(frame: .zero)
tv.register(CustomCell.self, forCellReuseIdentifier: "CustomCell")
tv.translatesAutoresizingMaskIntoConstraints = false
tv.rowHeight = UITableView.automaticDimension
tv.estimatedRowHeight = 100.0
tv.estimatedSectionHeaderHeight = 0
tv.estimatedSectionFooterHeight = 0
tv.showsVerticalScrollIndicator = false
tv.tableFooterView = UIView()
tv.alwaysBounceVertical = true
tv.decelerationRate = .fast
tv.bounces = false
return tv
}()
var selectedCell:IndexPath?
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(tableView)
tableView.dataSource = self
tableView.delegate = self
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[tableView]|", options: [], metrics: nil, views: ["tableView":tableView]))
self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[tableView]|", options: [], metrics: nil, views: ["tableView":tableView]))
}
}
extension ViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell") as? CustomCell ?? CustomCell()
if let selectedCell = selectedCell, selectedCell == indexPath {
cell.descriptionLabel.isHidden = false
} else {
cell.descriptionLabel.isHidden = true
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedCell = indexPath
tableView.reloadData()
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
}
class CustomCell: UITableViewCell {
let stackView = UIStackView()
let wordLabel = UILabel()
let descriptionLabel = UILabel()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupLabels()
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupLabels()
}
func setupLabels() {
selectionStyle = .none
stackView.axis = .vertical
stackView.distribution = .equalSpacing
stackView.spacing = 5
stackView.alignment = .fill
stackView.translatesAutoresizingMaskIntoConstraints = false
self.contentView.addSubview(stackView)
wordLabel.translatesAutoresizingMaskIntoConstraints = false
wordLabel.text = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lor"
wordLabel.numberOfLines = 0
wordLabel.lineBreakMode = .byWordWrapping
stackView.addArrangedSubview(wordLabel)
descriptionLabel.translatesAutoresizingMaskIntoConstraints = false
descriptionLabel.text = "It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."
descriptionLabel.numberOfLines = 0
descriptionLabel.lineBreakMode = .byWordWrapping
stackView.addArrangedSubview(descriptionLabel)
wordLabel.heightAnchor.constraint(greaterThanOrEqualToConstant: 30).isActive = true
descriptionLabel.heightAnchor.constraint(greaterThanOrEqualToConstant: 30).isActive = true
stackView.leadingAnchor.constraint(equalTo: self.contentView.layoutMarginsGuide.leadingAnchor,constant: 10).isActive = true
stackView.topAnchor.constraint(equalTo: self.contentView.layoutMarginsGuide.topAnchor,constant: 10).isActive = true
stackView.trailingAnchor.constraint(equalTo: self.contentView.layoutMarginsGuide.trailingAnchor,constant: 10).isActive = true
stackView.bottomAnchor.constraint(equalTo: self.contentView.layoutMarginsGuide.bottomAnchor,constant: 10).isActive = true
}
}
Try this:
tableView.beginUpdates()
tableView.reloadRows(at: [indexPath], with: .automatic)
tableView.endUpdates()
hello there you can overcome the problem by going through this link below,
http://vasundharavision.com/blog/ios/expandable-tableview-without-third-party
i hope it works for you.

UITableView not appearing properly using constraints

I'm having problems displaying this UITableView under the UIImageView. It does this weird thing, where you can't see the table or anything at all, however when you scroll up or down, you can see the blue cell appear in the 40px high UITableView.
class TvDetailHeader: UICollectionViewCell, UITableViewDelegate, UITableViewDataSource {
private let contributorCellId = "contributorCellId"
let thumbnailImageView: UIImageView = {
let imageView = UIImageView(image: #imageLiteral(resourceName: "stranger things poster"))
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.layer.cornerRadius = 6
imageView.contentMode = .scaleAspectFill
imageView.layer.masksToBounds = true
return imageView
}()
let contributorTableView: UITableView = {
let tableView = UITableView()
tableView.separatorStyle = .none
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.backgroundColor = .blue
return tableView
}()
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: contributorCellId, for: indexPath) as! ContributorCell
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 40
}
override func setupViews() {
super.setupViews()
contributorTableView.delegate = self
contributorTableView.dataSource = self
contributorTableView.register(ContributorCell.self, forCellReuseIdentifier: contributorCellId)
backgroundColor = .white
addSubview(thumbnailImageView)
addSubview(contributorTableView)
thumbnailImageView.topAnchor.constraint(equalTo: topAnchor, constant: 25).isActive = true
thumbnailImageView.leftAnchor.constraint(equalTo: leftAnchor, constant: 20).isActive = true
thumbnailImageView.widthAnchor.constraint(equalToConstant: 60).isActive = true
thumbnailImageView.heightAnchor.constraint(equalToConstant: 90).isActive = true
contributorTableView.topAnchor.constraint(equalTo: thumbnailImageView.bottomAnchor, constant: 10).isActive = true
contributorTableView.leftAnchor.constraint(equalTo: leftAnchor, constant: 20).isActive = true
contributorTableView.widthAnchor.constraint(equalToConstant: frame.width).isActive = true
contributorTableView.heightAnchor.constraint(equalToConstant: 40).isActive = true
}
}
class ContributorCell: UITableViewCell {
let cellView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupViews() {
addSubview(cellView)
backgroundColor = .blue
cellView.topAnchor.constraint(equalTo: topAnchor, constant: 0).isActive = true
cellView.leftAnchor.constraint(equalTo: leftAnchor, constant: 0).isActive = true
cellView.widthAnchor.constraint(equalToConstant: 30).isActive = true
cellView.heightAnchor.constraint(equalToConstant: frame.height).isActive = true
}
}

Resources