工具栏/导航栏中的Xamarin.Forms ActivityIndi​​cator

时间:2018-03-07 08:43:58

标签: xamarin.forms toolbar activity-indicator

我有一个遵循MVVM模式的多页(Android& iOS)Xamarin.Forms应用程序。有时,业务逻辑可以调用重要的活动,例如触发与某些Web服务的数据同步。我想向用户显示后台正在发生的事情。工具栏中的ActivityIndi​​cator将是我理想的解决方案。该活动与前景中的页面无关,因此我不想将指标放在页面上,我希望它在外面的某个地方,工具栏似乎是正确的位置。

我的第一次尝试是通过XAML:

<ContentPage.ToolbarItems>
    <ToolbarItem>
        <ActivityIndicator IsRunning="{Binding IsRunning}" />
    </ToolbarItem>
</ContentPage.ToolbarItems>

虽然这个(和类似的方法)编译,它会抛出一个异常,看起来像ActivityIndi​​cator可能不是ToolbarItems的子代或任何工具栏项。

翻转手册页我偶然发现了页面类的IsBusy属性。

https://developer.xamarin.com/api/property/Xamarin.Forms.Page.IsBusy/

试试,我使用了这段代码:

public App ()
{
    InitializeComponent();
    MainPage = new App1.MainPage();
    MainPage.IsBusy = true;
}

结果是 - 什么都没有。没有错误,但工具栏中没有显示任何内容。我在论坛中发现了一些迹象表明这个功能可能在最新的Android版本中被丢弃了,但没有明确的说明,而且文档也没有这么说。

我如何实现我的目标?

1 个答案:

答案 0 :(得分:1)

以下是可以在PCL和Android项目中使用的代码,遗憾的是我目前尚未编写iOS自定义渲染器。不管怎样,您需要在PCL中使用自定义NavigationPage,并在Android项目中使用自定义NavigationPageRenderer

CustomNavigationPage.cs (在您的PCL项目中):

public class CustomNavigationPage : NavigationPage
{
    public event EventHandler<EventArgs> OnShowActivityIndicator;
    public event EventHandler<EventArgs> OnHideActivityIndicator;
}

CustomNavigationPageRenderer.cs (在Android项目中):

[assembly: ExportRenderer(typeof(CustomNavigationPage), typeof(CustomNavigationPageRenderer))]
namespace MyProject.Droid.CustomRenderers
{
    CustomNavigationPage page;
    Android.Support.V7.Widget.Toolbar _toolbar;
    Android.Widget.ProgressBar _progressBar;
    bool _isProgressBarCurrentlyOnToolBar = false;

    public class CustomNavigationPageRenderer : NavigationPageRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<CustomNavigationPage> e)
        {
            base.OnElementChanged(e);

            if (e.NewElement != null)
            {
                page = (CustomNavigationPage)e.NewElement;
                page.OnShowActivityIndicator += HandleShowActivityIndicator;
                page.OnHideActivityIndicator += HandleHideActivityIndicator;
            }
        }

        private void HandleShowActivityIndicator(object sender, EventArgs e)
        {
            var progressBar = GetProgressBar();
            if (progressBar == null)
                return;

            var toolbar = GetToolbar();
            if (toolbar == null)
                return;

            Device.BeginInvokeOnMainThread(() => 
            {
                if (_isProgressBarCurrentlyOnToolBar == false)
                {
                    toolbar.AddView(progressBar);
                    _isProgressBarCurrentlyOnToolBar = true;
                }
            });
        }

        private void HandleHideActivityIndicator(object sender, EventArgs e)
        {
            var progressBar = GetProgressBar();
            if (progressBar == null)
                return;

            var toolbar = GetToolbar();
            if (toolbar == null)
                return;

            Device.BeginInvokeOnMainThread(() => 
            {
                if (_isProgressBarCurrentlyOnToolBar)
                {
                    toolbar.RemoveView(progressBar);
                    _isProgressBarCurrentlyOnToolBar = false;
                }
            });
        }

        private Android.Support.V7.Widget.Toolbar GetToolbar()
        {
            if (_toolbar == null)
            {
                for (var i = 0; i < this.ChildCount; i++)
                {
                    var child = GetChildAt(i);

                    if (child.GetType() == typeof(Android.Support.V7.Widget.Toolbar))
                    {
                        _toolbar = (Android.Support.V7.Widget.Toolbar)child;
                    }
                }
            }

            return _toolbar;
        }

        private Android.Widget.ProgressBar GetProgressBar()
        {
            if (_progressBar == null)
            {
                _progressBar = new Android.Widget.ProgressBar(Xamarin.Forms.Forms.Context)
                {
                    Indeterminate = true,
                    LayoutParameters = new LayoutParams(Utils.PxToDip(20), Utils.PxToDip(20))
                };
                _progressBar.SetPadding(10, 0, 0, 0);
            }

            return _progressBar;
        }

    }
}

使用它很简单,在你的代码后面只需调用事件处理程序。即:

public class MyPage : CustomNavigationPage
{
    public MyPage()
    {
        // show it:
        OnShowActivityIndicator?.Invoke(this, null);

        // hide it:
        OnHideActivityIndicator?.Invoke(this, null);
    }
}