I have a xib that is a UIView, with class MyUIView. I'd like to re-use this view as a Table View Cell, but I'm not sure how I would do that.
I know I have to register the xib for my table view, like:
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(nibName: "MyUIView", bundle: nil), forCellReuseIdentifier: "MyUIView")
}
But other than that, I'm not not sure how to upcast it to a Table View Cell. What modifications do I need to make to the regular Table View/Table View Cell process to use my UIView xib as the cell?
Add a UIView control to your table view cell. Then set its class to MyUIView.
Related
In a normal storyboard, table views come "with" embedded cells. Simply set "Dynamic Prototypes" to 1 (or more):
You then use the those cells in your view controller simply with
...cellForRowAt
let cell = tableView.dequeueReusableCell(
withIdentifier:"YourCellClassID", for: indexPath) as! YourCellClass
Where YourCellClass is the class of the table view cell,
and the string "YourCellClassID" is just
the "Identifier" set in the Attributes Inspector (nowadays the **5th button)** of the storyboard.
(Be careful to NOT use the "restoration identifier" on the 4th button, identity inspector, which sounds the same but is unrelated.)
But what if you want to use an XIB file?
Instead of using one of the prototypes "in" the table view in storyboard?
If you use an XIB file, you can use the same cell in different tables.
How to do it?
Step 1, to make a cell-style XIB file
In current (2020) Xcode there's no direct button to create a table view cell -style XIB file.
The secret is
create a 'Cocoa Touch Class', select UITableViewCell
and ALSO select 'create XIB file'
You now have a cell-style XIB file, TesteCell.xib in the example.
(Feel free to delete TesteCell.swift if you don't need it.)
Step 2, add the register#UINib code in viewDidLoad
If you now try this:
let cell = tableView.dequeueReusableCell(
withIdentifier: "TesteCellID",
for: indexPath) as! TesteCell
In fact it does not work.
In viewDidLoad, you must add
override func viewDidLoad() {
super.viewDidLoad()
// We will be using an XIB file, rather than
// just a cell "in" the table view on storyboard
tableView.register(
UINib(nibName: "filename without suffix", bundle: nil),
forCellReuseIdentifier: "identifier in attributes inspector"
)
}
In the example
override func viewDidLoad() {
super.viewDidLoad()
// We will be using an XIB file...
tableView.register(
UINib(nibName: "TesteCell", bundle: nil),
forCellReuseIdentifier: "TesteCellID")
}
And that's how you do it.
Summary
New file - cocoa touch class - subclass of table cell - do select 'also create XIB file'
In viewDidLoaed, register the XIB file using,
The file name (no suffix) and the identifier
You're done, you can now refer to the cell in the normal way in dequeueReusableCell
I have one view controller which is a subclass of UITableViewcontroller, that UITableViewcontroller i need show under one UIView which I need to assign Corner Radius so it will match with my design.
UITableViewcontroller is the Generic tableview class which I have used in the whole project so I couldn't make changes in the structure.
All my ViewController are created programmatically, i have not used anywhere Storyboard.
Here is my Viewconroller Code where I am implementing
headerViewController is part which i mark as white
deal and team controller is my UITableviewController which i have added in SJSegment
private func setupSegmentController() {
segmentViewController.headerViewHeight = 350
segmentViewController.headerViewController = headerViewController
segmentViewController.segmentControllers = [
dealViewController,
teamViewController]
segmentViewController.delegate = self
addChild(segmentViewController)
segmentViewController.view.frame = view.bounds
view.addSubview(segmentViewController.view)
segmentViewController.didMove(toParent: self)
}
Below in red highlighted is the area which i need to design
What I understand you want to add a view controller as child in some other view controller. You have to use ContainerView in the View Controller where you want to show that table Table View Controller. Create an outlet of that Container View then add the table view as child.
let yourTableViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "yourTableViewController") as! UITableViewcontroller
yourTableViewController.view.autoresizingMask = [.flexibleHeight, .flexibleWidth]
yourTableViewController.view.frame = self.containerView.bounds
self.addChild(yourTableViewController)
containerView.addSubview(yourTableViewController.view)
yourTableViewController.didMove(toParent: self)
You need to subclass UITableView and view.addSubview(yourCustomClass) . It is not necessary to add UITableViewController inside your UIView
Controllers it's also a basic class that can control your view. You can add as subview tableView you your generic view and set their delegate and dataSource to the main view controller. You don't need to create tablewviewcontroller for this.
all you need is - (inside main view controller)
tableView.delegate = self
tableView.dataSource = self.
and after this you must implement protocol conformance
MainViewController: UITableViewCOntrollerDelegate {
// implementation here
}
MainViewController: UITableViewControllerDataSource {
// implementation here
}
After this you can customise your table view like view and do what you want
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
guard let view = loadViewFromNib() else { return }
view.frame = self.bounds
self.addSubview(view) // My question
}
func loadViewFromNib() -> UIView? {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: self.className, bundle: bundle)
return nib.instantiate(withOwner: self, options: nil).first as? UIView
}
i want customXibView initial with nib .look like self = loadViewFromNib(), not by self.addSubview(nibView) .
I found that many of the answers are all done self.addSubview(nibView). In fact, look our view hierarchy,we will found a extra view.
This is my view hierarchy
Is there any way to instance xib to storyboard, not by self.addSubview(nibView).
if you don't understand my question,look this Custom UIView from Xib - requirements, good practices. I hope some one help me.
There are three scenarios:
You have CustomView class with all of its UI defined
programmatically in its drawRect method.
You have CustomView class with its UI defined in a subview of storyboard scene with its class set to 'CustomView'.
You have CustomView class with its UI defined in a separate xib.
Now if you want to include your CustomView in as a subview in your viewcontroller, the method differs depending how your class is defined in the first instance. Secondly how do you want to include it in you viewcontroller.
Adding CustomView with scenario 1:
Initialise the CustomView instance in your viewDidLoad method and add it to your viewcontroller's view as a subview.
Adding CustomView with condition 2:
You don't have to do anything in this scenario. Storyboards will initizlize your class for you. You can do additional setup in init(coder) method that will be called when you view is initialized.
Adding CustomView with condition 3:
The proper way to initialise a view with an xib is to initialise it programmatically via UINib's inistantiateWithOwner method. Then add the view as a subview in the viewDidLoad method of your viewcontroller.
What you are doing (or what I can guess seeing your image hierarchy) is that you have changed the class of your UIView to your custom class. Now since you have a separate xib, you are initialising it in init(coder) method and adding it as a subview to the view that was defined in and initialised by the storyboard. Hence you end up with an extra container view.
If you don't want the extra view, add your custom view programmatically.
OR
(If possible) copy the view defined in xib and place it in the viewcontroller dock and then link the view with an outlet and add it in viewDidLoad method.
Here's the answer you've wanted all along. You can just create your CustomView class, have the master instance of it in a xib with all the subviews and outlets. Then you can apply that class to any instances in your storyboards or other xibs.
No need to fiddle with File's Owner, or connect outlets to a proxy or modify the xib in a peculiar way, or add an instance of your custom view as a subview of itself (i.e. no need for self.addSubview(view), which is your question).
Just do this:
Import BFWControls framework
Change your superclass from UIView to NibView (or from UITableViewCell to NibTableViewCell)
That's it!
It even works with IBDesignable to refer your custom view (including the subviews from the xib) at design time in the storyboard.
You can read more about it here:
https://medium.com/build-an-app-like-lego/embed-a-xib-in-a-storyboard-953edf274155
And you can get the open source BFWControls framework here:
https://github.com/BareFeetWare/BFWControls
And here's a simple extract of the NibReplaceable code that drives it, in case you're curious:
https://gist.github.com/barefeettom/f48f6569100415e0ef1fd530ca39f5b4
Tom 👣
Its not necessary that you have to add the xib view as subview. Think about the usage, as per my understanding there are tow scenarios
Suppose you have a view called customXibView class and its xib, now in the xib select the view and and from the right side panel select [identity inspector] option and check, under [custom class] by default its class is UIView. So you can keep it as UIView and set the file owner as customXibView and load it from xib as UIView instance as you are doing now. So, now the question is if you allocate customXibView object manually or in some other xib how it will show your custom components which are in your view xib. So in that case in your customXibView's init method you have to load the UIView xib and add it to customXibViewobject's view.
Another case where you can set the xib's view [custom class] as your class customXibView in this case when you call the below method
func loadViewFromNib() -> customXibView? {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: self.className, bundle: bundle)
return nib.instantiate(withOwner: self, options: nil).first as? customXibView
}
You directly get an object of customXibView with UI loaded no need to add it to any other view. But in this case if you allocate the customXibView class object your UI will not be loaded if you don't do what what you are doing now. If any doubt plz comment.
I have a childViewController on a UICollectionViewController. I have so my childViewController appears on the screen. But when I register a cell collectionView?.register(MyCustomCell.self, forCellWithReuseIdentifier: CellId) and use numberOfItemsInSection and cellForItemAt. The problem is that the cells wont appear, I have checked the code so it´s right. Can it be something with the childViewController?
Generally it's not preferred to add any child view or viewController to UICollectionViewController or UITableViewController as you will see un-expected results as both of them inherits from scrollview and make the added content scroll able or scattered any place, if you have then better create a custom viewController with a collectionView and the childViewController
I have a UICollectionViewCell which I created using a visual XIB file.
The collection view is horizontally displayed.
I'm wanting to add another UICollectionView to this cell in the footer of the cell.
The cell itself is a "card" representing some information;
This diagram helps illustrate what I'm after;
The idea is that I can show/hide the dice imagery as many as needed, including zero; in a horizontal fashion as a child partial inside the current UICollectionCell.
Attempts using Storyboards;
The collection cell XIB won't let me add another UICollectionView to it
If I make a standalone UICollectionView inside the same storyboard, it won't let me add a UICollectionCell to it
The only solution I've got so far is to manually create 5 imageviews, then attach them to a collection outlet; and then I would need to do a for-loop to show/hide each die imagery.
Create normal View Controller with Collection View in the interface builder
Create CollectionViewCell in separate XIB. Inside this cell insert another CollectionView
In first VC register that collectionViewCell as sectionHeader:
tableView.register(UINib(nibName: DashboardPagerHeader.cellIdentifier, bundle: nil), forHeaderFooterViewReuseIdentifier: DashboardPagerHeader.cellIdentifier)
Create another CollectionViewCell in separate xib like before
Inside class of first collection view cell in awakeFromNib register cell created in step 4 like that:
override func awakeFromNib() {
super.awakeFromNib()
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(UINib(nibName: " DashboardHeaderCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: DashboardHeaderCollectionViewCell.cellIdentifier)
}
You don't need tableview for that just in your collectionview cell xib drag another collection and set its scrolling property to vertical,then create xib from inner collectionview.
In outer collectionview cell use that method to set delegate and datasource
// code
override func awakeFromNib() {
super.awakeFromNib()
serInnerCollectionView()
}
func serInnerCollectionView() {
collectionViewInner.delegate = self
collectionViewInner.dataSource = self
collectionViewInner.register(UINib(nibName: " FooterCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "FooterCollectionViewCellIdentifier")
}