I have been trying to incorporate tableview inside uiview xib file in Xcode.
I was able to get the table shown but unable to include customized cell in it.
here is my main code:
class homemoments:UIView, UITableViewDataSource, UITableViewDelegate {
var posts: Posts!
let screenHeight = UIScreen.main.bounds.height
let screenWidth = UIScreen.main.bounds.width
#IBOutlet weak var tableView: UITableView!
override init(frame: CGRect) {
super.init(frame: frame)
posts = Posts()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "newsfeedcell")
commitint()
}
//initWithCode to init view from xib or storyboard
required init?(coder: NSCoder) {
super.init(coder: coder)
commitint()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "newsfeedcell") as! NewsfeedTableViewCell
cell.set(post: posts.postsArray[indexPath.row])
return cell
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.postsArray.count
}
func commitint(){
let viewFromXib = Bundle.main.loadNibNamed("homemoments", owner: self, options: nil)![0] as! UIView
viewFromXib.frame = self.bounds
addSubview(viewFromXib)
}
}
when I run this code, my tableview.register returns an error saying that tableview is nil.
which is weird because initially my tableview.delegation & datasource doesn't work either. so I manually add them by dragging the tableview to file owner from the xib file to set those.
is this because we are not able to create customized cell for the tableview in xib? since I did notice that the tableview in xib doesn't have prototyped mode compared to uiviewcontroller.
UPDATES
My tableview now shows with the exception that there is no cell content shown.
I have searched and was told that to use
tableView.register(UINib(nibName: "momentcell", bundle:nil),forCellReuseIdentifier:"momentcell")
see below:
override init(frame: CGRect) {
super.init(frame: frame)
commitint()
posts = Posts()
tableView.register(UINib(nibName: "momentcell", bundle:nil),forCellReuseIdentifier:"momentcell")
}
//initWithCode to init view from xib or storyboard
required init?(coder: NSCoder) {
super.init(coder: coder)
commitint()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "momentcell") as! momentcell
//cell.set(post: posts.postsArray[indexPath.row])
cell.backgroundColor = .blue
return cell
}
here's the screenshot of my cell xib file
import UIKit
class momentcell: UITableViewCell {
}
and now the error is saying that
let cell = tableView.dequeueReusableCell(withIdentifier: "momentcell") as! momentcell
this is nil
Tableview will not be initialized yet In init if you are using storyboard
Please try to access it from awakefromnib or viewdidload
The problem is that you try to access tableView before xib is loaded.
Try this
override init(frame: CGRect) {
super.init(frame: frame)
posts = Posts()
commitint()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "newsfeedcell")
tableView.dataSource = self
tableView.delegate = self
}
If it's not working than probably you have incorrect xib set up. You can reference to this article, it explains how to load UIView from xib quite detailed
Related
I have followed this tutorial to create a custom .xib, which I plan to use in a table view's cell:
https://medium.com/#brianclouser/swift-3-creating-a-custom-view-from-a-xib-ecdfe5b3a960
Here is the .xib's class I created:
class UserView: UIView {
#IBOutlet var view: UIView!
#IBOutlet weak var username: UILabel!
override init(frame: CGRect) {
super.init(frame: frame)
initialize()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
initialize()
}
private func initialize() {
Bundle.main.loadNibNamed("UserView", owner: self, options: nil)
addSubview(view)
view.frame = self.bounds
view.autoresizingMask = [.flexibleHeight, .flexibleWidth]
}
}
Previously, I was creating my table view cell within the storyboard, but I've come to realize that I want a more flexible view so that I can use it in different parts of my app, so I created the above custom .xib, UserView.
I have updated the table view cell in the storyboard to use the custom .xib:
https://i.stack.imgur.com/t7Tr7.png
Here is what my table view controller class looked like prior to creating the custom .xib (i.e. making the layout in the storyboard):
class UserTableViewController: UITableViewController {
// MARK: Properties
let provider = MoyaProvider<ApiService>()
var users = [User]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.estimatedRowHeight = 100
tableView.rowHeight = UITableViewAutomaticDimension
// Fetch the user by their username
provider.request(.getUsers()) { result in
switch result {
case let .success(response):
do {
let results = try JSONDecoder().decode(Pagination<[User]>.self, from: response.data)
self.users.append(contentsOf: results.data)
self.tableView.reloadData()
} catch {
print(error)
}
case let .failure(error):
print(error)
break
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return users.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "UserTableViewCell"
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? UserTableViewCell else {
fatalError("The dequeued cell is not an instance of UserTableViewCell.")
}
let user = users[indexPath.row]
cell.username.text = user.username
return cell
}
}
Here is the table view cell class:
class UserTableViewCell: UITableViewCell {
//MARK: Properties
#IBOutlet weak var userView: UserView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
My question is, how do I update the above table view controller class to use my custom .xib, instead of using the storyboard layout?
You can use 2 ways:
Create UITableViewCell (better)
1) Change UIView to UITableViewCell
class CustomTableViewCell: UITableViewCell {
...
class var identifier: String {
return String(describing: self)
}
}
2) Register your cell
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.registerNib(UINib(nibName: CustomTableViewCell.identifier, bundle: nil), forCellReuseIdentifier: CustomTableViewCell.identifier)
...
}
3) Use cellForRow(at:)
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: CustomTableViewCell.identifier) as! CustomTableViewCell
cell.username.text = user.username
return cell
}
OR Add view as subview to cell (only in rare cases)
1) Add this to UserView
class UserView: UIView {
...
class func fromNib() -> UserView {
return UINib(nibName: String(describing: self), bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! UserView
}
}
2) Use cellForRow(at:)
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "UserTableViewCell"
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? UserTableViewCell else {
fatalError("The dequeued cell is not an instance of UserTableViewCell.")
}
let userView = UserView.fromNib()
let user = users[indexPath.row]
userView.username.text = user.username
//Use frame size, but for me better to add 4 constraints
userView.frame = CGRect(x: 0, y: 0, width: cellWidth, height: cellHeight)
cell.contentView.addSubview(UserView)
return cell
}
Hi I hav an issue where I cant seem to find the cell identifier to put into my table. I have 5 files.I am new to xcode but I need to code without a storyboard for my school project.
I am following the tutorial here -https://www.youtube.com/watch?v=kYmZ-4l0Yy4
ActiveCasesController.swift
//
// ActiveCasesController.swift
//
// Created by fypj on 29/3/18.
// Copyright © 2018 fypj. All rights reserved.
//
import UIKit
class ActiveCasesController:UIViewController, UITableViewDelegate, UITableViewDataSource {
let elements = ["horse", "cat", "dog", "potato","horse", "cat", "dog", "potato","horse", "cat", "dog", "potato"]
var acView = ActiveCasesView()
override func viewDidLoad() {
super.viewDidLoad()
setupView()
acView.tableView.delegate = self
acView.tableView.dataSource = self
}
func setupView() {
let mainView = ActiveCasesView(frame: self.view.frame)
self.acView = mainView
self.view.addSubview(acView)
acView.setAnchor(top: view.topAnchor, left: view.leftAnchor, bottom: view.bottomAnchor, right: view.rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return elements.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:ActiveCaseCellView = tableView.dequeueReusableCell(withIdentifier: "customCell") as! ActiveCaseCellView
cell.cellView.layer.cornerRadius = cell.cellView.frame.height / 2
cell.lblCell.text = elements[indexPath.row]
return cell
}
}
ActiveCasesView.swift
import UIKit
class ActiveCasesView: UIView{
#IBOutlet var mainView: UIView!
#IBOutlet weak var tableView: UITableView!
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
//scrollView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
private func commonInit(){
Bundle.main.loadNibNamed("ACView", owner: self, options: nil)
addSubview(mainView)
mainView.frame = self.bounds
mainView.autoresizingMask = [.flexibleHeight,.flexibleWidth]
}
}
ACView.xib
ActiveCaseCellView.swift
import UIKit
class ActiveCaseCellView:UITableViewCell {
#IBOutlet weak var cellView: UIView!
#IBOutlet weak var lblCell: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
}
ACViewCell.xib
Error Message
Image of me adding register not sure whether i added correctly..
use the cell identifier by selecting you cell in storyboard.
it must be same in viewcontroller and storyboard tableview cell.
Open your .xib file and drag and drop UITableViewCell not UIView.
After that select attribute inspector you will see cell identifier textbook where you need to set cell identifier
Don't forget to register table view cell before using it!!
self.tableView.registerClass(<YourCustomCellClass>, forCellReuseIdentifier: "cellIdentifier")
or
let nib = UINib(nibName: "YourNibFileName", bundle: nil)
tableView.register(nib, forCellReuseIdentifier: "cellIdentifier")
You need to call register(_:forCellReuseIdentifier:) on your tableView to make it find the requred cells upon calling dequeue....
You can set the reuse identifier in the xib or storyboard where your cell is defined.
Set cell identifier in Xib
Register Xib with UITableView in viewDidLoad :
tableView.register(UINib(nibName: "ActiveCaseCellView", bundle: Bundle.main), forCellReuseIdentifier: "customCell")
I am creating iOS app with swift for the iPad. There is going to be table view for every view and I created a UITableView class but I cannot able to view any data. I have already linked the tableview inside other views to that custom class already.
import UIKit
class SideTable: UITableView, UITableViewDataSource, UITableViewDelegate {
var TableItems = ["...", "Dashboard"]
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func awakeFromNib() {
super.awakeFromNib()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return TableItems.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = dequeueReusableCell(withIdentifier: TableItems[indexPath.row])! as UITableViewCell
cell.textLabel?.text = TableItems[indexPath.row]
cell.textLabel?.numberOfLines = 0
cell.textLabel?.lineBreakMode = NSLineBreakMode.byWordWrapping
// let currentpagetitle = self.navigationItem.title?.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
let cellname = cell.reuseIdentifier?.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
// if (cellname == currentpagetitle)
// {
//
// cell.backgroundColor = UIColor.lightGray
// }
//
return cell
}
Did you connect the data source and delegate?
put in your viewwilllappear, for example (or viewDidLoad):
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.tableview.datasource = self
self.tableview.delegate = self
}
Or connect it if you are using Storyboard or Xib
Control + click over tableview and connect with owner, then selecte delegate and repeat for data source
If this is not the problem, maybe you have a problem with the definition of the cell. Change your dequeueCell:
let cell = tableView.dequeueReusableCellWithIdentifier("CellIdentifier", forIndexPath: indexPath) as UITableViewCell
Use the same identifier if the cell are similar. Now you are using different names, you are using TableItems[indexPath.row] for each cell
I'm trying to load an UITableView from a xib file. I created an UIView object which I use in order to load the xib file. Here I added an UITableView but with the last update of Xcode, I can't figure out how to include a prototype cell inside this table view.
Here there is my code of the UIView which loads the xib file:
class TopChartView: UIView, UITableViewDataSource, UITableViewDelegate {
#IBOutlet var tableViewChart: UITableView!
var view : UIView!
var prova = [String]()
override init(frame: CGRect) {
super.init(frame: frame)
prova.append("hi")
prova.append("bye")
self.tableViewChart = UITableView()
self.tableViewChart.delegate = self
self.tableViewChart.dataSource = self
self.tableViewChart.registerClass(TopChartTVCell.self, forCellReuseIdentifier: "TopChart_IDcell")
//carico il file xib
xibSetup()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func xibSetup() {
Global.log.action()
view = loadViewFromNib()
// Make the view stretch with containing view
view.autoresizingMask = [UIViewAutoresizing.FlexibleWidth, UIViewAutoresizing.FlexibleHeight]
self.addSubview(view)
Global.log.action(methodEnded: true)
}
override func layoutSubviews() {
super.layoutSubviews()
Global.log.action()
let screenSize: CGRect = UIScreen.mainScreen().bounds
view.frame.size.width = screenSize.width
view.frame.size.height = screenSize.height
view.frame.origin.x = 0
view.frame.origin.y = 0
Global.log.action(methodEnded: true)
}
func loadViewFromNib() -> UIView {
Global.log.action()
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: Constants.topChartVC.xibFileName, bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
Global.log.action(methodEnded: true)
return view
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.prova.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("TopChart_IDcell", forIndexPath: indexPath) as! TopChartTVCell
let elem = self.prova[indexPath.row]
cell.label.text = elem
return cell
}
}
And here there is my simple xib which is the problem because I'm not able to add an UITableViewCell inside the UITableView:
I have a problem, i have a controller, and in viewdidload, i try to load a subview created from a xib file.
My "custom" subview is well added to my first controller but the tableview isn't responding... i mean it doesn't scroll, and when i click it, nothing happens... (i haven't implemented yet the method to trigger an action when a cell is clicked, but the celle isn't highlighted when clicked).
Here the code :
class FirstViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let v1 = MyViewTest(frame: CGRectZero)
v1.tableView.dataSource = self
v1.tableView.delegate = self
self.view.addSubview(v1)
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//datasource method returning the what cell contains
let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "MyTestCell")
//reusing the previous scrolled cells from table view(if any)
//cell.textLabel?.text = array[indexPath.row]
cell.textLabel?.text = "test"
//passing each elements of the array to cell
return cell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//datasource method returning no. of rows
return 14
}
}
here the code in MyViewTest
class MyViewTest: UIView {
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var tableView: UITableView!
var view:UIView!
let nibName:String = "MyViewTest"
override init(frame: CGRect) {
super.init(frame:frame)
setup()
}
required init(coder aDecoder: NSCoder) {
//fatalError("init(coder:) has not been implemented")
super.init(coder: aDecoder)
setup()
}
func setup() {
view = loadViewFromNib()
let screenSize: CGRect = UIScreen.mainScreen().bounds
let sWidth = screenSize.width
let sHeight = screenSize.height
let xPos = sWidth/2-(view.bounds.width/2)
let yPos = sHeight/2-(view.bounds.height/2)
view.frame = CGRectMake(xPos, yPos, view.bounds.width, view.bounds.height)
addSubview(view)
}
func loadViewFromNib () -> UIView {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: nibName, bundle: bundle)
let mview = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
return mview
}
}
in the xib file, i only have a view with a label and my tableview in. The xib file is associated with its class (in identifier).
If you know why my table view isn't working it would be great thx !
You seem to set the frame of the MyTestView to CGRectZero.
You then add your table as a subview of this view with the frame size set up. As MyTestView has 0 width and height and the default for a view is to not clip subviews I imagine you can see the table but not click it.
Try setting the frame of your MyTestView to the screen size?
The problem happens because I instantiate my MyViewTest with CGRectZero. If i use a CGRectMake for example with actual width and height it works great.
See rory mckinnel post just above for more details :-)