I am creating a UITableView using code, I am not using any storyboard or IB.
Following is my code:
class UserListController: UIViewController , UITableViewDelegate, UITableViewDataSource {
var chatTableView: UITableView = {
let table = UITableView()
table.translatesAutoresizingMaskIntoConstraints = false
return table
}()
func setChatTableView(){
chatTableView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
chatTableView.topAnchor.constraint(equalTo: chatSegmentControl.bottomAnchor).isActive = true
chatTableView.widthAnchor.constraint(equalTo:view.widthAnchor).isActive = true
chatTableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
}
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(chatTableView)
setChatTableView()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
let cellIdentifier = "cellId"
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath
// ) as UITableViewCell
let cell = UITableViewCell(style: .subtitle, reuseIdentifier: cellIdentifier)
cell.textLabel?.text = "LaLaLa"
return cell
}
I have created chatTableView which is my TableView and have add this on the main view i am not using UITableViewController.
I can see the table view on screen but there is no message in rows so what I should do to populate table view please help.
I am new to the ios and using a swift 4.
Thank you in advance.
Please provide UITableViewDataSource and UITableViewDelegate
var chatTableView: UITableView = {
let table = UITableView()
table.dataSource = self
table.delegate = self
table.translatesAutoresizingMaskIntoConstraints = false
return table
}()
You can also get full tutorial over Here.
Related
I am relatively new to UIKit. Currently, I am trying to create a UISwitch that will show up on a specific UITableView cell. However, I can't seem to figure out how to do this. Instead, I am getting a UISwitch on every single cell in the UITableView.
My code is below:
import UIKit
class SettingsVC: UIViewController {
var tableView = UITableView(frame: .zero, style: .insetGrouped)
let cells = ["Change Accent Color", "Change Currency Symbol", "Vibrations"]
let cellReuseIdentifier = "cell"
override func viewDidLoad() {
super.viewDidLoad()
createTableView()
setTableViewDelegates()
}
func createTableView() {
view.addSubview(tableView)
tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellReuseIdentifier)
tableView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
tableView.topAnchor.constraint(equalTo: view.topAnchor),
tableView.leftAnchor.constraint(equalTo: view.leftAnchor),
tableView.rightAnchor.constraint(equalTo: view.rightAnchor),
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
])
}
func setTableViewDelegates() {
tableView.delegate = self
tableView.dataSource = self
}
}
extension SettingsVC: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cells.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell") else {
return UITableViewCell()
}
cell.textLabel?.text = cells[indexPath.row]
let switchView = UISwitch(frame: .zero)
switchView.setOn(false, animated: true)
cell.accessoryView = switchView
return cell
}
}
This is how my UITableView looks currently in the simulator.
This is how I would like the UITableView to look.
How would I be able to achieve the look I'm going for? Any help would be greatly appreciated.
The method tableView(_:cellForRowAt:) is used to create all cells for a table, so the code inside this method is called for each cell. You need to figure out a condition that distinguishes the cell with a UISwitch and run the corresponding piece conditionally. Conceptually, something like this:
func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell") else {
return UITableViewCell()
}
cell.textLabel?.text = cells[indexPath.row]
if isSwitchNeeded { // Here.
let switchView = UISwitch(frame: .zero)
switchView.setOn(false, animated: true)
cell.accessoryView = switchView
}
return cell
}
There are some architectural options that might allow you do that. One of them is to rely on the index path. For instance, this should work in your raw example:
func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell") else {
return UITableViewCell()
}
cell.textLabel?.text = cells[indexPath.row]
if indexPath.row == 2 {
let switchView = UISwitch(frame: .zero)
switchView.setOn(false, animated: true)
cell.accessoryView = switchView
}
return cell
}
And a million other ways.
First of all most likely you want to save the value of the switch, so create a property on the top level of the view controller
var enableVibrations = false
Second of all cells are reused. Even if there are only three cells it's good practice to set all UI elements to a defined state, that means to set the accessory view to nil if there is no switch.
And there is a dequeueReusableCell API which returns a non-optional cell.
func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let title = cells[indexPath.row]
cell.textLabel?.text = title
if title == "Vibrations" {
let switchView = UISwitch(frame: .zero)
switchView.setOn(enableVibrations, animated: true)
switchView.addTarget(self, action: #selector(toggleVibrations), for: .valueChanged)
cell.accessoryView = switchView
} else {
cell.accessoryView = nil
}
return cell
}
And add the action method
#objc func toggleVibrations(_ sender : UISwitch) {
self.enableVibrations = sender.isOn
}
I want to learn Combine framework for Swift and I have found a tutorial video:
https://www.youtube.com/watch?v=hbY1KTI0g70
Unfortunately, I get:
No exact matches in call to initializer
error on the line which defines tableView and some other errors when I try to call the tableView, but I hope they will resolve after I fix the issue with initialising this element.
The code:
import UIKit
import Combine
class MyCustomTableCell: UITableViewCell{ }
class ViewController: UIViewController, UITableViewDataSource {
private let tableView = UITableView {
let table = UITableView()
table.register(MyCustomTableCell.self,
forceCellReuseIdentifier: "cell")
return table
}()
(...)
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(tableView)
tableView.dataSource = self
tableView.frame = view.bounds
(...)
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return models.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? MyCustomTableCell else {
fatalError()
}
cellTextLabel?.text = models(indexPath.row)
return cell
}
The whole code is long as hell. That is why I copied only the crucial parts of it (where the tableView occurs).
You can see the full code in the video:
https://www.youtube.com/watch?v=hbY1KTI0g70
It's either
private let tableView = UITableView( ... )
or
private let tableView : UITableView = { ... }()
The UITableView accessory view is not being displayed in a table view that is set to another view's input view and presented as such when that view becomes first responder.
For example, this code displays a table view controller with a single table view cell that has a checkmark for its accessory.
import PlaygroundSupport
import UIKit
class TableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
1
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = "Hello world"
cell.accessoryType = .checkmark
return cell
}
}
let tableViewController = TableViewController()
PlaygroundPage.current.liveView = tableViewController
When I set this same table view controller as the input view to a text field, it comes up when the user taps on the text field in gray.
import PlaygroundSupport
import UIKit
class TableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
1
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = "Hello world"
cell.accessoryType = .checkmark
return cell
}
}
let tableViewController = TableViewController()
let textField = UITextField()
textField.backgroundColor = .gray
textField.frame = CGRect(origin: .zero, size: CGSize(width: 100, height: 20))
let frame = CGRect(origin: .zero, size: CGSize(width: 360, height: 780))
let view = UIView(frame: frame)
view.addSubview(textField)
textField.inputView = tableViewController.view
PlaygroundPage.current.liveView = view
However, it is missing the checkmark accessory now.
How can you show the accessory view on the UITableViewCell when the UITableView is used as an input view?
Tried as Xcode project (works well as expected), and hold a reference to the table view controller, otherwise, it goes out of scope and deallocated (Not sure this is the root cause of the issue here).
Source code, your table view controller and adding text field in storyboard and having a reference of table view controller in view controller.
class TableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
1
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = "Hello world"
cell.accessoryType = .checkmark
return cell
}
}
class ViewController: UIViewController {
#IBOutlet weak var tx: UITextField!
var tableViewController : TableViewController!
override func viewDidLoad() {
super.viewDidLoad()
self.tableViewController = TableViewController()
self.tx.inputView = self.tableViewController.view
}
}
I've created a UITableView inside my ViewController. Here's the code I've added to fill the TableView with content. However, no content is showing up. I've created a customized tableView Cell which I am calling in the cellNib as PostTableViewCell. When the program is running, it shows the prototype cells with the divider lines, but none of the custom content.
import Foundation
import UIKit
import Firebase
class HomeViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var tableView:UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView = UITableView(frame: view.bounds, style: .plain)
//tableView.backgroundColor = UIColor.blue
let cellNib = UINib(nibName: "PostTableViewCell", bundle: nil)
tableView.register(cellNib, forCellReuseIdentifier: "postCell")
view.addSubview(tableView)
var layoutGuide:UILayoutGuide!
if #available(iOS 11.0, *) {
layoutGuide = view.safeAreaLayoutGuide
} else {
layoutGuide = view.layoutMarginsGuide
}
tableView.leadingAnchor.constraint(equalTo: layoutGuide.leadingAnchor).isActive = true
tableView.topAnchor.constraint(equalTo: layoutGuide.topAnchor).isActive = true
tableView.trailingAnchor.constraint(equalTo: layoutGuide.trailingAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: layoutGuide.bottomAnchor).isActive = true
tableView.delegate = self
tableView.dataSource = self
tableView.reloadData()
// Do any additional setup after loading the view.
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 12
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "postCell", for: indexPath) as! PostTableViewCell
return cell
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
You're not actually configuring the cell in your tableView:cellForRowAt: method:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "postCell", for: indexPath) as! PostTableViewCell
return cell
}
Typically you need to insert values into the elements of your custom cell. The "content" of your cell label text, images etc is usually inserted into the cells elements in this method. If you look at the code in a new Xcode project you will see:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let object = objects[indexPath.row] as! NSDate
cell.textLabel!.text = object.description
return cell
}
Note the line retrieving the data: let object = objects[indexPath.row] as! NSDate
Followed by the line in setting the text value of the textLabel:
cell.textLabel!.text = object.description
Code looks right..
Make sure you have assign content to table cell in cellForRowAt datasource methods.
class TableController: UIViewController {
#IBOutlet var ListTable: UITableView!
var list: [Dictionary<String, String>] = []
override func viewDidLoad() {
super.viewDidLoad()
let ListTable = UITableView(frame: view.bounds)
self.ListTable = ListTable
ListTable.dataSource = self
ListTable.delegate = self
initList()
}
func initList() {
// get list from firebase
self.ListTable.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return list.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let item = self.list[indexPath.row]
let cellIdentifier = "ListCell"
let cell = CustomCell(style: .default, reuseIdentifier: cellIdentifier)
cell.foodLabel?.text = item["Banana"]
return cell
}
}
extension QueueController: UITableViewDataSource, UITableViewDelegate {
}
CustomCell class:
import UIKit
class CustomCell: UITableViewCell
{
#IBOutlet weak var foodLabel: UILabel!
override func awakeFromNib()
{
super.awakeFromNib()
}
}
My data from firebase loads properly. On storyboard I have a normal view controller with a UITableView embedded inside of it. That table view is liked to my IBOutlet for my ListTable. In the table there is a cell with 3 labels. That cell has the identifier ListCell and it's class is CustomCell.
Edit: There is no error but my data isn't showing up.
This is because your Custom Cell does not dequeue properly. Try this one
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "ListCell"
var cell : ListCell? = tableView.dequeueReusableCell(withIdentifier: cellIdentifier) as! ListCell?
if (cell == nil) {
cell = Bundle.main.loadNibNamed("ListCell", owner: nil, options: nil)?[0] as? ListCell
}
cell?.backgroundColor = UIColor.clear
cell?.contentView.backgroundColor = UIColor.clear
return cell!
}
Perhaps try registering your cell in viewDidLoad
ListTable.register(UINib(nibName: "CustomCell", bundle: Bundle.main), forCellReuseIdentifier: "ListCell") //this is assuming that your nib is named "CustomCell"
Also, for the record, you should follow camel-case conventions and name your UITableView listTable
You did never add the TableView to your view... (or part go the code is missing )