2017-01-25 4 views
2

Я заметил, что когда OnElementPropertyChanged запускается в VisualElement, например BoxView, свойства представления базовой платформы в это время не обновляются.Как узнать, когда представление завершено?

Я хочу знать, когда соответствующий вид платформы VisualElement является закончен рендерингом, что-то вроде:

this.someBoxView.ViewHasRendered += (sender, e) => { // Here I would know underlying UIView (in iOS) has finished rendering };

просматривал код внутри Xamarin.Forms, а именно VisualElementRenderer.cs, казалось бы, что я может вызвать событие после завершения OnPropertyChanged. Что-то вроде:

protected virtual void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) 
{ 
    if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName) 
     SetBackgroundColor(Element.BackgroundColor); 
    else if (e.PropertyName == Layout.IsClippedToBoundsProperty.PropertyName) 
     UpdateClipToBounds(); 
    else if (e.PropertyName == PlatformConfiguration.iOSSpecific.VisualElement.BlurEffectProperty.PropertyName) 
     SetBlur((BlurEffectStyle)Element.GetValue(PlatformConfiguration.iOSSpecific.VisualElement.BlurEffectProperty)); 

    // Raise event 
    VisualElement visualElement = sender as VisualElement; 
    visualElement.ViewHasRendered();   
} 

Естественно, есть еще несколько сложностей для добавления события в классе VisualElement, как это будет необходимо подклассы. Но я думаю, вы можете видеть, что мне нужно.

В то время как я выгляжу, я заметил свойства на VisualElement, такие как IsInNativeLayout. Но это похоже только в Win/WP8. Кроме того, UpdateNativeWidget на VisualElementRenderer, однако, я не могу понять, как правильно использовать их.

Любые идеи? Очень ценится.

ответ

2

TL;DR: Убегай, не идти по этому пути ...

На iOS все, что отображает содержимое на экране происходит в UIView (или подкласса) и drawRect: является метод, который делает рисунок. Итак, когда drawRect: сделано, делается рисунок UIView.

Примечание: Анимация может произойти, и вы можете увидеть завершенные сотни завершенных циклов рендеринга. Возможно, вам придется подключиться к каждому обработчику завершения анимации, чтобы определить, когда действительно делается «рендеринг».

Примечание: Розыгрыш производится за пределами экрана и в зависимости от чтения компакт-дисков, экран обновления Гц мог 30fps, или 60 FPS в случае IPad Pro это переменная (30-60hz) ...

Пример :

public class CustomRenderer : ButtonRenderer 
{ 
    public override void Draw(CGRect rect) 
    { 
     base.Draw(rect); 
     Console.WriteLine("A UIView is finished w/ drawRect: via msg/selector)"); 
    } 
} 

на Androidобщего способа привлечь контент через View или подкласс, можно получить поверхность, рисовать/BILT через OpenGL на экран, и т.д. ... и что может не быть в пределах View, но для y наш вариант использования, думаю View s ..

View s имеют Draw методы, которые можно переопределить, и вы также можете подключить в ViewTreeObserver и контролировать OnPreDraw и OnDraw, и т.д., и т.д., и т.д ... Иногда вы должны контролировать Родитель представления (ViewGroup), чтобы определить, когда чертеж будет выполнен или когда он будет завершен.

Также все стандартные виджеты полностью завышены через ресурсы xml, и это оптимизировано, поэтому вы никогда не увидите вызов метода Draw/OnDraw (Примечание: вы всегда должны (?) Получать вызов слушателя OnPreDraw, если вы его принудительно).

Различные View s/s Widget ведут себя по-разному, и там нет возможности рассмотреть все проблемы, вы будете иметь определения, когда View действительно сделано «рендеринг» ...

Пример:

public class CustomButtonRenderer : Xamarin.Forms.Platform.Android.AppCompat.ButtonRenderer, 
    ViewTreeObserver.IOnDrawListener, ViewTreeObserver.IOnPreDrawListener 
{ 
    public bool OnPreDraw() // IOnPreDrawListener 
    { 
     System.Console.WriteLine("A View is *about* to be Drawn"); 
     return true; 
    } 

    public void OnDraw() // IOnDrawListener 
    { 
     System.Console.WriteLine("A View is really *about* to be Drawn"); 
    } 

    public override void Draw(Android.Graphics.Canvas canvas) 
    { 
     base.Draw(canvas); 
     System.Console.WriteLine("A View was Drawn"); 
    } 

    protected override void Dispose(bool disposing) 
    { 
     Control?.ViewTreeObserver.RemoveOnDrawListener(this); 
     Control?.ViewTreeObserver.RemoveOnPreDrawListener(this); 
     base.Dispose(disposing); 
    } 

    protected override void OnElementChanged(ElementChangedEventArgs<Button> e) 
    {   
     base.OnElementChanged(e); 
     if (e.OldElement == null) 
     { 
      Control?.SetWillNotDraw(false); // force the OnPreDraw to be called :-(
      Control?.ViewTreeObserver.AddOnDrawListener(this); // API16+ 
      Control?.ViewTreeObserver.AddOnPreDrawListener(this); // API16+ 
      System.Console.WriteLine($"{Control?.ViewTreeObserver.IsAlive}"); 
     } 
    } 

} 

Разное:

Примечание: Оптимизация макетов, кэширование контента, кэширование графического процессора, аппаратное ускорение, включенное в виджетах/представлении или нет, и т. Д. ... может помешать вызовам методов рисования ed ...

Примечание: Анимация, эффекты и т. д. могут привести к тому, что эти методы вызовут много, много, много раз, прежде чем область экрана будет полностью готова к отображению и готова к взаимодействию с пользователем.

Личные заметки: Я однажды спустился по этому пути из-за сумасшедших требований клиента, а после того, как я ударил головой по столу в течение некоторого времени, был сделан обзор фактической цели этой области пользовательского интерфейса, и я переписал требование и никогда не пробовал это снова ;-)

+0

- Мне потребовалась минута, чтобы «щелкнуть», но щелкнуть мышью! Я в конечном итоге принимать ваши советы и работает быстро и тяжело от этого подхода. –

2

Я собираюсь ответить на свой вопрос, он надеется, что это решение поможет кому-то, кто борется с этой проблемой в будущем.

Следуйте советам @ SushiHangover и RUN, не проталкивайте от этого что-то подобное. (Хотя его рекомендация будет работать и звучит). Попытка слушать/получать уведомление, когда платформа закончила визуализацию, является ужасной идеей. Как @SushiHangover упоминает, что есть слишком много вещей, которые могут пойти не так.

pin code ui

Так что привело меня на этот путь?

У меня есть требование для пользовательского интерфейса PIN-кода, аналогичного интерфейсу iOS, чтобы разблокировать устройство и во многих других приложениях. Когда пользователь нажимает цифру на пэде, я хочу обновить соответствующий экран «box» (поля над пэдом). Когда пользователь вводит последнюю цифру, я хочу, чтобы последний «ящик» был заполнен, в моем случае изменение цвета фона, а затем выполнение, чтобы продолжить, когда представление перейдет на следующий экран в рабочем процессе.

Проблема возникла, когда я попытался установить свойство BackgroundColor в четвертом поле, а затем перевести экран. Однако, поскольку выполнение не дожидается, когда свойство изменит переходы на экране до того, как будет произведено изменение. Естественно, это создает плохую работу пользователя.

В попытке исправить это я подумал: «О, мне просто нужно получить уведомление, когда представление было визуализировано». Как я уже говорил, я не соображаю.

После просмотра некоторых объективных реализаций C аналогичных пользовательских интерфейсов я понимаю, что это исправить довольно просто. Пользовательский интерфейс должен дождаться краткого момента и разрешить рендеринг свойства BackgroundColor.

Решение

private async Task HandleButtonTouched(object parameter)  
{ 
    if (this.EnteredEmployeeCode.Count > 4) 
     return;   

    string digit = parameter as string; 
    this.EnteredEmployeeCode.Add(digit); 
    this.UpdateEmployeeCodeDigits(); 

    if (this.EnteredEmployeeCode.Count == 4) { 
     // let the view render on the platform 
     await Task.Delay (1); 

     this.SignIn(); 
    } 
} 

Небольшая задержка миллисекунды достаточно, чтобы вид закончил рендеринга без необходимости идти вниз гигантскую кроличью нору и пытаться слушать его.

Еще раз спасибо @SushiHangover за его подробный ответ. Ты потрясающий мой друг! : D

Смежные вопросы