Using flyout navigation on monotouch by James Clancey. Can't get a subview controller to elegantly perform a segue on the main containing controller?
NavigationRoot = new RootElement ("Navigation") {
new Section ("Menu") {
new StringElement ("Mapview Controller"),
new StringElement ("Another View Controller"),
}
},
ViewControllers = new [] {
// mapview is a view inside this viewcontroller and able to perform segues
new UIViewController { View = mapView },
// this is a seperate viewcontroller but is embedded inside the flyoutNavigation
// AnotherViewController cant seem to call the root navigation controller (<-- actually a uiNav inside a tab bar nav) so i can perform a segue movement just like the above mapViewController??
this.Storyboard.InstantiateViewController("AnotherViewController") as AnotherViewController,
},
// sub viewcontroller i.e. AnotherViewController trying to move mainViewController to perform a segue..
// throws error: Receiver (<FlyoutNavigation.FlyoutNavigationController: 0x14360600>) has no segue with identifier 'segueTest'
this.ParentViewController.PerformSegue("segueTest", this);
* Update:
I gave up on segue. Instead of using additional view controllers, I'm relying on views but one of my views is a static-celled tableview and not sure how to add it to above code liek so:
ViewControllers = new [] {
new UIViewController { View = mapView },
new UIViewController { View = myTableView } // doesnt work - tried with 'new UITableViewController' which also fails
What do I do?
You can use navigation for that..
ViewControllers = new [] {
new UINavigationController (this.Storyboard.InstantiateViewController("profileViewController") as ProfileViewController),
}
Related
We have a sequence of screens that navigate in order...
BaseViewController -> A -> B -> BaseViewController
Each screen uses NavigationController.PushViewController to go from...Base->A, A->B. So each subsequent screen is placed in the navigation stack.
So if you are on A and you click 'back', then it goes back one screen. This works well as it is controlled by the NavigationController.
However, when you are on screen B, 'back' should to back to the BaseViewController.
Instead it goes (as designed by Apple) back to A. Is there a way to intercept the 'back' button on B so we can instead use NavigationController.PopToViewController to send the user back to BaseViewController?
As #the4kman mentioned , we can create a custom button to replace the LeftBarButtonItem ,and handle the back event .
ViewDidLoad in B
this.NavigationItem.LeftBarButtonItem =
new UIBarButtonItem("back", UIBarButtonItemStyle.Plain, (sender,e) => {
UIViewController baseVC = NavigationController.ViewControllers[NavigationController.ViewControllers.Length - 3];
NavigationController.PopToViewController(baseVC, true);
});
As #J.C. Chaparro mentioned , remove A from stack .
ViewDidLoad in B
List<UIViewController> list = NavigationController.ViewControllers.ToList<UIViewController>();
list.RemoveAt(list.Count-2);
NavigationController.ViewControllers = list.ToArray();
You can do something like this in B's viewDidAppear function:
guard let navigationController = self.navigationController else {
return
}
navigationController.viewControllers.remove(at: navigationController.viewControllers.count - 2)
This will remove A from the stack, and allow you to go back to BaseViewController from B.
If I understand correctly you want to pop to root view controller from a certain top view controller. One way to do it would be to create a subclass of UINavigationController and override popViewController method where you would check what you have on top at the moment and decide to pop to root or not. Here's an example:
open class CustomNavigationController: UINavigationController {
override open func popViewController(animated: Bool) -> UIViewController? {
if topViewController is BViewController {
return popToRootViewController(animated: animated)?.last
} else {
return super.popViewController(animated: animated)
}
}
}
Approach:
Use child view controllers
Steps:
Create a view controller C which is a subclass of Base
Add A as a child view controller to C
Create a view controller D which is a subclass of Base
Add B as a child view controller to D
Push C to D
Thanks for all the answers. #Cole Xia put me on the right path for our scenario. His technique works, and the following works as well.
Here is the Xamarin code. The technique is to replace the current list of ViewControllers with a new one. Then when 'back' is hit on B, it goes right back to BaseViewController.
var viewControllers = new UIViewController[] { NavigationController.ViewControllers[0], new B() };
NavigationController.SetViewControllers(viewControllers, false);
Is it possible such that I can have a navigation controller in each of my tabs of a TabBarController while using Xamarin iOS? I've currently setup my storyboard like so (for simplicity, I'm using a single tab)
TabBarController -> NavigationController -> UITableViewController
In my UITableViewController, the following code in my ViewDidLoad method does not change the title nor add the desired button to the top navigation. Have I set up something wrong?
public override void ViewDidLoad()
{
base.ViewDidLoad();
Console.WriteLine("view did load");
Title = "My custom title";
NavigationItem.SetRightBarButtonItem(
new UIBarButtonItem(UIBarButtonSystemItem.Add, (sender, args) =>
{
PerformSegue("CreateRecordSegue", this);
})
, true);
}
Image of storyboard is here: https://ibb.co/m7qq85
The solution is to:
1) Remove the navigation controller that leads into the tab bar controller
2) Create a segue from the home page into the tab bar controller, making the segue type to replace (instead of push)
when I'm moving from one story board to another storyboard via click on signIn button, this.NavigationController is showing null. so I'm not able to PushViewController.
I've one stoaryboard with two views and that two views have separate UIViewControllers.
You must explicitly create a UINavigationController and place your initial view controller inside of it. Doing this will automatically set the NavigationController property of any view controller contained within that Navigation controller.
// create the view controller for your initial view - using storyboard, code, etc
var first = new UIViewController(...);
// wrap your VC inside a Nav controller
var nav = new UINavigationController(first);
Just to add to Jason's answer. By default the RootViewcontroller is the initial view controller.
What I did was to override the that initial view controller with the a navigation view controller:
[Register("AppDelegate")]
public class AppDelegate : UIApplicationDelegate
{
public override UIWindow Window
{
get;
set;
}
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
Window.RootViewController = new UINavigationController(Window.RootViewController);
return true;
}
This is the line I added:
Window.RootViewController = new UINavigationController(Window.RootViewController);
Window.RootViewController: is the ViewController, e.g MainViewController
and I'm overriding this initial controller, that's set by default, with the navigation controller.
This worked perfectly for me.
I'm new to Xamarin IOS and I have a project which needs this flyout navigation.
var navigation = new FlyoutNavigationController {
// Create the navigation menu
NavigationRoot = new RootElement ("Navigation") {
new Section ("Menu") {
new StringElement ("Recipe"),
new StringElement ("Recipe Basket"),
new StringElement ("Meal Planner"),
new StringElement ("Grocery List"),
new StringElement ("Social"),
new StringElement ("Videos"),
new StringElement ("News Feed"),
new StringElement ("Partners"),
}
},
// Supply view controllers corresponding to menu items:
ViewControllers = new [] {
new UIViewController { View = new UILabel { Text = "Animals (drag right)" } },
new UIViewController { View = new UILabel { Text = "Vegetables (drag right)" } },
new UIViewController { View = new UILabel { Text = "Minerals (drag right)" } },
},
};
This code just presents the UILabel. How can I do this to send it to a specific view controller?
Please help.
Thanks in advance.
Do what vinaykumar said, but you also want to open the FlyoutNavigationController from those UIViewControllers, so you have to pass that initial one you created to those controllers.
Otherwise if you just open your view controller, you won't be able to get the menu again.
I'm opening navigation controllers like so:
MainViewController in ViewDidLoad:
UIStoryboard board = UIStoryboard.FromName("MainStoryboard_iPhone", null);
UINavigationController nav = (UINavigationController)board.InstantiateViewController("nav");
SearchViewController searchVC = (SearchViewController)nav.ViewControllers[0];
// Passing flyoutnavigation here
searchVC.navigation = navigation;
SettingsViewController settingsVC = (SettingsViewController)board.InstantiateViewController("settings");
UINavigationController navSettings = new UINavigationController(settingsVC);
// Passing flyoutnavigation here
settingsVC.navigation = navigation;
navigation.ViewControllers = new[]
{
nav,
navSettings
};
In the other view controllers, (Settings and Search in my example), I have a public variable to store the FlyoutNavigationController (set in MainViewController) then add a button to open the FlyoutNavigationController that was passed:
// Set in MainViewController
public FlyoutNavigationController navigation;
public override void ViewDidLoad()
{
base.ViewDidLoad();
// Add button to allow opening the FlyoutNavigationController
NavigationItem.LeftBarButtonItem = new UIBarButtonItem(UIBarButtonSystemItem.Action, delegate
{
navigation.ToggleMenu();
});
}
you have to add the FlyoutNavigationController's View to your View
// Show the navigation view
navigation.ToggleMenu ();
View.AddSubview (navigation.View);
This code just presents the UILabel.
because you are only providing UILable as a view to your new UIViewController.
View = new UILabel { Text = "Animals (drag right)" }
How can I do this to send it to a specific view controller?
Provide your UIViewController instead of new UIViewController
for instance change the following code
ViewControllers = new [] {
new UIViewController { View = new UILabel { Text = "Animals (drag right)" } },
new UIViewController { View = new UILabel { Text = "Vegetables (drag right)" } },
new UIViewController { View = new UILabel { Text = "Minerals (drag right)" } },
},
to
ViewControllers = new [] {
new <your_UIViewController>(),
new <your_UIViewController>(),
new <your_UIViewController>(),
},
Hope this helps you, let me know if you faced any issue while implementing the same.
As title said, I want to show another UIViewController from an existing UIViewController which is hosted in UIPopoverController. I tried the following method:
_secondViewController = new SecondViewController();
this.ModalPresentationStyle = UIModelPresentationStyle.CurrentContext;
this.ModelInPopover = true;
this.PresentModelViewController(_secondViewController, true);
However, the secondViewController is shown in the main view controller, instead of the popover controller.
In this post somebody mentions that it cannot be done and it violates the HIG. However, I have seen this in other apps (e.g. Yahoo! Email) if I'm not mistaken.
I'm also thinking about another approach: If I could create a UINavigationController within the popover context, it might work by just adding new ViewController to the NavigationController. But how?
Remember that UINavigationController derives from UIViewController.
So, you can use the controller contained within UIPopover just like any other container... in this case it's best to use UINavigationController inside UIPopover to display ViewControllers.
Usage:
var _NavController = new NavController();
Popover = new UIPopoverController(_NavController);
Popover.PopoverContentSize = new SizeF(..., ...);
Popover.PresentFromRect(...);
NavController:
public class NavController : UINavigationController
{
UIViewController _FirstViewController;
UIViewController _SecondViewController;
public NavController()
: base()
{
}
public override void LoadView()
{
base.LoadView();
_FirstViewController = new UIViewController();
// Initialize your originating View Controller here.
// Only view related init goes here, do everything else in ViewDidLoad()
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
// When a button inside the first ViewController is clicked
// The Second ViewController is shown in the stack.
_FirstViewController.NavButton.TouchUpInside += delegate {
PushSecondViewController();
};
this.PushViewController(_FirstViewController, true);
}
public void PushSecondViewController()
{
_SecondViewController = new UIViewController();
this.PushViewController(_SecondViewController, true);
}
}