Remove ViewController from stack

2020-03-05 02:34发布

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?

3条回答
beautiful°
2楼-- · 2020-03-05 03:04

This is quite a common scenario... so much so that we've included two mechanisms inside MvvmCross to allow this....

  1. a ClearTop parameter available in all ViewModel navigations.
  2. a RequestRemoveBackStep() call in all ViewModels - although this is currently NOT IMPLEMENTED IN iOS - sorry.
  3. If this isn't enough, then a third technique might be to use a custom presenter to help with your display logic.

To use : 1. a 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;
    }

from https://github.com/slodge/MvvmCross/blob/vnext/Cirrious/Cirrious.MvvmCross.Touch/Views/Presenters/MvxTouchViewPresenter.cs

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.


You can't: 2. 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;
    }

from https://github.com/slodge/MvvmCross/blob/vnext/Cirrious/Cirrious.MvvmCross.Touch/Views/MvxTouchViewDispatcher.cs

Sorry! I've raised a bug against this - https://github.com/slodge/MvvmCross/issues/80


3. You can always... Custom ideas

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:

  • for any View or ViewModel which needs to clear the previous view, you could decorate the View or ViewModel with a [Special] attribute
  • in 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

查看更多
祖国的老花朵
3楼-- · 2020-03-05 03:18

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);
查看更多
Evening l夕情丶
4楼-- · 2020-03-05 03:20

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.

查看更多
登录 后发表回答