Simulate a cell like in between two cells and below two cells - swift

I am using tableview and collection view inside to create this screen.
If you look closer in the design..i will have to create an effect of cells going above below or top cell with a corner radius...which simulates like the cells are below and in between two cells...
The same goes for the top area which has a corner radius.
Please guide through a proper way to design this entire screen.
(I am using storyboard and UIKit only...i dont want to use swiftUI)

Various ways to approach this -- here's one...
Four cell types:
"Top" cell
"Categories" cell
"Top Products" cell
"Suggestions" cell
In each cell class, add a UIView with rounded corners - this will hold the "content" of each cell.
Behind the rounded corners view, add a "Top Color" UIView and a a "Bottom Color" UIView.
It looks like this:
When running, we get this result:
Here is some sample code:
class MyBaseCell: UITableViewCell {
var topBotColors: [UIColor] = [.white, .white] {
didSet {
topColorView.backgroundColor = topBotColors[0]
botColorView.backgroundColor = topBotColors[1]
}
}
let theStack: UIStackView = {
let v = UIStackView()
v.axis = .vertical
v.spacing = 12
return v
}()
let topColorView = UIView()
let botColorView = UIView()
let roundedCornerView = UIView()
var topConstraint: NSLayoutConstraint!
var botConstraint: NSLayoutConstraint!
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() {
[topColorView, botColorView, roundedCornerView].forEach { v in
v.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(v)
}
theStack.translatesAutoresizingMaskIntoConstraints = false
roundedCornerView.addSubview(theStack)
let g = contentView.layoutMarginsGuide
topConstraint = theStack.topAnchor.constraint(equalTo: roundedCornerView.topAnchor, constant: 12.0)
botConstraint = theStack.bottomAnchor.constraint(equalTo: roundedCornerView.bottomAnchor, constant: -12.0)
NSLayoutConstraint.activate([
topColorView.topAnchor.constraint(equalTo: contentView.topAnchor),
topColorView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
topColorView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
botColorView.topAnchor.constraint(equalTo: topColorView.bottomAnchor),
botColorView.heightAnchor.constraint(equalTo: topColorView.heightAnchor),
botColorView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
botColorView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
botColorView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
roundedCornerView.topAnchor.constraint(equalTo: g.topAnchor),
roundedCornerView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
roundedCornerView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
roundedCornerView.bottomAnchor.constraint(equalTo: g.bottomAnchor),
theStack.leadingAnchor.constraint(equalTo: roundedCornerView.leadingAnchor),
theStack.trailingAnchor.constraint(equalTo: roundedCornerView.trailingAnchor),
topConstraint, botConstraint,
])
self.backgroundColor = .clear
contentView.backgroundColor = .clear
}
}
class TopCell: MyBaseCell {
override func commonInit() {
super.commonInit()
// let's add 1 tall label
let v = UILabel()
v.textAlignment = .center
v.text = "Top Cell"
v.textColor = .white
v.font = .systemFont(ofSize: 24.0, weight: .bold)
theStack.addArrangedSubview(v)
// avoid auot-layout complaints
let c = v.heightAnchor.constraint(equalToConstant: 80.0)
c.priority = .required - 1
c.isActive = true
}
}
class CatsCell: MyBaseCell {
override func commonInit() {
super.commonInit()
// let's add a few labels
for i in 1...4 {
let v = UILabel()
v.textAlignment = .center
v.text = "Categories Label \(i)"
theStack.addArrangedSubview(v)
}
roundedCornerView.backgroundColor = .white
roundedCornerView.layer.cornerRadius = 24
}
}
class TopProdsCell: MyBaseCell {
override func commonInit() {
super.commonInit()
// let's add a few labels
for i in 1...3 {
let v = UILabel()
v.textAlignment = .center
v.text = "Top Prods Label \(i)"
v.textColor = .white
theStack.addArrangedSubview(v)
}
roundedCornerView.backgroundColor = .clear
// increase top/bottom "spacing"
topConstraint.constant = 24.0
botConstraint.constant = -24.0
}
}
class SuggestionsCell: MyBaseCell {
override func commonInit() {
super.commonInit()
// let's add a few labels
for i in 1...6 {
let v = UILabel()
v.textAlignment = .center
v.text = "Suggested Label \(i)"
theStack.addArrangedSubview(v)
}
roundedCornerView.backgroundColor = .white
roundedCornerView.layer.cornerRadius = 24
}
}
class SampleTableVC: UIViewController, UITableViewDataSource, UITableViewDelegate {
let tableView = UITableView()
let myGray: UIColor = .gray
let myBlue: UIColor = UIColor(red: 0.25, green: 0.30, blue: 0.65, alpha: 1.0)
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
tableView.topAnchor.constraint(equalTo: g.topAnchor, constant: 0.0),
tableView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
tableView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
tableView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: 0.0),
])
tableView.register(TopCell.self, forCellReuseIdentifier: "topCell")
tableView.register(CatsCell.self, forCellReuseIdentifier: "catCell")
tableView.register(TopProdsCell.self, forCellReuseIdentifier: "prodCell")
tableView.register(SuggestionsCell.self, forCellReuseIdentifier: "suggCell")
tableView.dataSource = self
tableView.delegate = self
let bkv = UIView()
bkv.backgroundColor = myGray
tableView.backgroundView = bkv
tableView.separatorStyle = .none
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let c = tableView.dequeueReusableCell(withIdentifier: "topCell", for: indexPath) as! TopCell
c.topBotColors = [myGray, myGray]
return c
}
if indexPath.row == 1 {
let c = tableView.dequeueReusableCell(withIdentifier: "catCell", for: indexPath) as! CatsCell
c.topBotColors = [myGray, myBlue]
return c
}
if indexPath.row == 2 {
let c = tableView.dequeueReusableCell(withIdentifier: "prodCell", for: indexPath) as! TopProdsCell
c.topBotColors = [myBlue, myBlue]
return c
}
let c = tableView.dequeueReusableCell(withIdentifier: "suggCell", for: indexPath) as! SuggestionsCell
c.topBotColors = [myBlue, myGray]
return c
}
}

Related

change height of TableViewHeader and included UILabel after button click

When I want to set a new long status by pressing the button, my profileStatusLabel height and TableViewHeader height as well don't change.
P.S. sorry about my English, if there are some mistakes
**ProfileHeaderView: UIView
**
import UIKit
...
private lazy var profileStatusLabel: UILabel = {
let profileStatusLabel = UILabel()
profileStatusLabel.numberOfLines = 0
profileStatusLabel.text = "Looking for a big, young, good looking, able to cook female gorilla"
profileStatusLabel.textColor = .gray
profileStatusLabel.font = profileNameLabel.font.withSize(14)
profileStatusLabel.textAlignment = .left
profileStatusLabel.sizeToFit()
profileStatusLabel.translatesAutoresizingMaskIntoConstraints = false
return profileStatusLabel
}()
private lazy var setStatusButton: UIButton = {
let setStatusButton = UIButton()
setStatusButton.backgroundColor = .systemBlue
setStatusButton.layer.cornerRadius = 4
setStatusButton.layer.shadowOffset = CGSize(width: 4, height: 4)
setStatusButton.layer.shadowOpacity = 0.7
setStatusButton.layer.shadowRadius = 4
setStatusButton.layer.shadowColor = UIColor.black.cgColor
setStatusButton.setTitle("Set status", for: .normal)
setStatusButton.setTitleColor(.white, for: .normal)
setStatusButton.titleLabel?.font = setStatusButton.titleLabel?.font.withSize(14)
setStatusButton.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
setStatusButton.translatesAutoresizingMaskIntoConstraints = false
return setStatusButton
}()
private lazy var statusText: String = {
return statusText
}()
private func setupView() {
addSubview(profileImageView)
addSubview(profileNameLabel)
addSubview(profileStatusLabel)
addSubview(statusTextField)
addSubview(setStatusButton)
}
private func setupConstraints() {
NSLayoutConstraint.activate([
profileNameLabel.topAnchor.constraint(equalTo: topAnchor, constant: 27),
profileNameLabel.leadingAnchor.constraint(equalTo: profileImageView.trailingAnchor, constant: 20),
profileNameLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16),
profileNameLabel.heightAnchor.constraint(greaterThanOrEqualToConstant: 30),
profileStatusLabel.topAnchor.constraint(equalTo: profileNameLabel.bottomAnchor, constant: 10),
profileStatusLabel.leadingAnchor.constraint(equalTo: profileImageView.trailingAnchor, constant: 20),
profileStatusLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16),
profileStatusLabel.heightAnchor.constraint(greaterThanOrEqualToConstant: 49),
statusTextField.topAnchor.constraint(equalTo: profileStatusLabel.bottomAnchor, constant: 10),
statusTextField.leadingAnchor.constraint(equalTo: profileImageView.trailingAnchor, constant: 20),
statusTextField.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16),
statusTextField.heightAnchor.constraint(equalToConstant: 40),
setStatusButton.topAnchor.constraint(equalTo: statusTextField.bottomAnchor, constant: 16),
setStatusButton.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16),
setStatusButton.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16),
setStatusButton.heightAnchor.constraint(equalToConstant: 50),
bottomAnchor.constraint(equalTo: setStatusButton.bottomAnchor, constant: 16),
])
}
#objc private func statusTextChanged(_ textField: UITextField) {
statusText = statusTextField.text!
}
#objc private func buttonAction() {
guard statusTextField.text != nil else {
print("Text the status before press the button")
return
}
profileStatusLabel.text = statusText
profileStatusLabel.updateConstraintsIfNeeded()
self.setNeedsUpdateConstraints()
self.layoutIfNeeded()
}
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .systemGray4
setupView()
setupConstraints()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
**MyCustomHeader: UITableViewHeaderFooterView
**
import UIKit
class MyCustomHeader: UITableViewHeaderFooterView {
var profileHeaderView = ProfileHeaderView()
override init(reuseIdentifier: String?) {
super.init(reuseIdentifier: reuseIdentifier)
configureContents()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func configureContents() {
contentView.addSubview(profileHeaderView)
profileHeaderView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
contentView.leadingAnchor.constraint(equalTo: profileHeaderView.leadingAnchor),
contentView.trailingAnchor.constraint(equalTo: profileHeaderView.trailingAnchor),
contentView.widthAnchor.constraint(equalTo: profileHeaderView.widthAnchor),
contentView.heightAnchor.constraint(equalTo: profileHeaderView.heightAnchor),
contentView.topAnchor.constraint(equalTo: profileHeaderView.topAnchor),
])
}
}
**ProfileViewController
**
import UIKit
class ProfileViewController: UIViewController, UIGestureRecognizerDelegate {
let postList = [robberyPost, eatingPost, elephantPost, camelPost]
var profileTableView = UITableView()
let myCustomHeader = MyCustomHeader()
let headerID = "headerId"
let headerID2 = "headerId2"
let cellID = "cellId"
let collectionCellID = "collectionCellId"
...
func setupTableView() {
profileTableView.contentInsetAdjustmentBehavior = .never
profileTableView.register(PhotosTableViewCell.self, forCellReuseIdentifier: PhotosTableViewCell.cellID)
profileTableView.register(PostTableViewCell.self, forCellReuseIdentifier: PostTableViewCell.cellID)
profileTableView.delegate = self
profileTableView.dataSource = self
profileTableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(profileTableView)
}
func setupMyCustomHeader() {
profileTableView.register(MyCustomHeader.self, forHeaderFooterViewReuseIdentifier: headerID)
}
private func setupConstraints() {
NSLayoutConstraint.activate([
profileTableView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
profileTableView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
profileTableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
profileTableView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
])
}
...
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemGray6
setupTableView()
setupMyCustomHeader()
setupConstraints()
}
}
extension ProfileViewController: UITableViewDelegate, UITableViewDataSource {
// MARK: - Table view data source
...
// MARK: - Table view delegate
...
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
if #available(iOS 15, *) {
tableView.sectionHeaderTopPadding = 0
}
if section == 0 {
return UITableView.automaticDimension
} else {
return 50
}
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if section == 0 {
let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: headerID) as! MyCustomHeader
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(profileImageViewClicked(_ :)))
tapRecognizer.numberOfTapsRequired = 1
tapRecognizer.numberOfTouchesRequired = 1
tapRecognizer.delegate = self
header.profileHeaderView.profileImageView.isUserInteractionEnabled = true
header.profileHeaderView.profileImageView.addGestureRecognizer(tapRecognizer)
return header
} else {
let header2 = tableView.dequeueReusableHeaderFooterView(withIdentifier: headerID2) as! OneMoreCustomHeader
return header2
}
}
...
}
Probably I should use updateConstraints() function, but can't find the right way.
I added this code to buttonAction, buy it doesn't work
profileStatusLabel.updateConstraintsIfNeeded()
self.setNeedsUpdateConstraints()
self.layoutIfNeeded()
Any time you change the height of a table view element - cell, section header or footer view, etc - you must tell the table view to re-layout its elements.
This is commonly done with a closure.
For example, you would add this property to your custom header view class:
// closure so table layout can be updated
var contentChanged: (() -> ())?
and then set that closure in viewForHeaderInSection:
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if section == 0 {
let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: headerID) as! MyCustomHeader
// set the closure
header.contentChanged = {
// tell the table view to re-layout itself so the header height can be changed
tableView.performBatchUpdates(nil)
}
return header
} else {
let header2 = tableView.dequeueReusableHeaderFooterView(withIdentifier: headerID2) as! OneMoreCustomHeader
return header2
}
}
and when you tap the "Set status" button to update the profileStatusLabel, you would use the closure to "call back" to the controller:
contentChanged?()
With the code you posted, you are embedding ProfileHeaderView in MyCustomHeader, which complicates things a little because you will need a closure in MyCustomHeader that works with another closure in ProfileHeaderView.
There really is no need to do that -- you can put all of your UI elements directly in MyCustomHeader to avoid that issue.
Here is a complete, runnable example. I changed your MyCustomHeader as described... as well as added some other code that you will probably end up needing (see the comments):
class MyCustomHeader: UITableViewHeaderFooterView {
// closure to inform the controller the status text changed
// so we can update the data and
// so the table layout can be updated
var contentChanged: ((String) -> ())?
// presumably, we'll be setting the statusText and the name from a dataSource
public var statusText: String = "" {
didSet {
profileStatusLabel.text = statusText
}
}
public var name: String = "" {
didSet {
profileNameLabel.text = name
}
}
private lazy var profileImageView: UIImageView = {
let v = UIImageView()
if let img = UIImage(systemName: "person.crop.circle") {
v.image = img
}
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
private lazy var profileNameLabel: UILabel = {
let profileStatusLabel = UILabel()
profileStatusLabel.numberOfLines = 0
profileStatusLabel.text = ""
profileStatusLabel.textColor = .black
profileStatusLabel.textAlignment = .left
profileStatusLabel.translatesAutoresizingMaskIntoConstraints = false
return profileStatusLabel
}()
private lazy var profileStatusLabel: UILabel = {
let profileStatusLabel = UILabel()
profileStatusLabel.numberOfLines = 0
profileStatusLabel.text = ""
profileStatusLabel.textColor = .gray
profileStatusLabel.textAlignment = .left
profileStatusLabel.translatesAutoresizingMaskIntoConstraints = false
return profileStatusLabel
}()
private lazy var setStatusButton: UIButton = {
let setStatusButton = UIButton()
setStatusButton.backgroundColor = .systemBlue
setStatusButton.layer.cornerRadius = 4
setStatusButton.layer.shadowOffset = CGSize(width: 4, height: 4)
setStatusButton.layer.shadowOpacity = 0.7
setStatusButton.layer.shadowRadius = 4
setStatusButton.layer.shadowColor = UIColor.black.cgColor
setStatusButton.setTitle("Set status", for: .normal)
setStatusButton.setTitleColor(.white, for: .normal)
setStatusButton.setTitleColor(.lightGray, for: .highlighted)
setStatusButton.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
setStatusButton.translatesAutoresizingMaskIntoConstraints = false
return setStatusButton
}()
private lazy var statusTextField: UITextField = {
let statusTextField = UITextField()
statusTextField.text = ""
statusTextField.borderStyle = .roundedRect
statusTextField.backgroundColor = .white
statusTextField.translatesAutoresizingMaskIntoConstraints = false
return statusTextField
}()
private func setupView() {
contentView.addSubview(profileImageView)
contentView.addSubview(profileNameLabel)
contentView.addSubview(profileStatusLabel)
contentView.addSubview(statusTextField)
contentView.addSubview(setStatusButton)
}
private func setupConstraints() {
NSLayoutConstraint.activate([
profileImageView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10),
profileImageView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20),
profileImageView.widthAnchor.constraint(equalToConstant: 160.0),
profileImageView.heightAnchor.constraint(equalTo: profileImageView.widthAnchor),
profileNameLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 27),
profileNameLabel.leadingAnchor.constraint(equalTo: profileImageView.trailingAnchor, constant: 20),
profileNameLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16),
profileNameLabel.heightAnchor.constraint(equalToConstant: 30),
profileStatusLabel.topAnchor.constraint(equalTo: profileNameLabel.bottomAnchor, constant: 10),
profileStatusLabel.leadingAnchor.constraint(equalTo: profileImageView.trailingAnchor, constant: 20),
profileStatusLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16),
profileStatusLabel.heightAnchor.constraint(greaterThanOrEqualToConstant: 49),
statusTextField.topAnchor.constraint(equalTo: profileStatusLabel.bottomAnchor, constant: 10),
statusTextField.leadingAnchor.constraint(equalTo: profileImageView.trailingAnchor, constant: 20),
statusTextField.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16),
statusTextField.heightAnchor.constraint(equalToConstant: 40),
setStatusButton.topAnchor.constraint(equalTo: statusTextField.bottomAnchor, constant: 16),
setStatusButton.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16),
setStatusButton.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16),
setStatusButton.heightAnchor.constraint(equalToConstant: 50),
contentView.bottomAnchor.constraint(equalTo: setStatusButton.bottomAnchor, constant: 16),
])
}
#objc private func buttonAction() {
guard let stText = statusTextField.text else {
print("Text the status before press the button")
return
}
statusTextField.resignFirstResponder()
// update statusText property
// which will also set the text in the label
statusText = stText
// call the closure, passing back the new text
contentChanged?(stText)
}
override init(reuseIdentifier: String?) {
super.init(reuseIdentifier: reuseIdentifier)
contentView.backgroundColor = .systemGray4
setupView()
setupConstraints()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class ProfileViewController: UIViewController, UIGestureRecognizerDelegate {
// presumably, this will be loaded from saved data, along with the rest of the table data
var dataSourceStatusText: String = "Looking for a big, young, good looking, able to cook female gorilla"
var profileTableView = UITableView()
let headerID = "headerId"
let cellID = "cellId"
func setupTableView() {
profileTableView.contentInsetAdjustmentBehavior = .never
profileTableView.register(UITableViewCell.self, forCellReuseIdentifier: cellID)
profileTableView.delegate = self
profileTableView.dataSource = self
profileTableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(profileTableView)
}
func setupMyCustomHeader() {
profileTableView.register(MyCustomHeader.self, forHeaderFooterViewReuseIdentifier: headerID)
}
private func setupConstraints() {
NSLayoutConstraint.activate([
profileTableView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
profileTableView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
profileTableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
profileTableView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
])
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemGray6
setupTableView()
setupMyCustomHeader()
setupConstraints()
}
}
extension ProfileViewController: UITableViewDelegate, UITableViewDataSource {
// let's use 10 sections each with 5 rows so we can scroll the header out-of-view
func numberOfSections(in tableView: UITableView) -> Int {
return 10
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let c = tableView.dequeueReusableCell(withIdentifier: cellID, for: indexPath)
c.textLabel?.text = "\(indexPath)"
return c
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
if #available(iOS 15, *) {
tableView.sectionHeaderTopPadding = 0
}
if section == 0 {
return UITableView.automaticDimension
} else {
return 50
}
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if section == 0 {
let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: headerID) as! MyCustomHeader
header.name = "#KillaGorilla"
header.statusText = dataSourceStatusText
// set the closure
header.contentChanged = { [weak self] newStatus in
guard let self = self else { return }
// update the status text (probably also saving it somewhere?)
// if we don't do this, and the section header scrolls out of view,
// the *original* status text will be shown
self.dataSourceStatusText = newStatus
// tell the table view to re-layout itself so the header height can be changed
tableView.performBatchUpdates(nil)
}
return header
} else {
// this would be your other section header view
// for now, let's just use a label
let v = UILabel()
v.backgroundColor = .yellow
v.text = "Section Header: \(section)"
return v
}
}
}
Give that a try.

Creating custom table View with Cell properties programmatically

I am new to swift . I am trying to create table view and cell programmatically. I want to display the three label properties one below to another . I added the content view with respective label properties . I have set the row height but when I run the app is overlapping.
Here is the my Table view code with view controller .
class RoomViewController: UIViewController {
var coordinator: RoomBaseCoordinator?
init(coordinator: RoomBaseCoordinator) {
super.init(nibName: nil, bundle: nil)
self.coordinator = coordinator
title = "People"
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private let roomviewModel = RoomViewModel()
private var subscribers = Set<AnyCancellable>()
var activityIndicator = UIActivityIndicatorView(style: .medium)
private lazy var tableView: UITableView = {
let tableview = UITableView()
tableview.translatesAutoresizingMaskIntoConstraints = false
tableview.dataSource = self
tableview.prefetchDataSource = self
tableview.showsVerticalScrollIndicator = false
tableview.register(RoomCellTableViewCell.self, forCellReuseIdentifier: RoomCellTableViewCell.identifier)
return tableview
}()
override func viewDidLoad() {
super.viewDidLoad()
activityIndicator.startAnimating()
setUpUI()
setUpBinding()
self.activityIndicator.stopAnimating()
}
private func setUpUI() {
view.backgroundColor = .white
title = "Room List "
view.addSubview(tableView)
tableView.rowHeight = 100
// create constraints
tableView.topAnchor.constraint(equalTo:view.safeAreaLayoutGuide.topAnchor).isActive = true
tableView.leftAnchor.constraint(equalTo:view.safeAreaLayoutGuide.leftAnchor).isActive = true
tableView.rightAnchor.constraint(equalTo:view.safeAreaLayoutGuide.rightAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo:view.safeAreaLayoutGuide.bottomAnchor).isActive = true
tableView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
// Creating constrain for Indecator
activityIndicator.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(activityIndicator)
activityIndicator.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
activityIndicator.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
}
private func setUpBinding() {
roomviewModel
.$rooms
.receive(on : RunLoop.main)
.sink { [weak self ] _ in
self?.tableView.reloadData()
}
.store(in: &subscribers)
roomviewModel.getRoom()
}
}
extension RoomViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return roomviewModel.rooms.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: RoomCellTableViewCell.identifier, for: indexPath) as? RoomCellTableViewCell
else { return UITableViewCell() }
let row = indexPath.row
let room = roomviewModel.rooms[row]
cell.configureCell(createdAt: room.createdAt, IsOccupied: room.isOccupied, maxOccupancy: String(room.maxOccupancy), id: room.id)
return cell
}
}
extension RoomViewController: UITableViewDataSourcePrefetching {
func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) {
roomviewModel.getRoom()
}
}
Here is the cell .
class RoomCellTableViewCell: UITableViewCell {
static let identifier = "RoomCell"
private lazy var createdAtLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont.boldSystemFont(ofSize: 15)
label.numberOfLines = 0
label.textAlignment = .left
return label
}()
private lazy var IsOccupiedLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont.boldSystemFont(ofSize: 15)
label.numberOfLines = 0
//label.backgroundColor = #colorLiteral(red: 0.1764705926, green: 0.4980392158, blue: 0.7568627596, alpha: 1)
label.textAlignment = .left
return label
}()
private lazy var maxOccupancyLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont.boldSystemFont(ofSize: 15)
label.numberOfLines = 0
label.textAlignment = .left
return label
}()
private lazy var idLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont.boldSystemFont(ofSize: 15)
label.numberOfLines = 0
label.textAlignment = .left
return label
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
// self.contentView.addSubview(containerView)
contentView.addSubview(createdAtLabel)
contentView.addSubview(IsOccupiedLabel)
contentView.addSubview(maxOccupancyLabel)
createdAtLabel.centerYAnchor.constraint(equalTo:self.contentView.centerYAnchor).isActive = true
createdAtLabel.leadingAnchor.constraint(equalTo:self.contentView.leadingAnchor, constant:10).isActive = true
createdAtLabel.widthAnchor.constraint(equalToConstant:50).isActive = true
createdAtLabel.heightAnchor.constraint(equalToConstant:50).isActive = true
contentView.centerYAnchor.constraint(equalTo:self.contentView.centerYAnchor).isActive = true
contentView.leadingAnchor.constraint(equalTo:self.createdAtLabel.trailingAnchor, constant:10).isActive = true
contentView.trailingAnchor.constraint(equalTo:self.contentView.trailingAnchor, constant:-10).isActive = true
contentView.heightAnchor.constraint(equalToConstant:50).isActive = true
IsOccupiedLabel.topAnchor.constraint(equalTo:self.contentView.topAnchor).isActive = true
IsOccupiedLabel.leadingAnchor.constraint(equalTo:self.contentView.leadingAnchor).isActive = true
IsOccupiedLabel.trailingAnchor.constraint(equalTo:self.contentView.trailingAnchor).isActive = true
maxOccupancyLabel.topAnchor.constraint(equalTo:self.IsOccupiedLabel.bottomAnchor).isActive = true
maxOccupancyLabel.leadingAnchor.constraint(equalTo:self.contentView.leadingAnchor).isActive = true
maxOccupancyLabel.topAnchor.constraint(equalTo:self.IsOccupiedLabel.bottomAnchor).isActive = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func configureCell(createdAt: String, IsOccupied: Bool, maxOccupancy: String, id : String ) {
createdAtLabel.text = "CreatedAt :\(createdAt)"
IsOccupiedLabel.text = "IsOccupied : \(IsOccupied)"
maxOccupancyLabel.text = "MaxOccupancy : \(maxOccupancy)"
idLabel.text = "Id : \(id)"
}
}
Here is the result .
In setUpUI() method of your RoomViewController class, set tableView's rowHeight to UITableView.automaticDimension and estimatedRowHeight to 100.
import UIKit
class RoomViewController: UIViewController {
private func setUpUI() {
view.backgroundColor = .white
title = "Room List "
view.addSubview(tableView)
tableView.estimatedRowHeight = 100
tableView.rowHeight = UITableView.automaticDimension
// create constraints
tableView.topAnchor.constraint(equalTo:view.safeAreaLayoutGuide.topAnchor).isActive = true
tableView.leftAnchor.constraint(equalTo:view.safeAreaLayoutGuide.leftAnchor).isActive = true
tableView.rightAnchor.constraint(equalTo:view.safeAreaLayoutGuide.rightAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo:view.safeAreaLayoutGuide.bottomAnchor).isActive = true
tableView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
// Creating constrain for Indecator
activityIndicator.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(activityIndicator)
activityIndicator.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
activityIndicator.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
}
}
And add UIStackView in the RoomCellTableViewCell class as bellow:
import UIKit
class RoomCellTableViewCell: UITableViewCell {
private var stackView: UIStackView = {
let stackView = UIStackView()
stackView.axis = .vertical
stackView.distribution = .fill
stackView.alignment = .fill
stackView.spacing = 8
stackView.translatesAutoresizingMaskIntoConstraints = false
return stackView
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
addSubview(stackView)
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalTo: topAnchor),
stackView.bottomAnchor.constraint(equalTo: bottomAnchor),
stackView.leftAnchor.constraint(equalTo: leftAnchor),
stackView.rightAnchor.constraint(equalTo: rightAnchor)
])
stackView.addArrangedSubview(createdAtLabel)
stackView.addArrangedSubview(isOccupiedLabel)
stackView.addArrangedSubview(maxOccupancyLabel)
// stackView.addArrangedSubview(idLabel)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

Design the custom table view cell programatically

I created table view cell programmatically and set the constrains as well.It is able to display the image , firstname , lastname property into cell but when I added new label with values , it not displaying the values .
Here is the cell code .
import UIKit
class PeopleCell: UITableViewCell {
static let identifier = "PeopleCell"
let containerView:UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.clipsToBounds = true // this will make sure its children do not go out of the boundary
return view
}()
let profileImageView:UIImageView = {
let img = UIImageView()
img.contentMode = .scaleAspectFill // image will never be strecthed vertially or horizontally
img.translatesAutoresizingMaskIntoConstraints = false // enable autolayout
img.layer.cornerRadius = 35
img.clipsToBounds = true
return img
}()
let firstnameTitleLabel:UILabel = {
let label = UILabel()
label.font = UIFont.boldSystemFont(ofSize: 20)
label.textColor = .black
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let lastnameTitleLabel:UILabel = {
let label = UILabel()
label.font = UIFont.boldSystemFont(ofSize: 14)
label.textColor = .white
label.backgroundColor = #colorLiteral(red: 0.1764705926, green: 0.4980392158, blue: 0.7568627596, alpha: 1)
label.layer.cornerRadius = 5
label.clipsToBounds = true
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let jobTitleLabel:UILabel = {
let label = UILabel()
label.font = UIFont.boldSystemFont(ofSize: 20)
label.textColor = .black
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.contentView.addSubview(profileImageView)
containerView.addSubview(firstnameTitleLabel)
containerView.addSubview(lastnameTitleLabel)
containerView.addSubview(jobTitleLabel)
self.contentView.addSubview(containerView)
profileImageView.centerYAnchor.constraint(equalTo:self.contentView.centerYAnchor).isActive = true
profileImageView.leadingAnchor.constraint(equalTo:self.contentView.leadingAnchor, constant:10).isActive = true
profileImageView.widthAnchor.constraint(equalToConstant:70).isActive = true
profileImageView.heightAnchor.constraint(equalToConstant:70).isActive = true
containerView.centerYAnchor.constraint(equalTo:self.contentView.centerYAnchor).isActive = true
containerView.leadingAnchor.constraint(equalTo:self.profileImageView.trailingAnchor, constant:10).isActive = true
containerView.trailingAnchor.constraint(equalTo:self.contentView.trailingAnchor, constant:-10).isActive = true
containerView.heightAnchor.constraint(equalToConstant:40).isActive = true
firstnameTitleLabel.topAnchor.constraint(equalTo:self.containerView.topAnchor).isActive = true
firstnameTitleLabel.leadingAnchor.constraint(equalTo:self.containerView.leadingAnchor).isActive = true
firstnameTitleLabel.trailingAnchor.constraint(equalTo:self.containerView.trailingAnchor).isActive = true
lastnameTitleLabel.topAnchor.constraint(equalTo:self.firstnameTitleLabel.bottomAnchor).isActive = true
lastnameTitleLabel.leadingAnchor.constraint(equalTo:self.containerView.leadingAnchor).isActive = true
lastnameTitleLabel.topAnchor.constraint(equalTo:self.firstnameTitleLabel.bottomAnchor).isActive = true
lastnameTitleLabel.leadingAnchor.constraint(equalTo:self.containerView.leadingAnchor).isActive = true
jobTitleLabel.topAnchor.constraint(equalTo:self.lastnameTitleLabel.bottomAnchor).isActive = true
jobTitleLabel.leadingAnchor.constraint(equalTo:self.containerView.leadingAnchor).isActive = true
jobTitleLabel.topAnchor.constraint(equalTo:self.lastnameTitleLabel.bottomAnchor).isActive = true
jobTitleLabel.leadingAnchor.constraint(equalTo:self.containerView.leadingAnchor).isActive = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func configureCell(firstName: String, lastName: String,jobtitle: String ) {
firstnameTitleLabel.text = "Firstname :\(firstName)"
lastnameTitleLabel.text = "Lastname : \(lastName)"
jobTitleLabel.text = "Occupation : \(jobtitle)"
}
func configureImageCell(row: Int, viewModel: ViewModel) {
profileImageView.image = nil
viewModel
.downloadImage(row: row) { [weak self] data in
let image = UIImage(data: data)
self?.profileImageView.image = image
}
}
}
Here is the view controller code .
import UIKit
import Combine
class PeopleViewController: UIViewController {
var coordinator: PeopleBaseCoordinator?
init(coordinator: PeopleBaseCoordinator) {
super.init(nibName: nil, bundle: nil)
self.coordinator = coordinator
title = "People"
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private let viewModel = ViewModel()
private var subscribers = Set<AnyCancellable>()
private var activityIndicator = UIActivityIndicatorView(style: .medium)
private lazy var tableView: UITableView = {
let tableview = UITableView()
tableview.translatesAutoresizingMaskIntoConstraints = false
tableview.dataSource = self
tableview.prefetchDataSource = self
tableview.showsVerticalScrollIndicator = false
tableview.register(PeopleCell.self, forCellReuseIdentifier: PeopleCell.identifier)
return tableview
}()
override func viewDidLoad() {
super.viewDidLoad()
activityIndicator.startAnimating()
setUpUI()
setUpBinding()
self.activityIndicator.stopAnimating()
// Do any additional setup after loading the view.
}
private func setUpUI() {
view.backgroundColor = .white
title = "People List "
view.addSubview(activityIndicator)
view.addSubview(tableView)
// self.tableView.rowHeight = 100.00
tableView.rowHeight = UITableView.automaticDimension
tableView.rowHeight = 100
tableView.topAnchor.constraint(equalTo:view.safeAreaLayoutGuide.topAnchor).isActive = true
tableView.leftAnchor.constraint(equalTo:view.safeAreaLayoutGuide.leftAnchor).isActive = true
tableView.rightAnchor.constraint(equalTo:view.safeAreaLayoutGuide.rightAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo:view.safeAreaLayoutGuide.bottomAnchor).isActive = true
// Creating constrain for Indecator
activityIndicator.translatesAutoresizingMaskIntoConstraints = false
activityIndicator.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
activityIndicator.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
}
private func setUpBinding() {
viewModel
.$peoples
.receive(on : RunLoop.main)
.sink { [weak self ] _ in
self?.tableView.reloadData()
}
.store(in: &subscribers)
viewModel.getPeople()
}
}
extension PeopleViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewModel.peoples.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: PeopleCell.identifier, for: indexPath) as? PeopleCell
else { return UITableViewCell() }
let row = indexPath.row
let people = viewModel.peoples[row]
cell.configureCell(firstName: people.firstName, lastName: people.lastName,jobtitle: people.jobtitle)
cell.configureImageCell(row: row, viewModel: viewModel)
return cell
}
}
extension PeopleViewController: UITableViewDataSourcePrefetching {
func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) {
viewModel.getPeople()
}
}
Here is the screenshot . As it not showing the job title property into cell .
I think your problem is the height of your containerView
containerView.heightAnchor.constraint(equalToConstant:40).isActive = true
I think 40 is to low to show the jobTitleLabel

UITableViewCell subclass displaying itself twice on top of itself

Excuse the terrible title. The best way to explain this is to show it visually.
So I have a custom UITableViewCell, and when the view controller (with the table view) is loaded, the cell ends up looking like this:
and I have no idea why. It DOES fix itself if I tap on it, as shown here:
I’ve also noticed that this only happens when the cell is not immediately present on screen when the view controller loads (aka, you have to scroll down to it). If it was the first cell in the table view, it appears correctly.
code:
class CustomTableViewCell: UITableViewCell {
let label1 = UILabel()
let label2 = UILabel()
let label3 = UILabel()
let label4 = UILabel()
let label5 = UILabel()
let label6 = UILabel()
let label7 = UILabel()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
label1.translatesAutoresizingMaskIntoConstraints = false
label1.text = "Test"
label1.font = UIFont.systemFont(ofSize: 20, weight: .bold)
addSubview(label1)
label2.translatesAutoresizingMaskIntoConstraints = false
label2.text = "Test"
label2.textColor = .secondaryLabel
label2.font = UIFont.systemFont(ofSize: 13)
addSubview(label2)
label3.translatesAutoresizingMaskIntoConstraints = false
label3.text = "Test"
label3.font = UIFont.systemFont(ofSize: 17)
addSubview(label3)
label4.translatesAutoresizingMaskIntoConstraints = false
label4.text = "Test"
label4.textColor = .secondaryLabel
label4.font = UIFont.systemFont(ofSize: 13)
addSubview(label4)
label5.translatesAutoresizingMaskIntoConstraints = false
label5.text = "Test"
label5.font = UIFont.systemFont(ofSize: 17)
addSubview(label5)
label6.translatesAutoresizingMaskIntoConstraints = false
label6.text = "Test"
label6.textColor = .secondaryLabel
label6.font = UIFont.systemFont(ofSize: 13)
addSubview(label6)
label7.translatesAutoresizingMaskIntoConstraints = false
label7.text = "Test"
label7.font = UIFont.systemFont(ofSize: 17)
addSubview(label7)
NSLayoutConstraint.activate([
label1.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor, constant: 20),
label1.leadingAnchor.constraint(equalTo: safeAreaLayoutGuide.leadingAnchor, constant: 16),
label1.trailingAnchor.constraint(equalTo: safeAreaLayoutGuide.trailingAnchor, constant: -16),
label2.topAnchor.constraint(equalTo: label1.bottomAnchor, constant: 20),
label2.leadingAnchor.constraint(equalTo: label1.leadingAnchor),
label2.trailingAnchor.constraint(equalTo: label1.trailingAnchor),
label3.topAnchor.constraint(equalTo: label2.bottomAnchor, constant: 3),
label3.leadingAnchor.constraint(equalTo: label2.leadingAnchor),
label3.trailingAnchor.constraint(equalTo: label2.trailingAnchor),
label4.topAnchor.constraint(equalTo: label3.bottomAnchor, constant: 20),
label4.leadingAnchor.constraint(equalTo: label3.leadingAnchor),
label4.trailingAnchor.constraint(equalTo: label3.trailingAnchor),
label5.topAnchor.constraint(equalTo: label4.bottomAnchor, constant: 3),
label5.leadingAnchor.constraint(equalTo: label4.leadingAnchor),
label5.trailingAnchor.constraint(equalTo: label4.trailingAnchor),
label6.topAnchor.constraint(equalTo: label5.bottomAnchor, constant: 20),
label6.leadingAnchor.constraint(equalTo: label5.leadingAnchor),
label6.trailingAnchor.constraint(equalTo: label5.trailingAnchor),
label7.topAnchor.constraint(equalTo: label6.bottomAnchor, constant: 3),
label7.leadingAnchor.constraint(equalTo: label6.leadingAnchor),
label7.trailingAnchor.constraint(equalTo: label6.trailingAnchor),
])
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
--
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomTableViewCell
return cell
}
My dear friend, I can not see any bottomAnchor constraints :). Why don't you check this out. Maybe it helps you to understand how autolayout works in programmatically. If you have any question about it, please reach out. Have fun :)
PS: You should addsubview into contentView. Do not add any view directly to cell superview. :)
class TestTableViewCell: UITableViewCell {
private lazy var labelFirst: UILabel = {
let temp = UILabel()
temp.translatesAutoresizingMaskIntoConstraints = false
temp.font = UIFont(name: "System", size: 12)
temp.text = "Test"
return temp
}()
private lazy var labelSecond: UILabel = {
let temp = UILabel()
temp.translatesAutoresizingMaskIntoConstraints = false
temp.font = UIFont(name: "System", size: 15)
temp.text = "Test"
return temp
}()
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
addMajorViews()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func addMajorViews() {
contentView.addSubview(labelFirst)
contentView.addSubview(labelSecond)
NSLayoutConstraint.activate([
labelFirst.topAnchor.constraint(equalTo: contentView.topAnchor),
labelFirst.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
labelFirst.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
labelSecond.topAnchor.constraint(equalTo: labelFirst.bottomAnchor),
labelSecond.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
labelSecond.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
labelSecond.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
])
}
}

how to use ViewWithTag in Swift?

I'm new to Swift, however I work in Objective-C before. I'm having issue in checkin if the cell is being reused in UITableView or not.
let cell = tableView.dequeueReusableCellWithIdentifier(strCellId, forIndexPath:indexPath) as! MGSwipeTableCell
cell.backgroundColor = UIColor.clearColor()
let SMSObj = self.arraySMSContent[indexPath.row] as! SMSModel
let lblMessage = UILabel(frame: CGRectMake(15, 10, Constants.SCREEN_WIDTH/1.4, Constants.SCREEN_HEIGHT/11))
lblMessage.text = SMSObj.strSMSContent
lblMessage.textAlignment = NSTextAlignment.Left
lblMessage.numberOfLines = 2
lblMessage.textColor = UIColor.whiteColor()
cell.contentView.addSubview(lblMessage)
I have used MGSwipebleCell. While scrolling lblMessage overlaps. Even we can not check if cell is nil or not. So how to use viewWithTag in this situation? Thnaks
Rather than using viewWithTag, you can register a custom class with the cell reuse identifier. Then you can access the label using a property of that subclass:
override func viewDidLoad() {
super.viewDidLoad()
tableView.registerClass(CustomCell.self, forCellReuseIdentifier: "CustomCell")
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("CustomCell", forIndexPath: indexPath) as! CustomCell
cell.smsLabel.text = ...
return cell
}
Where:
class CustomCell: MGSwipeTableCell {
var smsLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.textAlignment = .Left
label.numberOfLines = 2
label.textColor = .whiteColor()
return label
}()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
backgroundColor = .blueColor()
contentView.addSubview(smsLabel)
NSLayoutConstraint.activateConstraints([
smsLabel.topAnchor.constraintEqualToAnchor(contentView.topAnchor, constant: 5),
smsLabel.bottomAnchor.constraintEqualToAnchor(contentView.bottomAnchor, constant: -5),
smsLabel.leadingAnchor.constraintEqualToAnchor(contentView.leadingAnchor, constant: 5),
smsLabel.trailingAnchor.constraintEqualToAnchor(contentView.trailingAnchor, constant: -5)
])
leftButtons = [MGSwipeButton(title: "Red", backgroundColor: .redColor())]
leftSwipeSettings.transition = .Rotate3D;
rightButtons = [MGSwipeButton(title: "Green", backgroundColor: .greenColor())]
rightSwipeSettings.transition = .Rotate3D;
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
fatalError("not needed")
}
}
There're many ways to solve your problem. Please try:
if let lblMessage = cell.contentView.viewWithTag(9999) as? UILabel { //Tag
lblMessage.text = SMSObj.strSMSContent
}else{
let lblMessage = UILabel(frame: CGRectMake(15, 10, Constants.SCREEN_WIDTH/1.4, Constants.SCREEN_HEIGHT/11))
lblMessage.text = SMSObj.strSMSContent
lblMessage.textAlignment = NSTextAlignment.Left
lblMessage.numberOfLines = 2
lblMessage.textColor = UIColor.whiteColor()
lblMessage.tag = 9999 //Tag
cell.contentView.addSubview(lblMessage)
}