Reputation: 1295
In our App we have a log-in ViewController A
. On user log-in, a request navigate is automatically called to navigate to the next ViewController B
. However when this is done we want to remove the log-in ViewController A
from the stack so the user cannot "go back" to the log-in view but goes back the previous ViewController
before the log-in instead.
We thought about removing the ViewController A
from the stack when ViewController B
is loaded, but is there a better way?
In the Android version of the App we've set history=no
(if I recall correctly) and then it works.
Is there an similar way to achieve this in MonoTouch and MvvmCross?
Upvotes: 3
Views: 6385
Reputation: 1295
I ended up with removing the unwanted viewcontroller from the navigation controller. In ViewDidDisappear()
of my login ViewController
I did the following:
public override void ViewDidDisappear (bool animated)
{
if (this.NavigationController != null) {
var controllers = this.NavigationController.ViewControllers;
var newcontrollers = new UIViewController[controllers.Length - 1];
int index = 0;
foreach (var item in controllers) {
if (item != this) {
newcontrollers [index] = item;
index++;
}
}
this.NavigationController.ViewControllers = newcontrollers;
}
base.ViewDidDisappear(animated);
}
This way I way remove the unwanted ViewController
when it is removed from the view. I am not fully convinced if it is the right way, but it is working rather good.
Upvotes: 8
Reputation: 66882
This is quite a common scenario... so much so that we've included two mechanisms inside MvvmCross to allow this....
ClearTop
parameter available in all ViewModel navigations.RequestRemoveBackStep()
call in all ViewModels - although this is currently NOT IMPLEMENTED IN iOS - sorry.ClearTop
parameter available in all ViewModel navigations.To use this, simply include the ClearTop flag when navigating.
This is a boolean flag - so to use it just change:
this.RequestNavigate<ChildViewModel>(new {arg1 = val1});
to
this.RequestNavigate<ChildViewModel>(new {arg1 = val1}, true);
For a standard simple navigation controller presenter, this will end up calling ClearBackStack
before your new view is shown:
public override void ClearBackStack()
{
if (_masterNavigationController == null)
return;
_masterNavigationController.PopToRootViewController (true);
_masterNavigationController = null;
}
If you are not using a standard navigation controller - e.g. if you had a tabbed, modal, popup or split view display then you will need to implement your own presentation logic to handle this.
RequestRemoveBackStep()
.Sadly it proved a bit awkward to implement this at a generic level for iOS - so currently that method is:
public bool RequestRemoveBackStep()
{
#warning What to do with ios back stack?
// not supported on iOS really
return false;
}
Sorry! I've raised a bug against this - https://github.com/slodge/MvvmCross/issues/80
If you need to implement something custom for your iOS app, the best way is to do this through some sort of custom Presenter logic.
There are many ways you could do this.
One example is:
[Special]
attributein Show
in your custom Presenter
in your app, you could watch for that attribute and do the special behaviour at that time
public override void Show(MvxShowViewModelRequest request)
{
if (request.ViewModelType.GetCustomAttributes(typeof(SpecialAttribute), true).Any())
{
// do custom behaviour here - e.g. pop current view controller
}
base.Show(request);
}
Obviously other mechanisms might be available - it's just C# and UIKit code at this stage
Upvotes: 1
Reputation: 1408
I don't know about mvvm but you can simply Pop the viewcontroller (AC A) without animation and then push the new viewcontoller (AC B) with animation
From within AC A:
NavigationController.PopViewControllerAnimated(false);
NavigationController.PushViewController(new ACb(), true);
Upvotes: 0