I have a UICollectionView with horizontal scrolling direction.
It has a button. On that button click i want to show a list tableView. My question is where should i implement table view delegate method,
in BasicVC, where i create collectionView,
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let c = collectionView.dequeueReusableCell(withReuseIdentifier:"cell", for: indexPath)
let btn = c.viewWithTag(9) as? UIButton
btn?.layer.masksToBounds = true
btn?.layer.cornerRadius = (btn?.frame.size.height)!/2
btn?.backgroundColor = getRandomColor()
return c
}
or in collectionCell class.
class PlayerHeaderCell: UICollectionViewCell{
#IBOutlet weak var btn: UIButton!}
tableView delegate methods needs to implemented in UICollectionViewCell like so
class PlayerHeaderCell: UICollectionViewCell, UITableViewDataSource, UITableViewDelegate{
#IBOutlet weak var btn: UIButton!
#IBOutlet weak var tableView: UITableView!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")!
return cell
}
}
It sounds like you want a table view to popup on top of the collection view like a drop down menu right? If you're wanting to have a table view that is displayed over top your current view, I'd recommend creating a new view controller for it in your story board that contains the table view, and then presenting that controller on top of the current view. The result would be a table view floating wherever you want on top of your collection view.
Unlike what the other answer said, do NOT make the collection cell the table view delegate, it just doesn't make sense unless you want a different table view for every cell, in which case you should do this and set the delegate to be the selected collection cell.
To implement the popup table view:
Create a view controller in storyboard
Create a new table view, place it INSIDE the new view controllers default view (the default view is used as the background but will be invisible.)
Set view controller's presentation to be Over Content
Set the new view controllers background view to be completely transparent by changing its color
Ctrl drag from your previous view controller to your new view controller and create a modal segue, give it some identifier string "id".
Call performSegue with the ID you set will cause the table view to appear as it is in the new view controller you created.
The advantage to this approach is that your table view can be designed in it's view controller and wont clutter up the original view controller in a storyboard. Just my thoughts, you seem to be doing things programatically so I'm not sure if it's suitable to your use case but I hope it helps.
It depends on where you are showing the tableview. I mean when you tap button, if you are navigating to a new controller with tableview, the delegate should be in the new controller. Or if you are showing the tableview in the same controller, the delegates will be in BasicVC. I think the collection cell has only the button.
This is my understanding. Someone please correct if I am wrong.
Related
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.
I have a view controller with a tableview inside it , in the table view i implemented a collection view with horizontal scrolling, the data appears correctly but i want to go to another view controller when i click on the collection view cell passing a string to that view , how can i handle this process .
thanks in advance
You have two choice
1) Implement Collection view delegate & datasource inside view controller. You can do this in tableview's cellForRowAt method like cell.collectionview.datasource = self
2) You can create delegate / closure to pass data from Collection View -> TableView Cell --> UIViewController
Hope it is helpful And let me know if you need example
EXAMPLE
As you have finding difficulties to understand theoretically here is example
suppose in your view controller
You have tableview datasource like below
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier:"identifer", for: indexPath) as! YourTableViewCell
// You have collection view inside tableview cell so
cell.yourCollectionViewObject.dataSource = self
cell.yourCollectionViewObject.delegate = self
return cell
}
Implement or Move the datasource & Delegate in Your view Controller and push or present view controller you want to
I've created a view controller that has a table view embedded in it and in each section of the table I have a cell containing a horizontal collection view. This is what it looks like. The collection view delegate is hooked up to the table view cell and the table view delegate is hooked up to the main view controller.
I want to segue on a cell tap to a new view controller using the navigation controller's push method and pass data from the collection view cell to the new view controller. However, I can't call that navigation controller's push method from inside my collection view's didSelectItem function as that is nested inside my table view cell and not the actual view controller. Some help would be appreciated, thank you!
This is the main view controller's cellForItem function
class SearchController: UIViewController, UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ExploreRow", for: indexPath) as! ExploreRow
let category = classTypes[indexPath.section]
cell.configureCell(type: category)
return cell
}
}
and this is the code within the table view cell's didSelectItem for the collection view cell
class ExploreRow: UITableViewCell, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("Selected \(indexPath.row)")
}
}
The print function works fine but I can't call the navigation controller to push the new view controller from inside that table view.
Implement a delegate protocol or call-back closure from your table view cell to the table view controller. Then you have:
CollectionViewCell tapped
TableViewCell is CollectionView's delegate - it processes the tap
In didSelectItem, TableViewCell tells TableViewController which CollectionViewCell was tapped
TableViewController handles it from there
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 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
}
}