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:
Related
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
I have UICollectionView with cells, that contains UIScrollView and inside it, there is a user defined UIView (via XIB)
I am using this code to init cell with data:
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
for v in cell.contentView.subviews {
if let scroll: UIScrollView = v as? UIScrollView {
scroll.contentOffset = CGPoint(x: 0, y: 0)
for s in scroll.subviews {
if let content: DetailedView = s as? DetailedView {
content.fillData()
}
}
}
}
}
In my DetailedView, I have:
#IBDesignable
class DetailedView: UIView {
#IBOutlet weak var btnTemp: UIButton!
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupView()
}
// Performs the initial setup.
private func setupView() {
let view = viewFromNibForClass()
view.frame = bounds
// Auto-layout stuff.
view.autoresizingMask = [
UIViewAutoresizing.flexibleWidth,
UIViewAutoresizing.flexibleHeight
]
addSubview(view)
}
// Loads a XIB file into a view and returns this view.
private func viewFromNibForClass() -> UIView {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: String(describing: type(of: self)), bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil).first as! UIView
return view
}
func fillData(){
self.btnTemp.titleLabel?.text = "btn temp"
print("fill data")
}
#IBAction func btnTempClick(_ sender: Any) {
print("Click")
}
}
All is working - view is visible, btnTempClick is called, but fillData is not working. It does not change content of button, there is still default text "Button". How to fix this?
Just to make it official removing it from comment and putting it as an answer.
have you tried using self.btnTemp.setTitle("btn temp", for:.normal)?
i think you can try with setTitle forControlState
I have an UITableViewCell contain a custom view, the custom view contains two label. The view hierarchical likes that:
|---Label 1
XIB---MyTableViewCell---MyView---|
|---Label 2
But run application, just shown 'MyView', Label 1 and Label 2 not visible! If I wrote code on viewDidLoad, take 'MyView' as viewController.view's subview, the label 1 and 2 is appeared. Hope you can help me.
Have you tried this?
Create MyView like this:
class MyView: UIView {
#IBOutlet weak var _label1: UILabel!
#IBOutlet weak var _label2: UILabel!
// Our custom view from the XIB file
var view: UIView!
//MARK: - Setup -
private func xibSetup() {
view = loadViewFromNib()
view.frame = bounds
// Make the view stretch with containing view
view.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
addSubview(view)
}
private func loadViewFromNib() -> UIView {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: "MyView", bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
return view
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
xibSetup()
}
override func awakeFromNib() {
super.awakeFromNib()
}
func setLabeles(lbl1: String, lbl2: String) {
_label1!.text = lbl1
_label2!.text = lbl2
}
}
Make Label1 and Label2 outlet to respective ones.
Then add it to custom tableViewCell as:
(Pink colour is for highlighting!)
Make My View outlet.
Custom cell code:
#IBOutlet weak var _myView: MyView!
class func identifier() -> String {
return "CustomTableViewCellId"
}
class func nib() -> UINib {
let nib = UINib(nibName: "CustomTableViewCell", bundle: NSBundle.mainBundle())
return nib
}
//MARK: Public Methods
func setCellIndexLabel(index: Int) {
_myView!.setLabeles("lbl1: \(index)", lbl2: "lbl2: \(index)")
}
Then there is no need to do extra anything in table view, just do:
In viewDidLoad()-
tableView!.registerNib(CustomTableViewCell.nib(), forCellReuseIdentifier: CustomTableViewCell.identifier())
//then
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// Configure the cell...
let cell = tableView.dequeueReusableCellWithIdentifier(CustomTableViewCell.identifier(), forIndexPath: indexPath) as! CustomTableViewCell
cell.setCellIndexLabel(indexPath.row)
return cell
}
And you will get this:
Is this what you are looking for?
Forgive me for providing swift code, but it's not much different that objective-c!
I have created a small sample project using Swift. I have created an "MyCustomView" as xib which contains label, button and imageView as shown in below code:
import UIKit
#IBDesignable class MyCustomView: UIView {
#IBOutlet weak var lblName: UILabel!
#IBOutlet weak var btnClick: UIButton!
#IBOutlet weak var myImageView: UIImageView!
var view:UIView!
#IBInspectable
var mytitleLabelText: String? {
get {
return lblName.text
}
set(mytitleLabelText) {
lblName.text = mytitleLabelText
}
}
#IBInspectable
var myCustomImage:UIImage? {
get {
return myImageView.image
}
set(myCustomImage) {
myImageView.image = myCustomImage
}
}
override init(frame : CGRect)
{
super.init(frame: frame)
xibSetup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
xibSetup()
}
func xibSetup()
{
view = loadViewFromNib()
view.frame = self.bounds
// not sure about this ?
view.autoresizingMask = [UIViewAutoresizing.FlexibleWidth, UIViewAutoresizing.FlexibleHeight]
addSubview(view)
}
func loadViewFromNib() -> UIView {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: "MyCustomView", bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
return view
}
}
Attached the image of xib for the reference.
In StoryBoard -> ViewController added UIViewCollection which as shown in the below image. In this viewcollection, I need that orange color cell to contain my custom xib to be loaded at runtime.
How do I achieve this?
New Modified code as suggested by Sandeep
// 1
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView.register(UINib(nibName: "MyCustomView", bundle: nil), forCellWithReuseIdentifier: "myCell")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 7
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell : MyCustomView = collectionView.dequeueReusableCellWithReuseIdentifier("your_reusable_identifier", forIndexPath: indexPath) as! MyCustomView
cell.lblName.text = "MyNewName"
return cell
}
}
// 2
import UIKit
#IBDesignable class MyCustomView: UICollectionViewCell {
#IBOutlet weak var lblName: UILabel!
#IBOutlet weak var btnClick: UIButton!
#IBOutlet weak var myImageView: UIImageView!
var view:UIView!
#IBInspectable
var mytitleLabelText: String? {
get {
return lblName.text
}
set(mytitleLabelText) {
lblName.text = mytitleLabelText
}
}
#IBInspectable
var myCustomImage:UIImage? {
get {
return myImageView.image
}
set(myCustomImage) {
myImageView.image = myCustomImage
}
}
}
Here is what you can do,
Change your MyCustomView class to be a subclass of UICollectionViewCell and not UIView.
Remove override init(frame : CGRect),required init?(coder aDecoder: NSCoder),func xibSetup(),func loadViewFromNib() -> UIView from MyCustomView
I seriously could not understand how are you using your setter and getter for mytitleLabelText and myCustomImage. If its of no use get rid of it as well.
Finally you will be left with just IBOutlets in MyCustomView.
For better coding practice change the name from MyCustomView to MyCustomCell (optional)
Go to your xib, select the xib and set its class as MyCustomView.
In the same screen change file owner to yourView controller hosting collectionView
In ViewDidLoad of your viewController register your nib.
self.collectionView.registerNib(UINib(nibName: "your_xib_name", bundle: nil), forCellWithReuseIdentifier: "your_reusable_identifier")
In cellForItemAtIndexPath,
let cell : MyCustomView = collectionView.dequeueReusableCellWithReuseIdentifier("your_reusable_identifier", forIndexPath: indexPath) as! MyCustomView
cell.lblName.text = "bla bla" //access your Cell's IBOutlets
return cell
Finally in order to control the size of cell either override the delegate of collectionView or simply go to your collectionView select the collectionCell in it and drag it to match your dimension :) Thats it :)
Happy coding. Search tutorials for better understanding. I can't explain all delegates as I'll end up writing a blog here.
For Swift 4.0
in viewDidLoad:
//custom collectionViewCell
mainCollectionView.register(UINib(nibName: "your_customcell_name", bundle: nil), forCellWithReuseIdentifier: "your_customcell_identifier")
in cellForItemAt indexPath:
let cell : <your_customcell_name> = mainCollectionView.dequeueReusableCell(withReuseIdentifier: "your_customcell_identifier", for: indexPath) as! <your_customcell_name>
And dont forget to set identifier for your custom cell in xib section.
One line approach if you have to register multiple cells.
extension UICollectionViewCell {
static func register(for collectionView: UICollectionView) {
let cellName = String(describing: self)
let cellIdentifier = cellName + "Identifier"
let cellNib = UINib(nibName: String(describing: self), bundle: nil)
collectionView.register(cellNib, forCellWithReuseIdentifier: cellIdentifier)
}
}
Steps on how to use
Name your Cell identifier as "YourcellName" + "Identifier" eg:
CustomCellIdentifier if your cell name is CustomCell.
CustomCell.register(for: collectionView)
For Swift 4.2
in viewDidLoad
self.collectionView.register(UINib(nibName: "your_xib_name", bundle: nil), forCellWithReuseIdentifier: "your_reusable_identifier")
in cellForItemAt indexPath:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "your_reusable_identifier", for: indexPath) as! MyCustomView
And of course as #Raj Aryan said:
don't forget to set identifier for your custom cell in xib section.
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 :-)