I'm trying to show a TableView inside a Form Sheet. This is totally working as expected on iPhone. However, when I test it on iPad for some reason the view is bigger than the Form Sheet.
Here is an Image of what I'm talking about:
iPad
As you can see the text isn't all visible in the frame. Full text is "THIS IS NOT SHOWING FULLY"
Here is what it is supposed to look like (ignore the dark mode)
iPhone
In MainController() I presented this page IntroController() by having this in ViewDidLoad()
let navController = UINavigationController(rootViewController: IntroController())
present(navController, animated: true, completion: nil)
In IntroController() this is the code.
import UIKit
var tableview: UITableView!
class IntroController: UIViewController, UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: TableCell.reuseIdentifier()) as! TableCell
cell.label.text = "Amount"
cell.typeLabel.text = "THIS IS NOT SHOWING FULLY"
cell.selectionStyle = .none
cell.accessoryType = .none
return cell
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func viewDidLoad() {
super.viewDidLoad()
tableview = UITableView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height), style: .grouped)
view.addSubview(tableview)
tableview.register(UINib(nibName: TableCell.nibName(), bundle: nil), forCellReuseIdentifier: TableCell.reuseIdentifier())
tableview.delegate = self
tableview.dataSource = self
}
}
Does anyone know why is this happening and how to fix it?
Thank you!
Instead of adding the table view to the view of VC as a subview, set it directly as the view:
view = tableview
Alternatively, use a UITableViewController directly. I strongly recommend you choose this approach.
class IntroController: UITableViewController {
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
...
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(nibName: TableCell.nibName(), bundle: nil), forCellReuseIdentifier: TableCell.reuseIdentifier())
}
}
I am not sure what causes this, but if I were to guess, it is probably because that view.frame is, for some reason, not set to the rect of the content size of VC (yet) when viewDidLoad is called. If you move the code that adds the table view as a subview of view to viewDidLayoutSubviews, then it works as well:
override func viewDidLayoutSubviews() {
if view.subviews.count < 1 {
tableview = UITableView(frame: CGRect(x: 0, y: 0, width: view.bounds.width, height: view.bounds.height), style: .grouped)
tableview.register(UINib(nibName: TableCell.nibName(), bundle: nil), forCellReuseIdentifier: TableCell.reuseIdentifier())
view.addSubview(tableview)
tableview.delegate = self
tableview.dataSource = self
}
}
Related
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
}
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.
Trying to play with Table in the XCode Playgrounds to understand how it works, because there a lot of stuff connected to the UITableView and a few tutorials describe these relations and inheritance under the scenes (like UIView -> UIScrollView -> UITableView -> UITableViewCell) and how it manages that inheritance, connections and delegations. Normally with an ordinary tutor, you're given with snippet of code and the instructions how to establish delegate connections in XCode and the right methods to call. Result - you memorize the steps but still don't understand the mechanism of the Table. Below is code snippet that I try to adopt for XCode Playgrounds to draw a simple table. The problem - I can't properly register programmatically reuse identifier for Table cell nether from class or outside it. The nature of error
reason: 'unable to dequeue a cell with identifier Cell - must register a nib or a class for the identifier or connect a prototype cell in a storyboard'.
Please, help and point out what is wrong and why.
class TableViewController: UITableViewController {
let tableData = ["Matthew", "Mark", "Luke", "John"]
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 {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as UITableViewCell
cell.textLabel?.text = tableData[indexPath.row]
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.dataSource = self
//Did this part as comments to try to do this outside the class
// self.view.frame = CGRect(x: 0, y: 0, width: 320, height: 480)
// self.tableView = UITableView(frame:self.view.frame)
// self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
self.view.addSubview(self.tableView)
}
}
let frame = CGRect(x: 0, y: 0, width: 320, height: 480)
let tableView = UITableView(frame: frame, style: .plain)
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
PlaygroundPage.current.liveView = TableViewController()
In a UIViewController contaning a UITableView, programmatically registering of Custom UITableViewCell Subclasses to an instance of UITableView is implemented by:
- (void)registerClass:(nullable Class)cellClass forCellReuseIdentifier:(NSString *)identifier
This is registeringClass should be done before setting up table's dataSource.
After long time playing with different solutions of building tables from various tutorials I finally have caught some difference in use between a UITableViewController and a UIViewController for displaying a UITableView. In my example from my question, some lines of code are just redundant. That's happened because I tried to implement the approach of building a table within the UIViewController, but I used the UITableViewController instead and additionally tried to set the dataSource and all view properties, but as I understand now - the UITableViewController already does all this stuff for me (correct me here if I wrong). The functioning snippet of code is below:
class TableViewController: UITableViewController {
let tableData = ["Matthew", "Mark", "Luke", "John"]
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 {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as UITableViewCell
cell.textLabel?.text = tableData[indexPath.row]
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
}
}
PlaygroundPage.current.liveView = TableViewController()
Can anyone see why in the world didSelectRowAtIndexPath would not be called? I have triple checked by delegate both in the code and in storyboard.
class AddCard: UIViewController,UIPopoverPresentationControllerDelegate, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var cardView: UIView!
#IBOutlet weak var tableView: UITableView!
let tableItems = ["Background Color","Background Image","Font Style","Font Color"]
let cellID = "cell"
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func setBackgroundColor (_ color: UIColor) {
cardView.backgroundColor = color
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableItems.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellID, for: indexPath as IndexPath)
let row = indexPath.row
cell.textLabel?.text = tableItems[row]
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath) {
tableView.deselectRow(at: indexPath as IndexPath, animated: true)
print(indexPath.row)
let row = indexPath.row
switch(row){
case 0:
let popoverVC = storyboard?.instantiateViewController(withIdentifier: "colorPickerVC") as! ColorPickerViewController
popoverVC.modalPresentationStyle = .popover
popoverVC.preferredContentSize = CGSize(width: 284, height: 446)
if let popoverController = popoverVC.popoverPresentationController {
popoverController.sourceView = self.view
popoverController.sourceRect = CGRect(x: 0, y: 0, width: 85, height: 30)
popoverController.permittedArrowDirections = .any
popoverController.delegate = self
popoverVC.delegate = self
}
present(popoverVC, animated: true, completion: nil)
break
default: break
}
}
}
Swift 3 modified the signature of the method (a lot of methods too, new "rules"/style)
Replace:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath) with
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
Notice the _, the didSelectRowAt vs didSelectRowAtIndexPath, like the other ones you updated (which adapted also the same "style"), but not this one.
Remove the line and let XCode do the autocompletion. Else, you can just replace it with the one from the doc.