I have a form inside a tableview controller. The last 3 parts of the form are address textfield, map and a save button. When the user begins typing on the address field a uitableview will slide up covering the map to display different results. When I set the child tableview mapTableview's delegate and datasource to self this is when the problem would start, the screen just displays a white background. I tried different solutions but they don't work. Also tried this one but the data source must be coming from the tableview controller itself. Dynamic Tableview inside a Static tableview Cell
When I create an array of strings in the class Datasource and put the following codes below in my tableview controller, the strings get displayed in the mapTableView.
var dataSource = DataSource()
mapTableView.delegate = dataSource
maptTableView.delegate = dataSource
But since the data source must be coming from tableview controller, I tried to put the code below, and many other things as suggested in other posts, in my table view controller but the screen won't display anything, just all white. And I get these errors:
UITableView was told to layout its visible cells and other contents without being in the view hierarchy (the table view or one of its superviews has not been added to a window)
Detected a case where constraints ambiguously suggest a height of zero for a table view cell's content view. We're considering the collapse unintentional and using standard height instead
extension EditProfileTableViewController {
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return pois.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellResult", for: indexPath) as! MapTableViewCell
let poi = pois[indexPath.row]
cell.textLabel?.text = poi.title
cell.detailTextLabel?.text = poi.subtitle
cell.detailTextLabel?.numberOfLines = 0
return cell
}
}
and in my viewDidLoad
tableView.estimatedRowHeight = 60.0;
tableView.rowHeight = UITableView.automaticDimension;
How to correctly put a tableview inside a static tableview cell? Please help
You should create another table view controller for the inner table view. Let's call it MapTableViewController.
Add Container View into the static cell in storyboard.
Add Table View Controller into that container view, set its class to MapTableViewController.
Put all datasource/delegate methods for mapTableView from the EditProfileTableViewController into MapTableViewController. After that, EditProfileTableViewController should have no UITableViewDataSource and UITableViewDelegate protocol methods at all.
Related
I have a UITableView that uses a cell that has 3 expandable and collapsable subviews in them. I would prefer to maintain the state of these views in my UITableViewCell class itself (states as in collapsed or expanded)
Since they are reusable cells, currently, if I expand view 1 in cell A, and then scroll down to cell B, it's view 1 will be expanded. I don't want this. I want it collapsed. But, if I scroll back up to cell A, I want it to still be expanded.
Other than storing all of these states in an array or dictionary
var expandedViewOneCells: [Int] = []
var expandedViewTwoCells: [Int] = []
etc.
I would prefer to have the cells essentially of act individually and maintain their own state... But how would I do this when cells are reused? Keep in mind, I will always only have at most 3 of these kinds of cells, so can I set something like only reuse after 3 cells.
Would it be wise to keep an array of the cells I load, and then on cellForRowAt load the cell from that array based on the index and return it?
In your func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell function try not to deque a cell but create a new instance of your cell
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = MyCustomCell()
return cell
}
If you are loading your cell from a xib file you need a way to create your custom cell from that nib. Add the following method to your CustomCell class
static func loadFromNib() -> RequestTableViewCell {
let nib = UINib(nibName: "\(MyCustomCell.self)", bundle: Bundle.main)
let cell = nib.instantiate(withOwner: self, options: nil)[0] as! MyCustomCell
return cell
}
Then in your func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell this will create a new cell for every row and not reuse a cell when scrolling
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = MyCustomCell.loadFromNib()
return cell
}
A solution like this may not be optimal if your table view has a lot of rows but for a SMALL amount of rows this should be okay
I see 2 solutions to your problem:
Use 3 View Controllers. They should never get destroyed, and add / remove the corresponding VC's view on top of the .contentView of the cell as it appears or goes off-screen. See the solution here http://khanlou.com/2015/04/view-controllers-in-cells/ The Custom Cell itself is just a view, shouldn't really be concerned with the state, but if we move that logic to a View Controller - we should be fine, an we are not violating MVC. Plus, the View Controller can keep track of the height of the view, based on the state, and heightForRow(at:) can ask it for that
I'd use a Stack View as this is a perfect scenario for it. I'd probably represent the Cell itself as another stack view. Not sure exactly what the views look like and how they change, but it may end up as simple as hiding / unhiding the second view from the Stack View that represent a "cell".
I am working on an app where I'm stuck in a limbo between collection view cells and the contained table views within them.
My first collection view cell contains a table view with table view cells.
Each table view cell contain saved data and by selecting one cell two things should happen.
The collection view cell should change index to current +1
The table view cells data (in this case title and date) should be passed onto the new collection view cells header property.
One other aspect is that the table views are stored in a container view class. I'm not sure if this matter or not, but its one extra layer to pass the variables through.
So far this is where I get stuck
tableViewDidselectCode
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let header = LoadHeaderView()
let cell = tableView.dequeueReusableCell(forIndexPath: indexPath) as SavedTableViewCell
header.titleString = cell.taskLabel.text!
header.descriptionString = cell.clientLabel.text!
}
How do I pass this to
self -> ContainerView -> collectionCell[0] -> CollectionView -> collectionCell[1] -> tableView -> header?
Your table view has a dependency on the parent collection view cell. That means you need to pass a reference of the collection view cell to the table view on instantiation. I'd make a protocol.
protocol myTableViewCellDelegate {
func updateMyCollectionViewCell
}
extension myCollectionViewCell: myTableViewCellDelegate {
func updateMyCollectionViewCell {
// update whatever you need to here
}
}
extension myCollectionTableViewDelegate: UITableViewDelegate {
// ...
func collectionView(_ collectionView: UICollectionView,
willDisplay cell: UICollectionViewCell,
forItemAt indexPath: IndexPath) {
// instantiate table view
// pass self to tableview *as weak reference*
myTableView.customDelegate = self
}
//...
}
extension myTableViewDelegate: UITableViewDelegate {
//...
func tableView(_ tableView: UITableView,
didSelectRowAt indexPath: IndexPath) {
// instantiate table view cell
// assuming you're not using custom cell class
tableCell.updateMyCollectionViewCell()
// if you are using custom cell class then the tableViewDelegate
// will need to pass collectionView reference on to the cells
}
}
Hope that helps!
I think you can use a blocks to send information and any other actions.
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/WorkingwithBlocks/WorkingwithBlocks.html
I'm trying to make my first app and I'm stuck at this point.
My app looks like snapchat, a horizontal scrollview and the left part is composed of a tableview.
So, in this left part I put as a subview a tableViewController. The problem is the cells are always empty ! The table view is showing with the right cell's height but cells are empty.
I'm sure you can help me, thank you !
I make the subview here
Link with cells here
Please be ensure that override necessary methods in table view controller and balance calls in adding child view controller code rutin.One more last thing when adding child view controller you should provide correct size to controller view.
for adding table view controller as a child view controller
guard let list = R.storyboard.dashboard.addressesController()else {
return
}
self.list = list
self.addChildViewController(list)
self.scroll.addSubview(list.view)
list.didMoveToParentViewController(self)
list.tableView.layoutIfNeeded()
list.view.snp_makeConstraints(closure: {
(make) in
make.left.equalTo(self.view).offset(10)
make.right.equalTo(self.view).offset(-10)
make.bottom.equalTo(self.scroll)
make.height.equalTo(list.tableView.contentSize.height)
make.top.equalTo(authorizedTop.snp_bottom).offset(10)
})
for extending table view controller
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableData.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier(self.cellIdentifier) as UITableViewCell
cell.textLabel?.text = self.tableData[indexPath.row]
return cell
}
I know this isn't an answer to you question, but I have a suggestion which might help you in the long run, and maybe help you debug your current problem:
How about splitting the tableViews' logic into separate UITableViewControllers? That way you avoid some gigantic common UIViewController. You can use the Container View in your storyboard, which can embed a UIViewController.
This is my first time using TableView's and I've already hit a road block.
I've got a View Controller with a Container inside. The Container View has an embedded Table View Controller. I have populated the table view controller using the below code. I have set the datasource and the delegate to the Table View Controller, set the Custom Class of the Table View controller to ORMTableVC and set the Table View cell Identifier to cellIdentifier.
My problem is at runtime the View Controller is just blank and I cannot see any Table lines or data.
Any help will be greatly appreciated.
import Foundation
import UIKit
class ORMTableVC : UITableViewController {
let cellIdentifier = "cellIdentifier"
var Array = [String]()
override func viewDidLoad() {
super.viewDidLoad()
Array = ["Reps", "Weight", "RPE", "Fatigue", "Potential Max", "Fatigue Weight"]
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return Array.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let Cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath)
Cell.textLabel?.text = Array[indexPath.row]
return Cell
}
}
StoryBoard Setup
Built App
After looking through many tutorials managed to fix this. Seemed like the code wasn't the issue it was the storyboard setup.
On the Table View Cell the identifier needed to be cellIdentifier not Cell.
I have an existing ViewController + xib in my project, and now I want to add a UITableView with static cells, like this:
But when I drag a UITableView onto my screen I don't have the "Content > Static" menu in the Attributes Inspector.
I've tried making my controller subclass UITableViewController, but that doesn't help -- I still don't get the option to use static cells in Attributes Inspector.
I've looked around on StackOverflow but haven't found any existing answers to this question. All the existing questions relate to Storyboards (which I'm not using) instead of xib files.
My guess is that Xcode does some kind of magic when you add a UITableViewController to a storyboard, but not when you change an existing xib to inherit from UITableViewController.
Any advice how how to add a table view with static cells to an existing xib?
Static table view cells are only available when using storyboards. However, if you aren't using storyboards for your entire UI you can still use them for individual screens instead of a collection of screens.
To do this you can create a UIStoryboard file with a single view controller on it that has it's File's Owner set to your custom view controller subclass. Set the VC's identifier to some value. When you want to display this, get the storyboard and then instantiate your view controller subclass by creating the VC from your storyboard.
UIStoryboard *tableViewStoryboard = [UIStoryboard storyboardWithName:#"your storyboard" bundle:nil];
CustomViewController = [tableViewStoryboard instantiateViewControllerWithIdentifier:#"custom identifier"];
You can present this VC as usual in your app.
This is a great way to start using storyboards without having to convert your entire app to use them.
This is doable without storyboards:
your controller must adopt protocols for tableview delegate and
source...UITableViewDelegate, UITableViewDataSource
Add a table view to your .xib; set the table view's style to "grouped"
Connect the table to a property in your controller (let's call it "yourTableView")
Add table view cells to the .xib as separate views...i.e. not as subviews of the table view...they'll be free floating in the .xib. (see example image below)
Add controls / labels etc to the table cells.
Assign unique strings to the "Identifier" field in Attributes for each table view cell.
Connect the table cells to other properties in the controller (sliderCell, switchCell, etc)
Connect the send events for the cells' controls to IBAction-ed methods in the controller
- (IBAction) handleSliderCell, etc.
In the viewDidLoad method of your controller, assign the delegate and source of the table view to the controller (self.yourTableControl.delegate = self; self.yourTableControl.dataSource = self;)
implement numberOfSectionsInTableView, numberOfRowsInSection, and cellForRowAtIndexPath in the controller
in tableView:cellForRowAtIndexPath:, return yourFirstCell, yourSecondCell, etc pointers for appropriate indexPath values
Events for controls for the table cells should go to your handler routines...
Example for step 4:
To expand on BVB's answer, when it comes to number 10, here are the Swift 3 snippets for your tableview delegate methods. Be sure to add outlets to all your cells in the xib.
When you manually create your table view sections, remember that indexPath is equal to a 2 dimensional array representing your table structure. for example, when indexPath is passed to tableView(cellForRowAt indexPath: IndexPath) is equal to [1][0], your cell will be placed in the first position of the second section.
Values can be pulled out of indexPath with the properties indexPath.row and indexPath.section. Using these values, you can manually construct your sections from your IBOutlets in whichever order you prefer.
#IBOutlet var is_enabled: UITableViewCell!
#IBOutlet var is_public: UITableViewCell!
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
switch(section){
case 0:
return "Cell 1"
case 1:
return "Cell 2"
default: return ""
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
print("index path here", indexPath)
if(indexPath.section == 0) {
return is_enabled
}
else if(indexPath.section == 1) {
return is_public
} else {
return is_enabled
}
}