我注意到,当在类似于BoxView的VisualElement上触发OnElementPropertyChanged时,底层平台视图的属性此时不会更新。
我想知道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中实现。另外,VisualElementRenderer上的UpdateNativeWidget也是如此,但是我无法弄清楚利用它们的正确方法。
有任何想法吗?非常感激。
TL;DR
:逃跑,不要走这条路...
在iOS
所有将内容显示到屏幕上的东西都在UIView
(或子类)内部发生,并且drawRect:
是执行绘图的方法。因此,当drawRect:完成时,UIView
is绘制完成。
注意:动画可能正在发生,您可能会看到数百个完成的渲染周期。您可能需要连接到每个动画的完成处理程序,以确定何时真正完成“渲染”。
注意:绘制是在屏幕外完成的,并且取决于iDevice,屏幕刷新频率可能为30FPS,60FPS,或者在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
或子类,你可以得到一个表面,通过OpenGL画/比尔特到屏幕上,等...这力量不是内的View
,但对于您的使用情况,认为View
秒。 。
View
s具有Draw
可以重写的方法,还可以挂接ViewTreeObserver
并监视OnPreDraw
和OnDraw
,等等等等等...有时,您必须监视视图的父级(ViewGroup
)才能确定何时完成绘制或何时完成绘制。
同样,所有标准Widget都通过xml资源完全膨胀,并且已进行了优化,因此您将永远不会看到Draw / OnDraw方法调用(注意:OnPreDraw
如果强制执行,则应该始终(?)获得监听器调用)。
不同的View
s / Widget
s的行为不同,并且无法复查您将确定“ a 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
其他:
注意:布局优化,内容缓存,GPU缓存,是否在Widget / View中启用了硬件加速等,这可以防止Draw方法被调用...
注意:动画,效果等...可能导致这些方法在屏幕上的某个区域完全完成显示并可以进行用户交互之前被调用很多很多次。
个人说明:由于疯狂的客户要求,我曾经走过这条路,在把头撞在桌子上一段时间后,对UI区域的实际目标进行了回顾,然后我重新编写了要求,再也没有尝试过;-)