I made a simple app for practicing tableView and Singletons. I am new to swift so I would appreciate some quick help on this one. The thing I want to do is simple but I can't think of anything at the moment.
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource{
var tableView = UITableView()
let names = Singleton.shared.nameArray
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(tableView)
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
tableView.delegate = self
tableView.dataSource = self
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
tableView.frame = .init(x: 0, y: 0, width: 414, height: 260)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return names.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let name = names[indexPath.row]
cell.textLabel?.text = "cell \(indexPath.row + 1)"
return cell
}
#IBAction func didPressButton(_ sender: Any) {
}
}
basically I want the tableView label to change to this name constant i made after the button is clicked.
Sorry if I didn't make everything clear in the question and I hope that you will understand and be able to help me. It's kinda hard to explain the code because I'm new to swift and English isn't my native language.
Edited to clear things up a little bit.
Add to the ViewController:
private var areNamesVisible = false
#IBAction func didPressButton(_ sender: Any) {
areNamesVisible.toggle()
tableView.reloadData()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let name = names[indexPath.row]
cell.textLabel?.text = areNamesVisible ? name : "cell \(indexPath.row + 1)"
return cell
}
Related
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 have a collection of items I'm putting into a menu for the time being while I work out my layout planning but I am having trouble with figuring out how to work the DidSelectRow with the indexPath.row -
I have the following code:
import UIKit
class DispatchViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
var videos: [DispatchMenuItem] = []
override func viewDidLoad() {
super.viewDidLoad()
videos = createArray()
self.tableView.rowHeight = 65.0
tableView.dataSource = self
}
func createArray() -> [DispatchMenuItem] {
let video1 = DispatchMenuItem(image: #imageLiteral(resourceName: "truckUnloadIcon"), title: "Open Manifests")
let video2 = DispatchMenuItem(image: #imageLiteral(resourceName: "podIcon"), title: "Customer Pickup")
return [video1, video2]
}
}
extension DispatchViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return videos.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let video = videos[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "DispatchMenuItemCell") as! DispatchMenuItemCell
cell.setVideo(video: video)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print(indexPath.row)
print(indexPath)
if indexPath.row == 1{
self.performSegue(withIdentifier: "goToOpenManifests", sender: nil)
}else if indexPath.row == 2{
self.performSegue(withIdentifier: "goToCustomerPickupForm", sender: nil)
}
}
}
You can see near the bottom my DidSelectRow, but it doesn't want to print out the indexPath.row so I am assuming that the row being selected is somehow now being passed along through the extension.
Are there any suggestions? I've usually done this through just a UITableViewController and have never had this issue, but somewhere here I seem to be getting stuck.
It will not print out the indexPath as you have not set the delegate. Implementing just the method is not sufficient, tableView needs to know who is going to implement the delegate methods.
There is a difference between delegate and datasource.
tableView.dataSource will help you to fetch numberofSections, numberofRowsInASection, TableCell Object
tableView.delegate will help you to manage the selection and deselection.
override func viewDidLoad() {
super.viewDidLoad()
videos = createArray()
self.tableView.rowHeight = 65.0
tableView.dataSource = self
//Add this
tableView.delegate = self
}
You just need to add below the first line of code in viewDid load method and improve your code like below.
tableView.delegate = self
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print(indexPath.row)
print(indexPath)
if indexPath.row == 0 {
self.performSegue(withIdentifier: "goToOpenManifests", sender: nil)
}else if indexPath.row == 1 {
self.performSegue(withIdentifier: "goToCustomerPickupForm", sender: nil)
}
}
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.
So I'm having this issue that when reloadData() is called after the initial API call, it calls willDisplayCell method which when the last cell is displayed will load more data (API returns 10 data at a time).
However in the view it can show only 4 - 5 cells as I set the row height to 175 points manually. Does anyone know why is this happening?
If this is how the tableView works what can I do to make my tableView to load only 10 initially?
Following is my code.
class MainViewController: UIViewController {
var tableView: UITableView!
var photoViewmodel: PhotoViewModel!
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Home"
initTableView()
photoViewmodel = PhotoViewModel()
photoViewmodel.loadNewPhotos {
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
func initTableView() {
tableView = UITableView.init(frame: self.view.frame, style: .plain)
tableView.delegate = self
tableView.dataSource = self
tableView.rowHeight = 175
tableView.separatorStyle = .none
tableView.register(HomeTableViewCell.nib, forCellReuseIdentifier: HomeTableViewCell.identifier)
view.addSubview(tableView)
}
}
extension MainViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return photoViewmodel.photos.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
print("cellForRowAt")
let cell = tableView.dequeueReusableCell(withIdentifier: HomeTableViewCell.identifier, for: indexPath) as! HomeTableViewCell
cell.tag = indexPath.row
cell.configureCell(url: photoViewmodel.photos[indexPath.row].regularImgUrl, cacheKey: indexPath.row)
return cell
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
print("willDisplay")
let lastCell = photoViewmodel.photos.count - 1
if indexPath.row == lastCell {
print("add 10 more photos")
photoViewmodel.loadNewPhotos(
DispatchQueue.main.async {
self.tableView.reloadData()
}
})
}
}
}
Everything works fine except the last line where I try to show the tableView in live view does not work: PlaygroundPage.current.liveView = controller
I can't figure out what I'm getting wrong?
import UIKit
import PlaygroundSupport
import Foundation
class TableViewController: UITableViewController {
let tableData = ["Matthew", "Mark", "Luke", "John"]
override func viewDidLoad() {
super.viewDidLoad()
print("Hello Matt")
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableData.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as UITableViewCell
cell.textLabel?.text = tableData[indexPath.row]
return cell
}
}
let controller = TableViewController()
PlaygroundPage.current.liveView = controller
I think you forgot to register the table view cell class in viewDidLoad()
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
}
In func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath), add one line to the top of the function:
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
Like this:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
var cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as UITableViewCell
cell.textLabel?.text = tableData[indexPath.row]
return cell
}