在iOS中调用RemovePage后未清除导航堆栈-Xamarin.Forms

时间:2019-05-21 20:01:32

标签: ios xamarin.forms navigation

我目前正在使用Xamarin.Forms开发应用程序。我在iOS中面临一些严重的问题。我的根页面是TabbedPage,我想使我的标签在整个应用程序中可见。因此,我将MainPage设置如下

App.cs

MainPage = new NavigationPage(new MyTabbedPage());

MyTabbedPage.cs

Children.Add(new NavigationPage(new FirstTabbedPage()));
Children.Add(new NavigationPage(new SecondTabbedPage()));
Children.Add(new NavigationPage(new ThirdTabbedPage()));

FirstTabbedPage和SecondTabbedPage均显示使用DevExpress.Mobile的DataGrid。在从网格的任何行中点击时,我都导航到另一个ContentPage,在Root选项卡中说MyContentPage。

SecondTabbePage.cs

private async void Grid_RowTap(object sender, RowTapEventArgs e)
        {
        //Some code logic, to get data from server
            await Navigation.PushAsync(new MyContentPage());
        }

例如,我要从SecondTabbedPage导航到MyContentPage。从ContentPage,我导航到FirstTabbedPage。现在,如果我单击SecondTabbedPage,将显示MyContentPage,但我不希望出现这种情况,因此我正在使用MyContentPage的OnDisappearing方法从NavigationStack中删除页面,如下所示:

MyContentPage.cs

protected override void OnDisappearing()
        {
            base.OnDisappearing();

            //Clear Navigation Stack, clicking on tab page should always 
            //go to corresponding page
            try
            {
                var existingPages = Navigation.NavigationStack.ToList();
                foreach (var page in existingPages)
                {                        
                    //existingPages count should be greater than 1, so that this will never be root page. Otherwise removing root page will throw exception
                    if (string.Compare(page.GetType().Name, "MyContentPage", StringComparison.OrdinalIgnoreCase) == 0 && existingPages.Count > 1)
                    {
                        Navigation.RemovePage(page);
                    }

                }
         //Just to check whether page was removed or not, but still was able to see MyContentPage even after removing it from Navigation Stack
             var existingPages = Navigation.NavigationStack.ToList();
            }
            catch(Exception ex)
            {

            }
        }

现在的问题是:

  1. 即使在调用RemovePage(MyContentPage)之后,我也可以在调试模式下看到该页面。
  2. 由于此行为,请等待Navigation.PushAsync(new MyContentPage());。尽管它执行代码没有任何异常,但仍没有第二次导航到MyContentPage。
  

与Android生命周期相同,相同的代码在Android中也能正常工作   在调试模式下可以看到的不同

我尝试过的一些事情是

  1. 从MainPage(TabbedPage)中删除了NavigationPage,因为我看到NavigationPage中的TabbedPage不是适用于iOS的良好设计。
  2. 删除了子项上的NavigationPage,但导航到MyContentPage后未显示选项卡式图标
  3. 试图在FirstTabbedPage的OnAppearing事件中从NavigationStack中删除MyContentPage。

2 个答案:

答案 0 :(得分:1)

正如您所说,由于Android生命周期不同于iOS,我建议您通过在iOS中使用自定义渲染器来达到要求。

您应该为MyTabbedPage创建自定义渲染器,然后在ViewControllerSelected事件中,从ContentPage中删除NavigationStack

[assembly: ExportRenderer(typeof(MainPage), typeof(myTabbarRenderer))]
namespace TabbedPageWithNavigationPage.iOS
{
    class myTabbarRenderer : TabbedRenderer
    {
        private MainPage _page;
        protected override void OnElementChanged(VisualElementChangedEventArgs e)
        {
            base.OnElementChanged(e);

            if (e.NewElement != null)
            {
                _page = (MainPage)e.NewElement;
            }
            else
            {
                _page = (MainPage)e.OldElement;
            }

            try
            {
                var tabbarController = (UITabBarController)this.ViewController;
                if (null != tabbarController)
                {
                    tabbarController.ViewControllerSelected += OnTabbarControllerItemSelected;
                }
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception);
            }
        }

        private async void OnTabbarControllerItemSelected(object sender, UITabBarSelectionEventArgs eventArgs)
        {
            if (_page?.CurrentPage?.Navigation != null && _page.CurrentPage.Navigation.NavigationStack.Count > 0)
            {
                await _page.CurrentPage.Navigation.PopToRootAsync();
            }

        }
    }
}

对于Android,请添加Device.RuntimePlatform == Device.Android以确保代码仅在Android平台上有效:

protected override void OnDisappearing()
{
    base.OnDisappearing();

    //Clear Navigation Stack, clicking on tab page should always 
    //go to corresponding page

    if (Device.RuntimePlatform == Device.Android)
    {
        try
        {
            var existingPages = Navigation.NavigationStack.ToList();
            foreach (var page in existingPages)
            {
                //existingPages count should be greater than 1, so that this will never be root page. Otherwise removing root page will throw exception
                if (string.Compare(page.GetType().Name, "UpcomingAppointmentsPage", StringComparison.OrdinalIgnoreCase) == 0 && existingPages.Count > 1)
                {
                    Navigation.RemovePage(page);
                }

            }                 
        }
        catch (Exception ex)
        {

        }
    }           
}

我编写了一个演示here,您可以检查它。让我知道它是否有效。

答案 1 :(得分:0)

我尝试了@Jackhua解决方案。它也完美。但是我使用下面的方法来解决Xamarin论坛中建议的上述问题。

参考:https://forums.xamarin.com/discussion/comment/375638#Comment_375638

MyTabbedPage.cs

    Page page1 = null;
    Page page2 = null;
    Page page3 = null;
    public MainPage()
    {
        InitializeComponent();

        page1 = new NavigationPage(new FirstTabbedPage());
        page1.Title = "Page1";

        page2 = new NavigationPage(new SecondTabbedPage());
        page2.Title = "Page2";

        page3 = new NavigationPage(new ThirdTabbedPage());
        page3.Title = "Page3";

        Children.Add(page1);
        Children.Add(page2);
        Children.Add(page3);
    }

    protected override void OnCurrentPageChanged()
    {
        base.OnCurrentPageChanged();

        int index = Children.IndexOf(CurrentPage);


        if (index == 0)
        {
            if (Children.Count > 1)
            {
                page2 = Children[1] as NavigationPage;
                page2.Navigation.PopToRootAsync();

                page3 = Children[2] as NavigationPage;
                page3.Navigation.PopToRootAsync();
            }
        }

        else if (index == 1)
        {
            if (Children.Count > 1)
            {
                page1 = Children[0] as NavigationPage;
                page1.Navigation.PopToRootAsync();

                page3 = Children[2] as NavigationPage;
                page3.Navigation.PopToRootAsync();
            }
        }

        else if (index == 2)
        {
            if (Children.Count > 1)
            {
                page1 = Children[0] as NavigationPage;
                page1.Navigation.PopToRootAsync();

                page2 = Children[1] as NavigationPage;
                page2.Navigation.PopToRootAsync();
            }
        }
    }

上述解决方案不需要自定义渲染器,并且适用于Android和iOS。

  

也不需要MyContentPage.cs下的代码块。即   在OnDisappearing方法下删除现有页面的迭代