Swift - Expand tableview without Storyboard segue - ios

I am trying to create a similar tableview like the one below:
https://github.com/justinmfischer/SwiftyExpandingCells
I already have a complete tableview with contents, including a filtering system. The current problem is that I want to implement the same functionality to expand cells and show detailed information, without using storyboard.
The sample code (link) uses a storyboard segue, but I want to get rid of that so that it can basically do the same thing through code. I removed the label for the background. Just want to get the title and a new controller first by clicking a tableview cell.
DetailViewController
class DetailVC: UIViewController {
var brand: Brand?
override func viewDidLoad() {
super.viewDidLoad()
self.setup()
}
func setup() {
self.view.frame.origin.y = UIApplication.sharedApplication().statusBarFrame.size.height
if let brand = self.brand {
self.title = brand.name
}
}
}
This part needs to change
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.selectedCellFrame = tableView.convertRect(tableView.cellForRowAtIndexPath(indexPath)!.frame, toView: tableView.superview)
self.selectedBrand = BrandManager.sharedInstance.brands[indexPath.row]
self.performSegueWithIdentifier(.DetailVC , sender: nil)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
switch segueIdentifierForSegue(segue) {
case .DetailVC:
let vc = segue.destinationViewController as! DetailVC
vc.brand = self.selectedBrand
self.navigationController?.delegate = self
}
}

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.selectedCellFrame = tableView.convertRect(tableView.cellForRowAtIndexPath(indexPath)!.frame, toView: tableView.superview)
self.selectedBrand = BrandManager.sharedInstance.brands[indexPath.row]
let vc = storyboard?.instantiateViewControllerWithIdentifier("DetailVc") as! DetailVC
vc.brand = self.selectedBrand
self.navigationController?.pushViewController(vc, animated: true)
}//// add the storyboardID for the detailsVc as "DetailVc"

Related

viewDidLoad() not running after segue

I'm performing a segue from one table view to another.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
NSLog("You selected cell number: \(indexPath.row)!")
self.performSegue(withIdentifier: "types", sender: productList[indexPath.row])
}
It should run the viewDidLoad() of the new TableView described by the custom class of the ViewController (Which I've declared in Storyboard)
func viewDidLoad(parent: String) {
print("This should print")
super.viewDidLoad()
//self.typeTableView.delegate = self
//self.typeTableView.dataSource = self
//Set reference
ref = Database.database().reference()
//Retrieve posts
handle = ref?.child(parent).observe(.childAdded, with: { (snapshot) in
let product = snapshot.key as? String
if let actualProduct = product
{
self.productList.append(actualProduct)
self.typeTableView.reloadData()
}
})
}
Any Idea why this might be happening?
Embed navigation controller to your destination controller
and make a segue from current table views cell to it with identifier types.
Then add below method after your
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "types" {
if let indexPath = tableView.indexPathForSelectedRow {
let object = productList[indexPath.row] as! yourProductType
let controller = (segue.destination as! UINavigationController).topViewController as! YourDestinationViewController
controller.yourProductProperty = object
}
}
}
Make sure to declare yourProductProperty in your Destination controller so that you can access current product object in it.
viewDidLoad has no parameters and needs an override clause:
override func viewDidLoad() {
...
}
Your method signature is
func viewDidLoad(parent: String) {
but it should be
override func viewDidLoad() {
super.viewDidLoad()
// Your code
}
are you using same class to tableviewcell ? if yes then keep different identifier [RESUE IDENTIFIER] for both tableview.

TableViewCell to ViewController - Swift

I tried many ways but still can't go to another ViewController. This is my storyboard.
and This is my code.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as? HistoryMainTableViewCell {
listItems.sort() { $0.seq > $1.seq }
let history = listItems[indexPath.row]
cell.setValue(history: history)
return cell
} else {
return HistoryMainTableViewCell()
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "vcProductHistory" {
if let productHistoryPage = segue.destination as? HistoryProductViewController {
if let IndexPath = tableViewHistory.indexPathForSelectedRow {
let historyArray = listItems[IndexPath.row]
productHistoryPage.history = historyArray
}
}
}
}
Try this code:(Untested Code)
Note: Below code will trigger prepare segue. When, tableViewCell selected.Let me know the code works...
func tableView(_ tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath) {
// let indexPath = myTableView!.indexPathForSelectedRow
// let currentCell = tableView.cellForRow(at: indexPath)! as UITableViewCell
//sendSelectedData = (currentCell.textLabel?.text)! as String as NSString
performSegue(withIdentifier: "vcProductHistory", sender: self)
}
Based on your answer to my initial comment: dragging the line from initial vc to destination vc tells your vc about the segue, preparing for segue tells your vc what do when the segue is triggered, but you still need to let your vc know when it should perform the segue. try this:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as? HistoryMainTableViewCell else { return HistoryMainTableViewCell() }
let history = listItems[indexPath.row]
cell.setValue(history: history)
return cell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "vcProductHistory" {
guard let productHistoryPage = segue.destination as? HistoryProductViewController, let indexPath = sender as? IndexPath else { return }
let historyArray = listItems[indexPath.row]
productHistoryPage.history = historyArray
}
}
func tableView(_ tableView: UITableView, didSelectRowAtIndexPath indexPath: IndexPath) {
performSegue(withIdentifier: "vcProductHistory", sender: indexPath)
}
I think this is a little bit neater using the guard syntax. Also, it uses sender as the indexPath, not using tableView.indexPathForSelectedRow.
Also, I noticed you have this in your cellForRowAtIndexPath:
listItems.sort() { $0.seq > $1.seq }
Your sorting your data source in cellForRowAtIndexPath. You can't do that there because that function gets called for each row individually. You need to do the sorting before that is called, somewhere like viewWillAppear. Also, to sort an array in place you need to remove the () after sort. try this.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
listItems.sort { $0.0.seq > $0.1.seq }
tableView.reloadData()
}
I think you should connect to UINavigationController , not to HistoryProductionViewController
Because your MainViewController's segue connected to Navigation Controller
I guess in func prepareForSegue segue.identifier == "vcProductHistory" it works but, if let productHistoryPage = segue.destination as? HistoryProductViewController not works
because your destination ViewController's class is NavigationController
you should call
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "vcProductHistory" {
if let naviVC = segue.destination as? UINavigationController {
if let productHistoryPage = naviVC.topViewController as? HistoryProductViewController {
if let IndexPath = tableViewHistory.indexPathForSelectedRow {
let historyArray = listItems[IndexPath.row]
productHistoryPage.history = historyArray
}
}
}
}
}
Your solution - as you described it - should work.
The most work here can be done directly in the Storyboard.
Select the prototype cell in the TableView, drag the Segue to the NavigationController and select presentModally.
This should work without further magic.
When selecting the TableViewCell the NavigationController should be presented. There is also no code needed at this point (except for the population of the TableView).
If not - you maybe misconfigured your TableView by setting the selection to No Selection:
or you set User Interaction Enabled to false somewhere.

How to access override func tableView property from prepareForSegue method inside same class

I have two viewControllers.First one is a tableViewController and second one is a webViewController.I want to pass data from 1st vc to 2nd vc using segue. For this reason i wants the value of "chosenCellIndex" from override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) to prepareForSegue method. But i can not access the chosenCellIndex value from prepareForSegue method. Please help.
class NewsTableViewController: UITableViewController {
#IBOutlet var Alphacell: UITableView!
var chosenCellIndex = 0
//var temp = 0
var newspaper = ["A","B","C"]
override func viewDidLoad() {
super.viewDidLoad()
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return newspaper.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Alphacell", forIndexPath: indexPath) as UITableViewCell
cell.textLabel?.text = newspaper[indexPath.row]
// Alphacell.tag = indexPath.row
//Alphacell.addTarget(self, action: "buttonClicked:",forControlEvents: UIControlEvents.TouchUpInside)
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
chosenCellIndex = indexPath.row
//println(chosenCellIndex)
// Start segue with index of cell clicked
//self.performSegueWithIdentifier("Alphacell", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let secondViewController = segue.destinationViewController as WebViewController
secondViewController.receivedCellIndex = chosenCellIndex
println(chosenCellIndex)
}
}
In order to get chosen cell index you need to get indexpath for selected row, then you need to get section or row index from indexpath.
See the below code for getting row index
let indexPath = tableName.indexPathForSelectedRow
let section = indexPath?.section
let row = indexPath?.row
Make sure you have set the identifier on the segue in storyboard then do:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "someIdentifier"{
let secondViewController = segue.destinationViewController as? WebViewController
//Also, make sure this is the name of the ViewController you are perfoming the segue to.
secondViewController.receivedCellIndex = chosenCellIndex
print(chosenCellIndex)
}
}
Also, what version of Xcode and Swift are you using? println() is now just print().
best way to do that is from did select row function, that example
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let objects = newspaper[indexPath.row]
let vc = storyboard.instantiateViewControllerWithIdentifier("someViewController") as! UIViewController
vc.someString = objects.title
self.presentViewController(vc, animated: true, completion: nil)
}
and prepareForSegue use this code :
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let path = self.tableView.indexPathForSelectedRow()!
segue.destinationViewController.detail = self.detailForIndexPath(path)
}

Swift 2.1 - How to pass index path row of collectionView cell to segue

From the main controller that I have integrated collection view, I want to pass selected cell index path to another view controller (detail view)
so I can use it for updating a specific record.
I have the following working prepareForSegue
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "RecipeDetailVC" {
let detailVC = segue.destinationViewController as? RecipeDetailVC
if let recipeCell = sender as? Recipe {
detailVC!.recipe = recipeCell
}
}
}
And I've tried including let indexPath = collection.indexPathForCell(sender as! UICollectionViewCell) but I get Could not cast value of type 'xxx.Recipe' (0x7fae7580c950) to 'UICollectionViewCell' at runtime.
I also have performSegueWithIdentifier("RecipeDetailVC", sender: recipeCell) and I wonder if I can use this to pass the selected cell's index path but not sure I can add this index to the sender.
I am not clear about the hierarchy of your collectionViewCell. But I think the sender maybe not a cell. Try to use
let indexPath = collection.indexPathForCell(sender.superView as! UICollectionViewCell)
or
let indexPath = collection.indexPathForCell(sender.superView!.superView as! UICollectionViewCell)
That may work.
I've wrote up a quick example to show you, it uses a tableView but the concept is the same:
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var things = [1,2,3,4,5,6,7,8] // These can be anything...
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = UITableViewCell()
let objectForCell = self.things[indexPath.row] // Regular stuff
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let objectAtIndex = self.things[indexPath.row]
let indexOfObject = indexPath.row
self.performSegueWithIdentifier("next", sender: indexOfObject)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "next" {
// On this View Controller make an Index property, like var index
let nextVC = segue.destinationViewController as! UIViewController
nextVC.index = sender as! Int
}
}
}
Here you can see you get the actual object itself and use it as the sender in the perform segue method. You can access it in prepareForSegue and assign it directly to a property on the destination view controller.

Navigation bar for UIWebView

I am new on iOS. Trying to implement a navigation bar for my UIWebView.
My TableView calls the webview when user clicks on any row. I load different local HTML files based on the index user clicked on. My webview is loading correctly but the problem is, I want to keep a navigation bar and < back button there, so that user can click it to come back to the tableview.
Here is the my ProductTableViewController:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "ProductTableViewCell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! ProductTableViewCell
let product = products[indexPath.row]
cell.name.text = product.name
cell.generic.text = product.generic
return cell
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if let resultController = storyboard!.instantiateViewControllerWithIdentifier("webView") as? WebViewController {
presentViewController(resultController, animated: true, completion: nil)
}
//print(indexPath.row)
clickedOn = indexPath.row
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let svc = segue.destinationViewController as! WebViewController;
//if clickedOn == 3{
svc.fileName = "Ace-VetBolus"
//}
}
And my WebViewController:
override func viewDidLoad() {
//print("got: "+self.fileName)
let url = NSBundle.mainBundle().URLForResource(self.fileName, withExtension:"html")
let request = NSURLRequest(URL: url!)
web1.loadRequest(request)
}
Please help me to write Swift code for this.
If you are presenting the WebViewController on ProductTableViewController, and want to have Bar Buttons on Navigation bar, I would suggest you to embed WebViewController in UINavigationController in IB.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let navc = segue.destinationViewController as! UINavigationController;
let svc = navc.topViewController as! WebViewController;
//if clickedOn == 3{
svc.fileName = "Ace-VetBolus"
//}
}
Will be the minor change in prepareForSegue method.
The back button on bar has to be added manually.
replace your didSelectRowAtIndexPath with following one, it works for me.
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if let resultController = storyboard!.instantiateViewControllerWithIdentifier("webView") as? WebViewController {
let navController : UINavigationController = UINavigationController (rootViewController: resultController)
self.navigationController?.presentViewController(navController, animated: true, completion: nil)
}
//print(indexPath.row)
clickedOn = indexPath.row
}

Resources