【问题标题】:TabbedPage hide all tabsTabbedPage 隐藏所有选项卡
【发布时间】:2018-07-17 10:55:05
【问题描述】:

我是 Xamarin 的新手,想创建一个包含多个页面的应用程序,这些页面通过按钮单击导航到。 我已经想出了如何通过代码导航到所需的页面,但我正在努力隐藏标签以禁用用户导航。

我正在使用一个 TabbedPage 有我的主页,然后添加 8 个 NavigationPages 作为子页面。

如何隐藏标签?

【问题讨论】:

    标签: xamarin.forms tabbedpage


    【解决方案1】:

    要在 Xamarin.Forms 中隐藏选项卡,您需要在本机项目中包含自定义呈现器。我没有使用 UWP atm,所以只是发布了 iOS 和 Android 的渲染器,它们完全隐藏了选项卡栏。 更改我的命名空间并考虑可能将选项卡式页面子类化,这样您就不会隐藏应用程序中的所有选项卡,而只是选择的选项卡。

    iOS 渲染器:

    using System;
    using AppoMobi.iOS;
    using Xamarin.Forms;
    using Xamarin.Forms.Platform.iOS;
    using UIKit;
    
    [assembly: ExportRenderer(typeof(TabbedPage), typeof(HiddenTabbedPageRenderer))]
    namespace AppoMobi.iOS
    {   
        //***************************************************************************
        public class HiddenTabbedPageRenderer : TabbedRenderer
        //***************************************************************************
        {
    
            private UITabBarController tabbarController { get; set; }
            private TabbedPage CurrentTabbedPage { get; set; }
    
            //-------------------------------------------------------------
            protected override void OnElementChanged(VisualElementChangedEventArgs e)
            //-------------------------------------------------------------
            {
                base.OnElementChanged(e);
    
                if (e.OldElement != null)
                {
                    //release any stuff here
                }
    
                if (e.NewElement != null)
                {
                    tabbarController = (UITabBarController) this.ViewController;
                    CurrentTabbedPage = (TabbedPage) e.NewElement;
                }
                else
                {
                    CurrentTabbedPage = (TabbedPage) e.OldElement;
                }
    
                //the following commented code is not working
                //as Forms as it just leaves empty white space
                //instead of hidden tabbedbar:     
                //       if (tabbarController != null)
                //         tabbarController.TabBar.Hidden = true;
            }
    
            //just hide tabbar by setting its height to zero
            // credits:
            // https://stackoverflow.com/a/26255545/7149454
            // "how to change UITabBar height"
            private nfloat newHeight = 0; //change tabbed bar height to this value
            //-------------------------------------------------------------------
            public override void ViewWillLayoutSubviews()
            //-------------------------------------------------------------------
            {
                if (tabbarController != null)
                {
                    var tabFrame = tabbarController.TabBar.Frame; //self.TabBar is IBOutlet of your TabBar
                    tabFrame.Height = newHeight;
                    tabFrame.Offset(0, tabbarController.View.Frame.Height - newHeight);
                    tabbarController.TabBar.Frame = tabFrame;
                }
                base.ViewWillLayoutSubviews();
            }
        }
    }
    

    Android 渲染器:

    using Xamarin.Forms;
    using Xamarin.Forms.Platform.Android;
    using System;
    using Android.Content;
    using Android.Support.Design.Widget;
    using Android.Support.V4.View;
    using Android.Views;
    using AppoMobi.Droid;
    using Xamarin.Forms.Platform.Android.AppCompat;
    
    [assembly: ExportRenderer(typeof(TabbedPage), typeof(MyTabbedRenderer))]
    namespace AppoMobi.Droid
    {
        //****************************************************
        public class MyTabbedRenderer : TabbedPageRenderer, TabLayout.IOnTabSelectedListener
        //****************************************************
        {
    
            private TabLayout TabsLayout { get; set; }
            private ViewPager PagerLayout { get; set; }
            private NiftyTabbedPage CurrentTabbedPage { get; set; }
    
            //-------------------------------------------------------------------
            public MyTabbedRenderer(Context context) : base(context)
            //-------------------------------------------------------------------
            {
            }
    
            protected override void OnElementChanged(ElementChangedEventArgs<TabbedPage> e)
            {
                base.OnElementChanged(e);
    
                if (e.OldElement != null)
                {
                    //cleanup here
                }
    
                if (e.NewElement != null)
                {
                    CurrentTabbedPage = (NiftyTabbedPage)e.NewElement;
                }
                else
                    CurrentTabbedPage = (NiftyTabbedPage)e.OldElement;
    
                //find the pager and tabs
                for (int i = 0; i < ChildCount; ++i)
                {
                    Android.Views.View view = (Android.Views.View)GetChildAt(i);
                    if (view is TabLayout)
                        TabsLayout = (TabLayout)view;
                    else
                    if (view is ViewPager) PagerLayout = (ViewPager)view;
                }
    
            }
    
    
            //-------------------------------------------------------------------------------
            protected override void OnLayout(bool changed, int l, int t, int r, int b)
            //-------------------------------------------------------------------------------    
            {
                TabsLayout.Visibility = ViewStates.Gone;
    
                base.OnLayout(changed, l, t, r, b);
            }    
        }
    
    
    }
    

    【讨论】:

    • 信息 NiftyTabbedPage 是一个简单的 TabbedPage 的子类
    【解决方案2】:

    我喜欢 ZaneCampbell 提供的解决方案 here。它可以工作,很简单,并且不需要自定义渲染器。用他自己的话说:

    我只是将我的 TabbedPage 嵌入到 NavigationPage 中,然后当我将选项卡添加到 TabbedPage 时,我将一个操作传递给必要的选项卡,从而允许它们将页面推送到 NavigationPage 上。已在 iOS 和 Android 上测试并运行。

    然后是代码:

    public class TabControllerPage : TabbedPage
    {
        public TabControllerPage()
        {
            // This hides the navigation page's navigation bar as it is not needed
            NavigationPage.SetHasNavigationBar(this, false);
    
            // Create tab page and pass PushPage action to it
            var testPage = new TestPage {
                PushPage = (page) => {
                    Navigation.PushAsync(page, true);
                }
            };
    
            // Add as many tabs as you like here
            AddTab(testPage, "Tab 1", true, "tab_1_icon.png");
        }
    
        void AddTab(Page page, string title, bool inNav, string icon = null)
        {
            // This sets the NavigationBar title
            page.Title = title;
    
            if (inNav)
            {
                var navigationPage = new NavigationPage(page);
                if (icon != null)
                {
                    navigationPage.Icon = icon;
                }
                // This sets the tab labels
                navigationPage.Title = title;
                Children.Add(navigationPage);
            }
            else
            {
                Children.Add(page);
            }
        }
    }
    
    public partial class TestPage : ContentPage
    {
        public Action<ContentPage> PushPage;
    
        public TestPage()
        {
            InitializeComponent();
        }
    
        // Call this method when ever you need to push a page onto the navigation page and hide the tabbed page.
        void NavigateToPage(ContentPage page)
        {
            PushPage?.Invoke(page);
        }
    }
    

    【讨论】:

      【解决方案3】:

      您只需执行此操作即可删除或隐藏您不想要的页面。

      this.Children.Remove(Page you want to remove);
      

      【讨论】:

        【解决方案4】:

        在我的自定义渲染器中,我可以像这样隐藏标签导航栏。

         protected override void OnElementChanged(ElementChangedEventArgs<TabbedPage> e)
            {
                base.OnElementChanged(e);
        
                if (e.NewElement != null)
                {
                    tabbedPage = e.NewElement as Xamarin.Forms.TabbedPage;
                    bottomNavigationView = (GetChildAt(0) as Android.Widget.RelativeLayout).GetChildAt(1) as BottomNavigationView;
                    bottomNavigationView.NavigationItemSelected += BottomNavigationView_NavigationItemSelected;
        
                    //Call to change the font
                    ChangeFont();
                }
        
                if (e.OldElement != null)
                {
                    bottomNavigationView.NavigationItemSelected -= BottomNavigationView_NavigationItemSelected;
                }
        
                bottomNavigationView.Visibility = ViewStates.Gone;
            }
        

        【讨论】:

          【解决方案5】:

          如何隐藏标签?

          在我看来你不应该。

          对于您描述的导航方案,标签页根本不是正确的手段,无论是从技术上还是从用户体验的角度来看。

          也许实现所需导航方案的最简单方法是使用NavigationPage(请参阅herehere)并通过将HasNavigationBar 属性设置为false 来隐藏导航栏

          // in App.xaml.cs
          
          public App()
          {
              InitializeComponent();
              MainPage = new NavigationPage(new FirstPage())
              {
                  HasNavigationBar = false;
              };
          }
          

          您可以从您的页面访问Application.Current,获取NavigationPage 并导航

          public void Button_OnPress(object sender, EventArgs e)
          {
              var navigationPage = Application.Current.MainPage as NavigationPage;
              if(navigationPage != null)
              {
                  navigationPage.PushAsync(new WhatEverPage());
              }
          }
          

          备注:虽然你可以这样做,但这并不意味着你应该这样做。我强烈建议使用像 Prism 这样的 MVVM 框架并使用 prisms INavigationService 进行导航。通过这种方式,您可以保持页面松散耦合,因为INavigationService 不使用页面实例,而是使用它们的名称并使用 DI 容器解析它们。

          【讨论】:

          • TL/DR 不合适。我有一个完全需要这个功能的用例。我的应用程序有一个主进程,它将页面推送到堆栈上并在进程结束时弹出到根目录。我有使用根页面上的选项卡访问的支持功能。主进程需要隐藏选项卡,并且仅在根上可见。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-05-21
          • 1970-01-01
          • 1970-01-01
          • 2023-03-17
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多