OnAppearing与iOS和Android不同

时间:2018-04-24 15:27:46

标签: xamarin xamarin.forms

我发现在iOS上,当页面字面上出现在屏幕上时会调用OnAppearing,而在Android上,它会在创建时调用。

我正在使用这个事件懒洋洋地构建一个昂贵的构建视图,但显然Android的行为使这个失败了。

当屏幕出现在屏幕上时,是否有某种方式可以了解Android?

2 个答案:

答案 0 :(得分:1)

您可以使用该活动:

this.Appearing += YourPageAppearing;

否则,您应该使用包含生命周期方法的Application类的方法:

protected override void OnStart()
{
    Debug.WriteLine ("OnStart");
}
protected override void OnSleep()
{
    Debug.WriteLine ("OnSleep");
}
protected override void OnResume()
{
    Debug.WriteLine ("OnResume");
}

答案 1 :(得分:0)

在Android上,Xamarin.Forms.Page.OnAppearing会在向用户显示页面视图之前立即调用(不是在“创建”(构造)页面时)。


如果您希望通过省略昂贵的子视图来快速显示初始视图,请使用绑定使该视图的IsVisible最初为“ false”。这将使它脱离可视化树,从而避免了构建它的大部分成本。将(不可见的)视图放置在尺寸不变的网格单元中(在DP或“ *”中-除“自动”以外的任何其他值。)因此,当您使该视图可见时,该布局将“就绪”。


方法1:

现在,您只需要在视图模型中绑定即可将IsVisible更改为“ true”。
最简单的方法是在OnAppearing中触发一个动作,该动作将在250 ms之后更改该变量。


方法2:

干净的替代方法是创建自定义页面渲染器,并覆盖“绘制”。
在调用base.draw之后进行抽奖,然后检查页面上的action属性。
如果不为null,请调用该操作,然后将其清除(因此只会发生一次)。

我是通过继承自定义页面基类来实现的:

每个页面的XAML(将“ ContentPage”更改为“ exodus:ExBasePage”):

<exodus:ExBasePage
    xmlns:exodus="clr-namespace:Exodus;assembly=Exodus"
    x:Class="YourNamespace.YourPage">
    ...
</exodus:ExBasePage>

xaml.cs:

using Exodus;

// After creating page, change "ContentPage" to "ExBasePage".
public partial class YourPage : ExBasePage
{
...

我的自定义ContentPage。注意:包括与此无关的代码,这些代码与iOS安全区域和Android向后硬按钮相关:

using Xamarin.Forms;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
namespace Exodus
{
    public abstract partial class ExBasePage : ContentPage
    {
        public ExBasePage()
        {
            // Each sub-class calls InitializeComponent(); not needed here.

            ExBasePage.SetupForLightStatusBar( this );
        }


        // Avoids overlapping iOS status bar at top, and sets a dark background color.
        public static void SetupForLightStatusBar( ContentPage page )
        {
            page.On<Xamarin.Forms.PlatformConfiguration.iOS>().SetUseSafeArea( true );

            // iOS NOTE: Each ContentPage must set its BackgroundColor to black or other dark color (when using LightContent for status bar).
            //page.BackgroundColor = Color.Black;
            page.BackgroundColor = Color.FromRgb( 0.3, 0.3, 0.3 );
        }


        // Per-platform ExBasePageRenderer uses these.
        public System.Action NextDrawAction;


        /// <summary>
        /// Override to do something else (or to do nothing, i.e. suppress back button).
        /// </summary>
        public virtual void OnHardwareBackButton()
        {
            // Normal content page; do normal back button behavior.
            global::Exodus.Services.NavigatePopAsync();
        }
    }
}

Android项目中的渲染器:

using System;

using Android.Content;
using Android.Views;
using Android.Graphics;

using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

using Exodus;
using Exodus.Android;

[assembly: ExportRenderer( typeof( ExBasePage ), typeof( ExBasePageRenderer ) )]
namespace Exodus.Android
{
    public class ExBasePageRenderer : PageRenderer
    {
        public ExBasePageRenderer( Context context ) : base( context )
        {
        }


        protected override void OnElementChanged( ElementChangedEventArgs<Page> e )
        {
            base.OnElementChanged( e );

            var page = Element as ExBasePage;
            if (page != null)
                page.firstDraw = true;
        }

        public override void Draw( Canvas canvas )
        {
            try
            {
                base.Draw( canvas );

                var page = Element as ExBasePage;
                if (page?.NextDrawAction != null)
                {
                    page.NextDrawAction();
                    page.NextDrawAction = null;
                }
            }
            catch (Exception ex)
            {
                // TBD: Got Disposed exception on Android Bitmap, after rotating phone (in simulator).
                // TODO: Log exception.
                Console.WriteLine( "ExBasePageRenderer.Draw exception: " + ex.ToString() );
            }
        }
    }
}

在第一次绘制页面后要执行一些操作:

public partial class YourPage : ExBasePage
{

    protected override void OnAppearing()
    {
        // TODO: OnPlatform code - I don't have it handy.
        // On iOS, we call immediately "DeferredOnAppearing();"
        // On Android, we set this field, and it is done in custom renderer.
        NextDrawAction = DeferredOnAppearing;
    }

    void DeferredOnAppearing()
    {
        // Whatever you want to happen after page is drawn first time:
        //   ((MyViewModel)BindingContext).ExpensiveViewVisible = true;
        // Where MyViewModel contains:
        //   public bool ExpensiveViewVisible { get; set; }
        // And your XAML contains:
        //    <ExpensiveView IsVisible={Binding ExpensiveViewVisible}" ... />
    }

}

注意:我在iOS上的操作方式有所不同,因为iOS上的Xamarin Forms(错误地-不符合规范)会在页面绘制后调用OnAppearing。
所以我有OnPlatform逻辑。在iOS上,OnAppearing立即调用DeferredOnAppearing。在Android上,显示的行已完成。
希望iOS最终会被修复,以在调用OnAppearing之前, 以确保两个平台之间的一致性。
如果是这样,那么我将为iOS添加类似的渲染器。

(当前的iOS实现意味着,由于弹出导航堆栈,因此无法在显示第二秒钟之前更新视图。 相反,它出现了过时的内容,那么您就有机会 纠正它。这不好。)