I’ve implemented a custom cell for a UITableView, but when I run the Playground it’s just a standard table. It’s probably something stupid simple, but I’m very new to UIKit and somewhat new to Swift.
Also, I’ve tried to implement a “sticky header”, but no matter what I try the header scrolls with the rest of the table.
import UIKit
import PlaygroundSupport
class ViewController : UIViewController, UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 19
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: CardCell = tableView.dequeueReusableCell(withIdentifier: "CardCell", for: indexPath) as! CardCell
cell.messageLabel.text = "yo"
return cell
}
var convoTableView = UITableView()
override func viewDidLoad(){
super.viewDidLoad()
convoTableView = UITableView(frame: self.view.bounds, style:
UITableView.Style.plain)
convoTableView.backgroundColor = UIColor.white
convoTableView.register(CardCell.self, forCellReuseIdentifier: "CardCell")
let header = UIView(frame: CGRect(x: 0, y: 0, width: convoTableView.frame.width, height: 100))
header.backgroundColor = .red
self.convoTableView.delegate = self
self.convoTableView.dataSource = self
let yourLabel = UILabel(frame: CGRect(x: 10, y: 0, width: 100, height: 100))
yourLabel.textColor = UIColor.black
yourLabel.backgroundColor = UIColor.white
yourLabel.text = "mylabel text"
header.addSubview(yourLabel)
convoTableView.tableHeaderView = header
convoTableView.estimatedSectionHeaderHeight = 40.0
self.view.addSubview(convoTableView)
}
}
class CardCell: UITableViewCell {
let messageLabel:UILabel = {
let label = UILabel()
label.font = UIFont.boldSystemFont(ofSize: 14)
label.clipsToBounds = true
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let dateLabel:UILabel = {
let label = UILabel()
label.font = UIFont.boldSystemFont(ofSize: 8)
label.clipsToBounds = true
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let containerView:UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.clipsToBounds = true
return view
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
containerView.addSubview(messageLabel)
containerView.addSubview(dateLabel)
self.contentView.addSubview(containerView)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
PlaygroundPage.current.liveView = ViewController()
Here's all the code you need here to make a custom cell and sticky header:
import UIKit
import PlaygroundSupport
class ViewController: UITableViewController {
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = UIView()
view.backgroundColor = .purple
return view
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
50
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
19
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CardCell", for: indexPath) as! CardCell
cell.textLabel?.text = "\(indexPath.row)"
return cell
}
override func viewDidLoad(){
super.viewDidLoad()
tableView.register(CardCell.self, forCellReuseIdentifier: "CardCell")
}
}
class CardCell: UITableViewCell { }
PlaygroundPage.current.liveView = ViewController()
To make the header sticky and non-scrollable with the table view you need to take a different UIView above the table view and give the frames of the table just below the UiView.
customView = MyCustomView(frame: CGRect(x: 0, y: 0, width: 200, height: 50))
self.view.addSubview(customView
Related
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.
I want to add or delete some view in a TableViewCell dynamically
And I want the cell Height could be adjusted to the cell content height when I delete the UIView in cell.
below is my demo, I use the
self.frame.size.height -= 100
to adjust cell height, but the result is not so good.
import UIKit
import SnapKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let table = UITableView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 1200))
table.dataSource = self
table.delegate = self
table.estimatedRowHeight = 1
table.rowHeight = UITableView.automaticDimension
table.separatorColor = UIColor.blue
table.register(CustomCell.self, forCellReuseIdentifier: "identifierid")
view.addSubview(table)
}
}
class CustomCell:UITableViewCell {
let btn:UIButton = {
let btn = UIButton()
btn.layer.borderColor = UIColor.black.cgColor
btn.layer.borderWidth = 1
btn.setTitle("delete red view", for: .normal)
btn.setTitleColor(UIColor.black, for: .normal)
return btn
}()
let v:UIView = {
let v = UIView()
v.backgroundColor = UIColor.red
return v
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.contentView.addSubview(btn)
btn.snp.makeConstraints { (make) in
make.top.equalToSuperview().offset(10)
make.size.equalTo(CGSize(width: 150,height: 50))
}
btn.addTarget(self, action: #selector(deleteCellImg), for: .touchUpInside)
self.contentView.addSubview(v)
v.snp.makeConstraints { (make) in
make.top.equalTo(btn.snp.bottom)
make.left.equalTo(btn)
make.size.equalTo(CGSize(width: 100, height: 100))
make.bottom.equalToSuperview().offset(-10)
}
}
#objc func deleteCellImg() {
v.removeFromSuperview()
self.frame.size.height -= 100 //100 is the red view height
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension ViewController:UITableViewDelegate,UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 6
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "identifierid", for: indexPath) as! CustomCell
return cell
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
}
The result is showed below
When I delete a view in a cell,I don't want the other cell height would be influenced.So is there some detail I ignore?
call removeFromSuperview() while removing the view. This will be done in your Custom Cell class.
Then reload table view through table.reloadData().
If the row height is still misleading use constraints or height for row.
I am trying to make this, as in the first picture:
Image 1
Image 2
But the view somehow does not show up like I want it to. Here you can see my full project code:
import UIKit
import RealmSwift
import CVCalendar
class Test: UIViewController, UITableViewDelegate, UITableViewDataSource {
var myTableView: UITableView = UITableView()
var itemsToLoad: [String] = ["One", "Two", "Three"]
var myView = UIView()
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor(red: 4/255, green: 4/255, blue: 4/255, alpha: 1.0)
self.navigationController?.navigationBar.barStyle = .black
self.navigationController?.navigationBar.tintColor = UIColor.white
self.navigationItem.title = "Test"
self.navigationController?.navigationBar.prefersLargeTitles = true
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Get main screen bounds
let screenSize: CGRect = UIScreen.main.bounds
let screenWidth = screenSize.width
let screenHeight = screenSize.height
myView.frame = CGRect(x: 0, y: 0, width: screenWidth, height: 150)
myView.backgroundColor = .black
self.view.addSubview(myView)
myTableView.frame = CGRect(x: 0, y: 50, width: screenWidth, height: screenHeight-50);
myTableView.dataSource = self
myTableView.delegate = self
myTableView.backgroundColor = .blue
myTableView.layer.borderWidth = 3
myTableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
self.view.addSubview(myTableView)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return itemsToLoad.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = self.itemsToLoad[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("User selected table row \(indexPath.row) and item \(itemsToLoad[indexPath.row])")
}
}
Why won't it show up? The first picture is how I want it, then second picture is how it looks now.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
if self.itemsToLoad[indexPath.row] != nil {
cell.textLabel?.text = self.itemsToLoad[indexPath.row]
cell.backgroundColor = .white
}else {
cell.backgroundColor = .blue
}
return cell
}
I have a TableViewController class :-
class SideMenuViewController: UITableViewController {
let tableViewFooter = UIView(frame: CGRect(x: 0, y: self.view.bounds.size.height + 80, width: self.view.bounds.width, height: 80))
tableViewFooter.backgroundColor = UIColor(patternImage: UIImage(named: "nav_drawer_footer.jpg")!)
tableView.tableFooterView = tableViewFooter
}
But using this code ..the view is under the last cell of tableView....i don't want this.
What I need is an ImageView / UIView at the Bottom of the table view Controller
let theHeight = view.frame.size.height //grabs the height of your view
let footer = UIView()
footer.backgroundColor = UIColor(patternImage: UIImage(named: "nav_drawer_footer.jpg")!)
footer.frame = CGRect(x: 0, y: theHeight - 150 , width: self.view.frame.width, height: 80)
self.view.addSubview(footer)
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footerView = UIView()
let imgView = UIImageView()
//Write UIImageView required code
footer.addSubView(imgView)
return footerView
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return HEIGHT_YOU_WANT
}
I would do this with UIViewController with separate UITableView and UIImageView instead of using UITableViewController.When using UITableViewController self.view is actually self.tableView, i.e. your image will be a subview of the UITableView and it will overlap the bottom rows. It is also better to use layout constraints than frame rects. As constraints code is somewhat a pain to write you can use SnapKit as I did here:
import SnapKit
class SideMenuViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
let tableView = UITableView()
let tableViewFooter = UIView()
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
tableView.delegate = self
tableView.dataSource = self
tableViewFooter.backgroundColor = UIColor(patternImage: UIImage(named: "nav_drawer_footer.jpg")!)
view.addSubview(tableView)
view.addSubview(tableViewFooter)
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
tableViewFooter.snp.makeConstraints { (make) -> Void in
make.width.equalTo(view.snp.width)
make.left.equalTo(view.snp.left)
make.bottom.equalTo(view.snp.bottom)
make.height.equalTo(80)
}
tableView.snp.makeConstraints { (make) in
make.top.equalTo(view.snp.top)
make.bottom.equalTo(tableViewFooter.snp.top)
make.width.equalTo(view.snp.width)
make.centerX.equalTo(view.snp.centerX)
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.backgroundColor = UIColor.blue
return cell
}
}
Edit: I am using SnapKit just so I don't write all this constraints code.The point is in the logic.
I'm having a problem with my parallax effect. I'm having a tableView and a ImageView above the tableView. Now when the user scrolls from the top I want to stretch the image a bit. But the problem is that my tableView keeps having a white background like you can see on the screenshot. So the image isn't visible. The screenshot is taken when the viewcontroller loads and then I just pull down as far as I can go. The tableView has backgroundColor .clear so I don't why it isn't working.
My code:
import UIKit
import PureLayout
class ViewController: UIViewController {
lazy var headerImageView: UIImageView = {
let imageView = UIImageView(forAutoLayout: ())
imageView.image = UIImage(named: "test")
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
return imageView
}()
lazy var tableView: UITableView = {
let tableView = UITableView(forAutoLayout: ())
tableView.delegate = self
tableView.dataSource = self
tableView.separatorStyle = .none
tableView.isOpaque = false
tableView.backgroundColor = .clear
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "default")
tableView.tableFooterView = UIView()
tableView.showsVerticalScrollIndicator = false
return tableView
}()
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(self.headerImageView)
self.headerImageView.autoPinEdge(toSuperviewEdge: .left)
self.headerImageView.autoPinEdge(toSuperviewEdge: .right)
self.headerImageView.autoPin(toTopLayoutGuideOf: self, withInset: 0)
self.headerImageView.autoSetDimension(.height, toSize: 100)
self.view.addSubview(self.tableView)
self.tableView.autoPinEdge(toSuperviewEdge: .left)
self.tableView.autoPinEdge(toSuperviewEdge: .right)
self.tableView.autoPinEdge(toSuperviewEdge: .bottom)
self.tableView.autoPinEdge(.top, to: .bottom, of: self.headerImageView)
}
}
extension ViewController: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 20
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "default", for: indexPath)
cell.textLabel?.text = "test"
cell.backgroundColor = .red
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 50
}
}
extension ViewController: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
// Parallax functionality
let yOffset = scrollView.contentOffset.y * 0.2
let availableOffset = min(yOffset, 60)
let contentRectYOffset = availableOffset / self.headerImageView.frame.size.height
self.headerImageView.layer.contentsRect = CGRect(x: 0.0, y: contentRectYOffset, width: 1, height: 1)
}
}