UITableViewController as subview swift - ios

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.

Related

Tableview Controller with a dynamic tableview in its static cell

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.

Merging static table view with a UIViewController

I'm currently trying to build a screen that contains 2 UIButton, and 1 UIImageView.
Below these UI Elements, I want to add a static table view that would contain 1 UITextField for each cell in order to create a kind of scrollable form.
The error I'm having is the following one:
Static table views are only valid when embedded in UITableViewController instances
While it doesn't seem possible to create a static table view without a table view controller, I was wondering if there could be any way to get the same result as my initial idea?
Please note that I'm building my UI using storyboard.
Here's a screenshot of what I was trying to build initially:
EDIT: I finally decided to use a static view controller, and implemented the buttons in a cell and the other textfields in different cells. Thank you all for your help.
You can add the UITableViewController as a childViewController to your bigger UIViewController (parentVC)
Then manage parentVC's view hierarchy so that you can achieve the 2 UIButton, 1 UIImageView and a table view at the bottom
In Xcode 10.2 you can use Container View to implement the UI you described. Drag and drop a container view object to the required view controller in your storyboard scene:
Then add UITableViewController instance to your storyboard scene:
Set Static Cells for it's Content:
Then right-click on Content View that you added in one of the previous steps, and setup it as described on the following screenshots:
Setup constrains and cells content. Then you will see something like that on your testing device:
I think you should manage this adding elements in a UIScrollView, there's no need to use a UITableView. So you can scroll all the contents when you show the keyboard
A static tableview is nothing more than a UITableViewController handling the UITableView's UITableViewDataSource methods on your behalf.
You can simply add a UITableView to your UIViewController, set the UITableView datasource to your UIViewController and implement the methods as appropriate.
e.g.
class MyViewController: UIViewController, UITableViewDataSource {
override func viewDidLoad() {
super.viewDidLoad()
tableview.datasource = self
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// create UITableViewCell
}
}

didSelectItemAtIndexPath not called with multiple collection views on same screen

I have 2 collection views on the same screen, and I have the data source and delegate implemented for both in the same view controller. However, the delegate methods such as didSelectItemAtIndexPath is only called for one.
Other info:
Both collection views have a cell with an image.
AllowSelection and UserInteractionEnabled is set to true in both collection views
User interaction enabled on the images
Delegate and data source are set on the storyboard from both collection views to the view controller
Collection views are displayed properly
Both collection views have the same setup, yet only one delegate works. Would you have any clues what could be setting this up?
The collection views are inside a view that has a scroll view. Could this be somehow related?
EDIT 2:
Project with the same problem: https://github.com/iagomr/ProblemWithAutoLayout
EDIT 1:
Somehow this has to do with autolayout constraints, because if I pin the bottom collection view to the bottom of the screen instead of the bottom of other collection view, it starts working.
This is all due to the fact that I need to build a tall screen, and added everything into a view inside a scroll view 1000 points tall.
Code:
//MARK: - CollectionView Delegate
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
println("Called")
}
//MARK: - CollectionView DataSource
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == thisCV {
return 1
} else if collectionView == thisOtherCV{
return 1
}
}
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
if collectionView == "thisCV" {
if let thisCell = collectionView.dequeueReusableCellWithReuseIdentifier("thisCell", forIndexPath: indexPath) as? thisCollectionViewCell {
thisCell.image = image
return thisCell
}
} else if collectionView == "thisOtherCV"{
if let thisOtherCell = collectionView.dequeueReusableCellWithReuseIdentifier("thisOtherCell", forIndexPath: indexPath) as? OtherCollectionViewCell {
thisOtherCell.image = image
return thisOtherCell
}
}
return UICollectionViewCell()
}
I can confirm that didSelectItem is not getting called. If constant for top-bottom constraint between two collection views is changed from 501 to 0 it is working.
This problem is most likely related to the fact that you have two scroll views (collection views) inside of another scroll view. Overall, I would say, that you should modify your UI. I would suggest two ways of fixing it
Using single collection view
Use just one collection view with different sections for different content. Also, do NOT embed it in the scroll view - collection view already has a scroll view so you should be able to scroll easily. You can also dequeue different class of cells for different sections so you should be able to do everything which you want to do now.
If you want a starting point, here is a good tutorial which should help you with that.
Using scroll view
If you want to setup your UI in Interface Builder remove both collection views and simply add all of your UI inside of scroll view. Place UIButton in places where you want clicking to produce action.
You can even assign the same action to each button and then differentiate which one was triggered by assigning custom tags to each of them.

How to make the first row of an UITableView a header of a section?

I have an UITableView with custom cells. I would like that the first row is always visible. As I have only once section, I thought of making a header but in this case I don't really know how to do it?
Is it possible to make a header from the first row with the same gesture recognizers, same dataSource behind the rows, briefly, have the header exactly like th row, just as if the row was pined to the top of the tableView?
You should use a header, or a separate view outside the table view. You can use the same gestures (generally, though not the delete) and data source.
If you want it all, you could use 2 table views- the first with one section and one row, the second with all the other data. It would be easiest if your data source was broken down in a similar way in the view controller.
In either case you can achieve what you want, but not by flicking a switch, you will need to add some logic and different views to make it happen.
If you want to make one static cell that is pinned to the top but in all other ways the same to the others, you could simply add one to your numberOfRowsInSection
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataSource.count + 1
}
Then when you display the cells, check for the row number and always set the first row to contain your static header content.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath.row == 0 {
// Create or set static cell content.
}
}
The other way is to create a custom section header and set it using viewForHeaderInSection
override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if section == 0 {
var view = UIView()
view.backgroundColor = UIColor.blueColor()
return view
}
return nil
}

How to use static cells in UITableView without using Storyboards?

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
}
}

Resources