如何在 Xamarin.Forms 中推送时隐藏标签栏?

Woj*_*lik 3 uitabbar xamarin.ios ios xamarin xamarin.forms

我最近几天TabbedPage在 iOS 上的 Xamarin.Forms 中苦苦挣扎。我找到了一些类似的解决方案:https : //forums.xamarin.com/discussion/20901/hide-tab-bar-on-push

但是,它们中没有一个运行良好。我还尝试子类化TabbedRenderer并将 TabBar 高度设置为 0。它可以工作,但是如果我在NavigationPage.Pushed事件处理程序中隐藏 TabBar,则会出现一些延迟,例如 TableView 底部有空白区域。

如果我尝试NavigationRendererPushViewController/PopViewController方法中覆盖和隐藏/显示标签栏,它有时会失败。例如,如果我来回快速导航,PopViewController则不会调用方法,导航堆栈被破坏并且标签栏不会恢复。

我认为唯一好的解决方案是使该属性起作用:UIViewController.HidesBottomBarWhenPushed. 但是,我不知道该怎么做,因为在渲染器中设置/覆盖它不起作用。

有没有人成功地显示和隐藏 TabBar?

Woj*_*lik 5

我设法实施了一个解决方案,该解决方案在隐藏后解决了空白问题TabBar。您可以在本文中阅读有关它的更多详细信息。

为了解决这个问题,我们只需要布局 all ChildViewControllers。这是我自定义的示例实现TabbedPage及其TabbedPageRenderer.

HideableTabbedPage.cs:

using System;
using Xamarin.Forms;

namespace HideTabBar.Controls
{
    public class HideableTabbedPage : TabbedPage
    {
        public static readonly BindableProperty IsHiddenProperty =
            BindableProperty.Create(nameof(IsHidden), typeof(bool), typeof(HideableTabbedPage), false);

        public bool IsHidden
        {
            get { return (bool)GetValue(IsHiddenProperty); }
            set { SetValue(IsHiddenProperty, value); }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

HideableTabbedPageRenderer.cs:

using System;
using System.ComponentModel;
using System.Threading.Tasks;
using HideTabBar.Controls;
using HideTabBar.iOS.CustomRenderer;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

[assembly: ExportRenderer(typeof(HideableTabbedPage), typeof(HideableTabbedPageRenderer))]
namespace HideTabBar.iOS.CustomRenderer
{
    public class HideableTabbedPageRenderer : TabbedRenderer
    {
        private bool disposed;
        private const int TabBarHeight = 49;

        protected override void OnElementChanged(VisualElementChangedEventArgs e)
        {
            base.OnElementChanged(e);

            if (e.OldElement == null)
            {
                this.Tabbed.PropertyChanged += Tabbed_PropertyChanged;
            }
        }

        private void Tabbed_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == HideableTabbedPage.IsHiddenProperty.PropertyName)
            {
                this.OnTabBarHidden((this.Element as HideableTabbedPage).IsHidden);
            }
        }

        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
            this.disposed = true;
        }

        private async void OnTabBarHidden(bool isHidden)
        {
            if (this.disposed || this.Element == null || this.TabBar == null)
            {
                return;
            }

            await this.SetTabBarVisibility(isHidden);
        }

        private async Task SetTabBarVisibility(bool hide)
        {
            this.TabBar.Opaque = false;
            if (hide)
            {
                this.TabBar.Alpha = 0;
            }

            this.UpdateFrame(hide);

            // Show / Hide TabBar
            this.TabBar.Hidden = hide;
            this.RestoreFonts();

            // Animate appearing 
            if (!hide)
            {
                await UIView.AnimateAsync(0.2f, () => this.TabBar.Alpha = 1);
            }
            this.TabBar.Opaque = true;

            this.ResizeViewControllers();
            this.RestoreFonts();
        }

        private void UpdateFrame(bool isHidden)
        {
            var tabFrame = this.TabBar.Frame;
            tabFrame.Height = isHidden ? 0 : TabBarHeight;
            this.TabBar.Frame = tabFrame;
        }

        private void RestoreFonts()
        {
            // Workaround to restore custom fonts:

            foreach (var item in this.TabBar.Items)
            {
                var text = item.Title;
                item.Title = "";
                item.Title = text;
            }
        }

        private void ResizeViewControllers()
        {
            foreach (var child in this.ChildViewControllers)
            {
                child.View.SetNeedsLayout();
                child.View.SetNeedsDisplay();
            }
        }
    }
}  
Run Code Online (Sandbox Code Playgroud)

最后结果:

自动隐藏标签栏