How to display UINavigationController from didSelectRowtAtIndexPath method of UITableViewDelegate? - ios

How to display UINavigationController when a user taps on a table cell? Code only.
The following code doesn't work:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
guard let vm = (viewModel as? UICatalogVM)?.modelForRowAtIndexPath(indexPath) else {
return
}
let vc = ActivityIndicatorVC(viewModel: vm)
let nc = UINavigationController(rootViewController: self)
nc.pushViewController(vc, animated: true)
}
On the contrary such code works, but it is going to display the VC modally, which is not what I would like to do.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
guard let vm = (viewModel as? UICatalogVM)?.modelForRowAtIndexPath(indexPath) else {
return
}
let vc = ActivityIndicatorVC(viewModel: vm)
self.showViewController(vc, sender: self)
}

If your current view controller is already in a navigation controller then you can directly do it like:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
guard let vm = (viewModel as? UICatalogVM)?.modelForRowAtIndexPath(indexPath) else {
return
}
let vc = ActivityIndicatorVC(viewModel: vm)
navigationController.pushViewController(vc, animated: true)
}
Otherwise you have to add your current view controller in navigation controller before its coming in front.
For example if you are using Storyboard and your current view controller is initial view controller then you have to add a UINavigationController as initial view controller and then set your current view controller as rootViewController for that navigation controller then you can easily push new view controller on didSelectRowAtIndexPath: using
navigationController.pushViewController(vc, animated: true)

Related

ios how to change another view controller's content in different view controller in swift

I am new to swift and ios developer. And I want to create a side menu that the cell event will dynamically change the content in a container view. But it seems not work.
the left is the tableview(my side menu) and the right is the container view with a viewcontroller(vc2) on it
I try two ways to change background color of the container view
the first is
func tableView (_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
let vc2 = storyboard?.instantiateViewController(withIdentifier: "vc2") as? ViewController2
vc2?.view.backgroundColor = UIColor.white
}
and the second way is
func tableView (_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
let vc2 = storyboard?.instantiateViewController(withIdentifier: "vc2") as? ViewController2
vc2?.changecolor()
}
and in vc2
func changecolor()
{
print(123)
self.view.backgroundColor = UIColor.purple
}
it will print 123 but not change bg color
How can I change the content in other view controller ? (If I don't want to remove the current container view and change to another one)
func tableView (_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
let vc2 = storyboard?.instantiateViewController(withIdentifier: "vc2") as? ViewController2
vc2?.setColor(UIColor.purple)
}
class ViewController2: UIViewController {
private(set) var color:UIColor?
override func viewDidLoad() {
guard let color = self.color else { return }
self.view.backgroundColor = color
}
func setColor(_ color:UIColor) {
self.color = color
}
}

Push new view controller programmatically from within didSelectRow method

I'm building a meme generator that employs a tableView and a collectionView for viewing saved memes. When the user taps a cell within the tableView the image should be presented by sliding the view from the previous controller not by presenting modally as a new view, which is the case. Here is my current code
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let meme = memes[indexPath.row]
let detailController = UIStoryboard(name: "DetailsStoryboard", bundle: nil).instantiateViewController(withIdentifier: "DetailsViewController") as! DetailsViewController
present(detailController, animated: true, completion: nil)
detailController.detailsImageView.image = meme.memedImage
}
Everything I am finding is depending on using a segue, which I am not. Can I use a segue within the didSelectRow method? Here is a link to the repo.
You have to use UINavigationController to push the controller.
And second thing you can't set image to DetailsViewController from TableView didSelect method.
Instead you can pass this image to DetailsViewController and set this image in particular controller.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let meme = memes[indexPath.row]
let detailController = UIStoryboard(name: "DetailsStoryboard", bundle: nil).instantiateViewController(withIdentifier: "DetailsViewController") as! DetailsViewController
detailController.memeImage = meme.memedImage //Pass image like this
self.navigationController?.pushViewController(detailController, animated: true)
}
In DetailsViewController do like this
class DetailsViewController: UIViewController {
//Add one memeImage variable
var memeImage: UIImage?
override func viewDidLoad() {
super.viewDidLoad()
detailsImageView.image = memeImage
}
}

Swift - Expand tableview without Storyboard segue

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"

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
}

Pass an array of places from tableview to mapview

Here is my tableview controller. I declared my array of mapSearch in the class to pass.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
let selectedMap = mapSearch[indexPath.row]
let mapviewDestination = MapViewController()
mapviewDestination.mapString = selectedMap
performSegueWithIdentifier("showDetails", sender: tableView)
}
Here is my mapViewController code.
var mapString : String?
The actual search.
var request = MKLocalSearchRequest()
request.naturalLanguageQuery = mapString
request.region = self.placeMap.region
var search:MKLocalSearch = MKLocalSearch.init(request: request)
search.startWithCompletionHandler {
(response:MKLocalSearchResponse!, error:NSError!) in
if !(error != nil) {
var placemarks:NSMutableArray = NSMutableArray()
for item in response.mapItems {
placemarks.addObject((item as MKMapItem).placemark)
}
self.placeMap.removeAnnotations(self.placeMap.annotations)
self.placeMap.showAnnotations(placemarks, animated: true)
} else {
}
}
My problem is that when I run the simulator it doesn't search based on the mapString.
Any ideas are welcome!
EDIT:
I have been trying this and no luck:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.cellForRowAtIndexPath(indexPath)
tableView.deselectRowAtIndexPath(indexPath, animated: true)
let selectedMap = mapSearch[indexPath.row]
performSegueWithIdentifier("showDetails", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "showDetails" {
var mapController = segue.destinationViewController as MapViewController
mapController.mapString = mapSearch
}
}
Are you sure mapviewDestination in your didSelectRowAtIndexPath isn't released and destroyed? You're assigning it a mapString but you're not doing anything with it.
The search is performed on a nil (or empty) string because you never actually set a mapString.
If you need to pass data between two view controllers using segues, you should be using UIViewController's prepareForSegue:sender: (you just re-implement it in your presenting view controller). It gives you a pointer to the presented view controller that you can configure just before it gets on screen.

Resources