По-разному на iOS и Android - PullRequest
0 голосов
/ 24 апреля 2018

Я обнаружил, что в iOS OnAppearing вызывается, когда страница буквально появляется на экране, тогда как в Android он вызывается при создании.

Я использую это событие, чтобы лениво создавать дорогойпредставление конструкции, но, очевидно, поведение Android побеждает это.

Есть ли какой-нибудь способ узнать в Android, когда экран буквально появляется на экране?

Ответы [ 2 ]

0 голосов
/ 11 октября 2018

В Android Xamarin.Forms.Page.OnAppearing вызывается непосредственно перед тем, как пользователю отображается представление страницы (а не когда страница «создается» (создается)).


Если вы хотите, чтобы начальное представление появлялось быстро, опуская дорогостоящее вложенное представление, используйте привязку, чтобы изначально IsVisible этого представления был "ложным". Это будет держать его вне визуального дерева, избегая большей части затрат на его создание. Поместите (невидимое) представление в ячейку сетки, размеры которой постоянны (либо в DP, либо в «*» - что угодно, кроме «Авто»). Таким образом, этот макет будет «готов» для этого представления, когда вы сделаете его видимым.


ПОДХОД 1:

Теперь вам просто нужна модель привязки в представлении, которая изменит IsVisible на "true".
Самый простой способ взлома - в OnAppearing запустить действие, которое изменит эту переменную через 250 мс.


ПОДХОД 2:

Чистая альтернатива - создать пользовательский рендерер страниц и переопределить «рисование».
Сделайте draw, после вызова base.draw, проверьте свойство действия на вашей странице.
Если не ноль, вызовите это действие, затем очистите его (так происходит только один раз).

Я делаю это, наследуя от пользовательского базового класса страницы:

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, потому что Xamarin Forms на iOS (неправильно - не по спецификации) вызывает OnAppearing ПОСЛЕ рисования страницы.
Итак, у меня есть логика OnPlatform. На iOS OnAppearing немедленно вызывает DeferredOnAppearing. На Android показанная строка завершена.
Надеюсь, в конечном итоге iOS будет исправлен вызов OnAppearing ДО, для согласованности между двумя платформами.
Если это так, я бы добавил аналогичный рендерер для iOS.

(Текущая реализация iOS означает, что нет способа обновить представление, пока оно не появилось ВТОРОЕ время, из-за появления стека навигации. вместо этого он появляется с устаревшим контентом, ТОГДА вы получаете шанс исправить это. Это не хорошо.)

0 голосов
/ 24 апреля 2018

Вы можете использовать событие:

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");
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...