我发现在iOS上,当页面字面上出现在屏幕上时会调用OnAppearing,而在Android上,它会在创建时调用。
我正在使用这个事件懒洋洋地构建一个昂贵的构建视图,但显然Android的行为使这个失败了。
当屏幕出现在屏幕上时,是否有某种方式可以了解Android?
答案 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实现意味着,由于弹出导航堆栈,因此无法在显示第二秒钟之前更新视图。 相反,它出现了过时的内容,那么您就有机会 纠正它。这不好。)