How to use two tableview in one view? - macos

I have two table view in one view container. I insert each of them to the container.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: false)
self.storyboard?.instantiateViewController(withIdentifier: "ChildTableView") as! ChildTableViewController
childTV.updateTable(id: indexPath.row)
}
I need to update second tableview when first tableview cell clicked.
How i can do this?

Okay, I think I see the problem. The way you've done this is with two UITableViewControllers and their table views. So now you have a problem communicating between the two table view controllers. But consider this: if you've truly created child view controllers, the table view controllers are children of the same parent. So the first table view controller can get its parent view controller, then get the parent's child view controllers, then get the second child view controller, and that must be the second table view controller.
In other words, if your view controller hierarchy is:
ParentViewController
TableViewController1
TableViewController2
... then TableViewController1 can say:
let tvc2 = self.parent!.childViewControllers[1] as! TableViewController2
... and now you have established a line of communication between them. So now table view controller 1 can talk to table view controller 2 and tell it to update its table. You will need to have a method in table view controller 2 that table view controller 1 can call, in order to hand it any needed data and tell it what to do.

in Second TableView:
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(ChildTableViewController.updateTable(sender:)), name: NSNotification.Name(rawValue: "updateChild"), object: nil)
}
func updateTable(sender:NSNotification){
tableView.reloadData()
}
in First TableView:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: false)
selectedItem["id"]=indexPath.row
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "updateChild"),object:selectedItem)
}

Related

How to get the right row in a #IBsegueAction function?

I can segue from an embedded UIKit tableview to a SwiftUI view, with the necessary data. I select the indexPath.row with a tableView(_didSelectRowAt).
However, the #IBSegueAction takes place before the didSelectRowAt. This makes the detailView lag one selected row: it shows the previously selected row.
I tried to put the didSelectRowAt first, tried to embed them: no chance
I saw in a WWDC video that it should be possible lo select the right row, but can't figure out the right syntax from this short segment (about minute 6:00)
https://developer.apple.com/videos/play/wwdc2019/231/
#IBSegueAction func MeasurementDetail(_ coder: NSCoder) -> UIViewController? {
return UIHostingController(coder: coder, rootView: PointDetailSwiftUIView(pointDetail: measurements[selectedMeasurementRow]))
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedMeasurementRow = indexPath.row
}
How do I solve the problem?
In that WWDC session, Tanu doesn't care when UIKit calls tableView(_:didSelectRowAt:). Instead, her #IBSegueAction asks the table view for the selected row, by using tableView.indexPathForSelectedRow.
Make sure you have a tableView outlet connected to your table view. You already have a tableView outlet if your view controller is a subclass of UITableViewController. Then use tableView.indexPathForSelectedRow:
#IBSegueAction func MeasurementDetail(_ coder: NSCoder) -> UIViewController? {
guard let row = tableView.indexPathForSelectedRow?.row else { return nil }
let detailView = PointDetailSwiftUIView(pointDetail: measurements[row])
return UIHostingController(coder: coder, rootView: detailView)
}

Merge cells of NSTableView

Is there any way to merge cell's in a NSTableView?
I know there are two modes for displaying data in a NSTableView: cell-based and view-based. If the data are presented by cells, the function
tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int)
is responsable, otherwise
tableView(_ tableView: NSTableView, rowViewForRow row: Int)
Currently I'm using the first one. In iOS, you can use the cell prototype in interface builder to link the views with a custom UITableViewCell, but how can I achieve this for a complete row in a NSTableView?
Maybe I found a solution: You can use both
tableView(_:viewFor:row:)
and
tableView(:viewFor:tableColumn:row:)
but you have to be aware that the tableView is not using both methods for one cell (mutually exclusive).
Now you can define a xib, with a single UIView in it. Change the class of the UIView to NSTableRowView. Next, load the class in viewDidLoad into your table:
if let nib: NSNib = NSNib(nibNamed: NSNib.Name("SpecialRow"), bundle: nil) {
self.tableView?.register(nib, forIdentifier: NSUserInterfaceItemIdentifier("specialRow"));
}
In your table method rowViewForRow you can do the following:
if let srow: SpecialRow = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "specialRow"), owner: nil) as? SpecialRow {
// ...
return srow;
}

How to Pass Collection View Data to a New View Controller

I am going try be as specific as possible.
What I am trying to achieve is to have one view controller which has a collection view in it and when the user clicks on of the collection view cells, it then sends the user to another view controller which has another collection view however the items displayed in the second collection view will change depending on which collection view cell the user previously tapped. I am also using CoreData to do this. With CoreData, the task is an entity and has attributes like name etc. Will I have to change this or have a relationship between the 2 collection views?
The reason for me wanting to do this is because I am creating a productivity app for iOS and the first view controller with a collection view will be where the user can create projects, within these projects which will be displayed in a collection view, the user can then tap on one of the cells and go to the next view controller and begin to create tasks specific to that project.
How can I keep the tasks stored in a specific collection view cell and have the user create different tasks in other projects. It is sort of like Wunderlist. If anybody is confused at what I am trying to do, I can ellaborate more.
This is one of my view controllers where the data from the 'create item view controller' gets sent to via CoreData and displays it in a collection view, hope it helps:
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
#IBOutlet weak var myCollView: UICollectionView!
#IBAction func addCore(_ sender: UIButton) {
}
var tasks : [Task] = []
override func viewDidLoad() {
super.viewDidLoad()
self.myCollView.delegate = self
self.myCollView.dataSource = self
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
getData()
myCollView.reloadData()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return tasks.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "connectCell", for: indexPath) as! MyCollectionViewCell
let task = tasks[indexPath.row]
cell.labelTe?.text = task.name!
self.myCollView.backgroundColor = UIColor.clear
cell.layer.cornerRadius = 25
return cell
}
func getData() {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
do {
tasks = try context.fetch(Task.fetchRequest())
}
catch {
print("Ahhhhhhhh")
}
}
If I am guessing right, and upon clicking a cell on the first collection view, you want to segue to another collection view, where you will display display data according to the selected cell.
In order to achieve this, simply add collectionView(_ collectionView:, didSelectItemAt indexPath:) and prepare(for segue:, sender:) functions in your first view controller.
In the collectionView(_ collectionView:, didSelectItemAt indexPath:) function get the id of the task selected by determine which cell was selected, then pass this id to the second view controller in prepare(for segue:, sender:) function.
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath) as! MyCollectionViewCell
id = cell.labelTe?.text
}
or
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
id = tasks[indexPath.row].id
}
Then pass this value in your prepare(for segue:, sender:) function to the second viewController.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "YourIdentifier"{
let destinationViewController = segue.destination as! SecondViewController
destinationViewController.id = id
}
}
Make sure to add a var id in both your viewControllers. In the second viewController, use this id to fetch the data of the selected task that you want to display.
Hope this helps.
EDIT
Simply declare a new variable id of your particular type in both the viewControllers. In your first viewController :
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
var id = ""
and in the second viewController
class secondViewController: UIViewController {
var id = ""
Just make sure that both the variable are of same type.

Is it possible to create one tableViewCell that can be used in multiple Table Controllers?

I have about 3 or 4 table controllers that will all use the same tableview cell. I keep going back on fourth of the possible logic. Can I use the same tableViewCell in multiple tableView Controllers assuming the information is between the two is the same? Or will I have to create a new cell for each controller?
Yes you can.
I am assuming that you are using Swift.
Goto File -> New and select cocoaTouch class as follows.
Now name Your class for custom cell and make it subClass of UITableViewCell. also check the box which says "Also create Xib file"
Now design your cell in this Xib and create outlets in its .Swift file. Lets say you have a custom tableView cell which looks something like this
Which contains a label or ImageView or anyThing that you have in your cell. Now in your swift file of custom cell you can write a method like so
class func cellForTableView(tableView: UITableView, atIndexPath indexPath: NSIndexPath) -> YourCustomTableViewCell {
let kYourCustomTableViewCellIdentifier = "kYourCustomTableViewCellIdentifier"
tableView.registerNib(UINib(nibName: "YourCustomTableViewCell", bundle: NSBundle.mainBundle()), forCellReuseIdentifier: kYourCustomTableViewCellIdentifier)
let cell = tableView.dequeueReusableCellWithIdentifier(kYourCustomTableViewCellIdentifier, forIndexPath: indexPath) as! YourCustomTableViewCell
return cell
}
Now you can use this cell in any tableView in your application just like below
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = YourCustomTableViewCell.cellForTableView(tableView, atIndexPath: indexPath)
cell.backgroundColor = UIColor.clearColor()
// do something with your cell
}
I hope it helps.
Update for Swift 3 and Swift 4:
class func cellForTableView(tableView: UITableView, atIndexPath indexPath: IndexPath) -> YourCustomTableViewCell {
let kYourCustomTableViewCellIdentifier = "kYourCustomTableViewCellIdentifier"
tableView.register(UINib(nibName: "YourCustomTableViewCell", bundle: Bundle.main), forCellReuseIdentifier: kYourCustomTableViewCellIdentifier)
let cell = tableView.dequeueReusableCell(withIdentifier: kYourCustomTableViewCellIdentifier, for: indexPath) as! YourCustomTableViewCell
return cell
}
Yes you can use the table view cell in multiple tableView Controllers .

didSelectRowAtIndexPath and performSegueWithIdentifier

I have a tableView that display a list of cells. I need to catch the selected cell, and pass my object data based on indexPath.row to display it on my Second View Controller. My didSelectRowAtIndexPath is working fine, but probably I'm not familiar with the syntax for performSegueWithIdentifier, where it fails to call the method.
Sorry I'm new to Swift programming, would appreciate if you could explain more details.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath){
selectedCell = indexPath.row
performSegueWithIdentifier("DetailScreen", sender: self)
}
override func performSegueWithIdentifier(identifier: String, sender: AnyObject?) {
detailedView.personName = personList[selectedCell].GetPersonName()
}
Solution 1
First, make sure you have segue between your first and second view controllers (From the table view controller one to the Detail view screen). Make sure that the segue has a name
Now in your first view controller's didSelectRowAtIndexPath event, Invoke the segue like this.
performSegueWithIdentifier("DetailScreen", sender: nil)
Now in the prepareForSegue method of the first view controller, you can customize it to send more details.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
if(segue.identifier=="DetailScreen")
{
let ctrl = segue.destinationViewController as! YourDetailsViewController
ctrl.personName = "Set some person name here"
}
}
Assuming Your Detail screen's class is called YourDetailsViewController and it has a property called personName of String type. You may update the code to use your real view controller.
Solution 2
If you do not want to create the segue, you can programmatically navigate( actually pushing the second view controller to the front) to the second view. In your first view controllers, didSelectIndexPathAtRow method,
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath){
let ctrl = self.storyboard?.instantiateViewControllerWithIdentifier("DetailsCtrl")
as? YourDetailsViewController
ctrl?.personName="Set some name here"
self.navigationController?.pushViewController(ctrl!, animated: true)
}
For the above code to work, you need to make sure that you have StoryBoardID set to "DetailsCtrl" on the second view controller(Details view)
You have set the storyboard segue as given below:
Click on the segue and add the identifier
You can achieve the above requirement using the following code and this worked for me:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath){
let storyboard1 = UIStoryboard(name: "Main", bundle: nil)
let detail = storyboard1.instantiateViewControllerWithIdentifier("DetailScreen") as! SecondViewController
detail.personName = personList[selectedCell].GetPersonName()
self.navigationController?.pushViewController(detail, animated: true)
}
The storyboard segue from your first view controller to second view controller should be "Push".
Hope this might be helpful.

Resources