i'm trying to implement the following design with MapBox and a TableView.
I've been thinking about it and I wanted to use a UITableView for the results, but as far as I know, it's only possible to have data and detail on the left & right side. Is there an alternative to UITableView ?
If not, i'm also facing the problem that my "root"-View is a MapView (from MapBox) and that I can't use the MapViewController as UITableViewController nor as UITableViewDelegate/UITableViewDataSource. Is it possible to Embed the MapView in another View ?
If you need any more information, just let me know. And thank you in advance.
but as far as I know, it's only possible to have data and detail on the left & right side. Is there an alternative
You know wrong. You can include any interface you want in a table view cell. Just make this a custom cell and design it as desired.
Assuming that you have a UIViewController in your storyboard or xib called ViewController which has both a UITableView and an MKMapView (or whatever you are using) correctly connected to the two outlets in the code below:
import UIKit
import MapKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, MKMapViewDelegate {
#IBOutlet weak var mapView: MKMapView!
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Now tell the system that we are going to reference our
// hand-made table cell from a xib called "MyCell"
self.tableView.register(UINib(nibName: "MyCell", bundle: nil), forCellReuseIdentifier: "MyCell")
// These next you can do here, or in IB...
self.tableView.dataSource = self
self.tableView.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//MARK: - TableViewDataSource
// ANY ViewController can do this, if we register the class as conforming
// to the `UITableViewDataSource` protocol
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 {
// Get a reference to an instance of our very own UITableViewCell subclass,
// Which we registered in `viewDidLoad`
let c = self.tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) as! MyCell
// Whatever controls/outlets we have put in our cell subclass,
// we need to populate with data now... (I just did a label)
c.cellNumber?.text = "\(indexPath.row)"
return c
}
//MARK: - TableViewDelegate
//... implement whatever funcs you need ...
//MARK: - MKMapViewDelegate
//... implement whatever funcs you need ...
}
You then need to create the following code, AND a stand-alone xib (called in this case "MyCell.xib"). The xib should contain all of the controls you want in your table cell. In my example it has only one control, the UILabel referenced as cellNumber.
To make the xib, choose "File->New File->User Interface->Empty" from the Xcode menu, then drop a UITableViewCell into the xib from the palette. Make sure you change the class of the cell from UITableViewCell to MyCell. Add whatever controls (and constraints between them) that you need. Obviously, connect all of your controls to relevant #IBOutlets in this class.
class MyCell: UITableViewCell {
// Create `#IBOutlet weak var ...` for all of the controls in your cell here
#IBOutlet weak var cellNumber: UILabel!
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.configureCell()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.configureCell()
}
func configureCell() {
// Your stuff to load up the IBOutlet controls of your cell with defaults.
// You will be able to override these when the instantiated cell is passed to
// `tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell`
// in the `UITableViewDataSource`
}
}
Related
I wanted to create a custom view. So I designed my view like so..it's called TagResolutionView.xib
This is how I designed my view
And the TagResolutionView.swift file for that looks like this
import UIKit
#IBDesignable class TagResolutionView: UIView {
#IBOutlet var tagResolutionView: UIView!
#IBOutlet var tableview: UITableView!
required init?(coder: NSCoder) {
super.init(coder: coder)
tableview = UITableView()
}
override init(frame: CGRect) {
tableview = UITableView()
super.init(frame: frame)
}
override func awakeFromNib() {
super.awakeFromNib()
}
#IBOutlet weak var delegate: UITableViewDelegate? {
get {
return tableview.delegate
}
set {
tableview.delegate = newValue
}
}
#IBOutlet weak var dataSource: UITableViewDataSource? {
get {
return tableview.dataSource
}
set {
tableview.dataSource = newValue
}
}
func registerClass(cellClass: AnyClass?, forCellReuseIdentifier identifier: String) {
tableview.register(cellClass, forCellReuseIdentifier: "cellClass")
}
func dequeueReusableCellWithIdentifier(identifier: String) -> UITableViewCell? {
return tableview.dequeueReusableCell(withIdentifier: identifier)
}
override func layoutSubviews() {
super.layoutSubviews()
tableview.frame = self.bounds
self.addSubview(tableview)
}
}
This is how I inserted the view in my main viewcontroller where I want the custom view to appear..
This is the view
This is how I configured it in the viewcontroller..
In the viewDidLoad..
stdProcedViewHeight.constant = 533 //Since the view I took above (as given in the pic) is less than the height of the actual TagResolutionView.xib, I increased its height here programatically.
standardsProceduresView.delegate = self
standardsProceduresView.dataSource = self
standardsProceduresView.registerClass(cellClass: UpdatingListTableViewCell.self, forCellReuseIdentifier: "cellClass") //I have also made .xib & .swift files for UpdatingListTableViewCell
Also added these methods..
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: UpdatingListTableViewCell = self.standardsProceduresView.dequeueReusableCellWithIdentifier(identifier: "cellClass") as! UpdatingListTableViewCell
// cell.nameLbl.text = "MyName"
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
But I'm not able to get the desired output by doing all of this...All I get is just an empty tableview of the set height(height of 533 here) and nothing else of the design...
The reason why your table view doesn't show up is that you're resetting all of its content by calling tableView = UITableView() in your code.
It seems like you're using Storyboards, so assuming you properly connected your UITableView to the property outlet #IBOutlet var tableview: UITableView!, your table view will appear just fine and you don't need to initialize it via code.
I can also see that you're setting the frame of your table view and adding it to the view hierarchy in the layoutSubviews() method. That's definitely not something you need/want to do, first because you're using Storyboards and it means that your table view will already be part of the view hierarchy at this point.
I'd also mention that you should generally never add a subview in the layoutSubviews() method, because this method may be called multiple times and it means your view would be added multiple times to the view hierarchy, which would end up wasting memory.
//custom cell in one swift file
import UIKit
class CardTableViewCell: UITableViewCell {
#IBOutlet weak var elapsedTime: UILabel!
#IBOutlet weak var todo: UILabel!
#IBOutlet weak var startAndStop: UIView!
#IBOutlet weak var progress: UIView!
#IBOutlet weak var cardView: UIView!
}
//custom Table view controller in another swift file
import UIKit
class CardFeedTableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(CardTableViewCell.self, forCellReuseIdentifier: "cardCell")
tableView.delegate = self
tableView.dataSource = self
}
// MARK: - Table view data source
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return 3
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: CardTableViewCell = self.tableView.dequeueReusableCell(withIdentifier: "cardCell", for: indexPath) as! CardTableViewCell
cell.todo.text = "study"
return cell
}
running the app triggers a error
storyboard
I don't know why all the properties in the my table cell is nil, when I run the app.
There are two variants to register, but both take a parameter called
forCellReuseIdentifier, which is a string that lets you register
different kinds of table view cells. For example, you might have a
reuse identifier "DefaultCell", another one called "Heading cell",
another one "CellWithTextField", and so on. Re-using different cells
this way helps save system resources.
If you want to use register() with a Swift class, you provide a table
view cell class as its first parameter. This is useful if your cell is
defined entirely in code. As an example, this uses the default
UITableViewCell class:
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "DefaultCell")
You can then dequeue that cell like this:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "DefaultCell")!
return cell
}
The other option is to use register() with an Interface Builder nib
file. Nibs contain the class name to use along with their design, so
this method is more common. Here's an example
tableView.register(UINib(nibName: "yourNib", bundle: nil), forCellReuseIdentifier: "CellFromNib")
But if you're using storyboards you will find it easier to create
prototype cells and give them a reuse identifier directly inside
Interface Builder.So no need to register programmatically.
Remove this line form viewDidLoad
tableView.register(CardTableViewCell.self, forCellReuseIdentifier: "cardCell).
I'm trying to have a better understanding on how the dataSource and delegate outlets get connected to the UITableView under the hood when you do the connection through the UI in Xcode by dragging and dropping to the viewController icon.
I found this thread but I think I'm missing something because I cannot make it work.
Here is the code I currently have that works fine by connecting the outlets through XCode (by drag and dropping).
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var hobbies:[String] = ["Computers", "Photography", "Cars", "Reading", "Learning New Things"]
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return hobbies.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("myCell", forIndexPath: indexPath) as UITableViewCell
cell.textLabel?.text = hobbies[indexPath.row]
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I tried removing the outlet connections made by XCode, created an outlet for the tableView (myTable) and added the following code in the viewDidLoad method but it doesn't work, no error it just doesn't load the data.
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
myTable.delegate = self
myTable.dataSource = self
}
Can someone describe the steps needed to do this connection with code?
Just for reference here are the steps needed to do your connection programmatically.
1.- Create outlet for tableView
#IBOutlet weak var myTable: UITableView!
2.- Assign delegate and dataSource in the viewDidLoad method.
myTable.delegate = self
myTable.dataSource = self
3.- DONE
There are a couple of ways to do it.
1. The simplest one is by dragging and dropping:
In your main.storyboard select your TableView;
Press your Control button;
Click and drag the mouse from your TableView to your ViewController's icon and drop it;
Then select dataSource and delegate as shown on the image above.
2. The other way is by coding:
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
}
PS: Make sure not to forget connecting your tableView outlet to your code by dragging and dropping it into your ViewController class.
PPS: It'll also ask you to implement the following methods into your class so that your tableView works properly:
numberOfRowsInSection
cellForRowAtIndexPath
For those who don't have them yet, you'll see Xcode complaining about it.
I am new to Swift, and iOS development in general. I am attempting to create a custom UITableViewCell. I have created the cell in my main storyboard on top of a UITableView that is inside a UIViewController. When I loaded one of the default cells, I was able to populate it with data. However, now that I am using a custom cell, I cannot get any data to appear in the table. I have gone through all kinds of tutorials and questions posted on the internet, but I can't figure out why it is not working. Any help would be appreciated.
Here is my code for the UIViewController that the tableview resides in.
import UIKit
class FirstViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tblView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//self.tblView.registerClass(UITableViewCell.self, forCellReuseIdentifier : "Cell")
self.tblView.registerClass(CustomTableViewCell.self, forCellReuseIdentifier : "Cell")
tblView!.delegate = self
tblView!.dataSource = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataMgr.data.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell : CustomTableViewCell = self.tblView.dequeueReusableCellWithIdentifier("Cell", forIndexPath : indexPath) as! CustomTableViewCell
var values = dataMgr.data[indexPath.row]
cell.newTotalLabel?.text = "\(values.newTotal)"
cell.winLoseValueLabel?.text = "\(values.newTotal - values.currentTotal)"
cell.dateLabel?.text = "5/17/2015"
return cell
}
}
I have stepped through the program where it is assigning values to the cell variables. The variable 'values' is being populated with data, but when stepping over the assignment lines to the cell variables, I found that they are never assigned. They all remain nil.
When you make a custom cell in the storyboard, don't register the class (or anything else). Just be sure to give the cell the same identifier in the storyboard that you pass to dequeueReusableCellWithIdentifier:forIndexPath:.
I've been stuck with this problem for days, so I'd be really happy if someone could help.
I'm trying to create a dynamic UITableView, for which I created a custom UITableView subclass and I've created a custom UITableViewCell subclass as well, because I need several UILabels and a UIButton in each cell.
The cell is created, but the problem is that the value of the labels is always nil, hence the cell isn't displayed properly.
This is, how the storyboard looks like, and this is what I see while running the program.
Here's my UITableViewCell subclass:
import UIKit
class QuestionTableViewCell: UITableViewCell {
#IBOutlet var student: UILabel!
#IBOutlet var labDesk: UILabel!
#IBOutlet var topic: UILabel!
#IBOutlet var answers: UILabel!
}
and my UITableView subclass:
import UIKit
class QuestionViewController: UITableViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var table: UITableView!
struct Question {
var student: String
var labDesk: String
var topic: String
var answered: String
}
override func viewDidLoad() {
super.viewDidLoad()
table.estimatedRowHeight = 50
table.dataSource = self
table.delegate = self
self.table.registerClass(QuestionTableViewCell.self, forCellReuseIdentifier: "cell")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell") as QuestionTableViewCell
cell.student.text = "random string"
cell.labDesk?.text = "25/A"
cell.topic?.text = "string"
cell.answers?.text = "3"
return cell
}
}
Try removing self.table.registerClass(QuestionTableViewCell.self, forCellReuseIdentifier: "cell")
If you're using a cell with a nib then make sure that you are registering the cell with the table view using registerNib:forCellReuseIdentifier:. If the cell just has a class then use registerClass:forCellReuseIdentifier:.
First, you don't have to register the class if it exists in Interface Builder.
Second, you should dequeueReusableCellWithIdentifier:forIndexPath instead of dequeueReusableCellWithIdentifier.
Third, UITableViewController already has a property called tableView so there is no need to make an IBOutlet to table as UITableViewController already handles this. It also conforms to the UITableViewDataSource and UITableViewDataSource so these are extraneous.
Fourth, don't set the properties for table set them for tableView.
Fifth, cell.labDesk.text = "" is sufficient, no need to make it optional.
If all your IBOutlets are hooked up, Cell Identifiers correctly set, and these revisions are made, it will work.
class QuestionTableViewCell: UITableViewCell {
#IBOutlet var student: UILabel!
#IBOutlet var labDesk: UILabel!
#IBOutlet var topic: UILabel!
#IBOutlet var answers: UILabel!
}
class QuestionViewController: UITableViewController {
struct Question {
var student: String
var labDesk: String
var topic: String
var answered: String
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.estimatedRowHeight = 50
tableView.dataSource = self
tableView.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as QuestionTableViewCell
cell.student.text = "random string"
cell.labDesk.text = "25/A"
cell.topic.text = "string"
cell.answers.text = "3"
return cell
}
}
The most important part is to register the xib containing the custom cell with the table view. Therefore add the following code in viewDidLoad() method.
let nib = UINib.init(nibName: "MyCustomCell", bundle: nil)
self.tblUsers.register(nib, forCellReuseIdentifier: "MyCustomCell")
I might be late here, but I just solved a similar problem.
Make sure you've set the Identifier in InterfaceBuilder on your UITableViewCell.
For those who are still trying to figure this out after trying all those possible solutions:
Disconnect/Reconnect the IBOutlets in your Storyboards should do the trick!
Don't forget to add:
tableView?.register(UINib(nibName: "xyz",
bundle: nil),
forCellReuseIdentifier: "abc")
If you are using a table cell with Xib. you need to register your cell with ..
register(_:forCellReuseIdentifier:)
If you haven't added constraints for the label then they will not be created though the custom cell is created.
Make sure you added some constraints.
Make sure that the selected cell is in the right "module" and if necessary, inherit:
If not, your IBOutlets will be nil.
Issue I was facing: TableViewCell has been created and all the IBOutlets are nil. So I can't set any values such as text or color etc. Below code worked for me.
Xcode version: 13.3
Step 1:
Remove datasource and delegate reference form storyboard.
Step 2:
In viewDidLoad add,
tableView.delegate = self
tableView.dataSource = self
Step 3:
In tableview UITableViewDataSource cellForRowAt function, add your cell the given way.
let cell = tableView.dequeueCell(ofType: YourCellName.self)
cell.yourCellFunction()
return cell
Note 1: dequeueCell(ofType...) is calling the below function internally. you don't need to use it directly.
func dequeueCell<T: UITableViewCell>(ofType type: T.Type) -> T {
}
Important: You don't need to provide any "Resporation ID" or "Reuse Identifier" for cell. It works with your cell name.