2017-01-25 3 views
2

OnElementPropertyChangedがBoxViewのようなVisualElementで起動されたとき、その時に基底のプラットフォームビューのプロパティは更新されていないことに気付きました。ビューのレンダリングが完了したら、どうすればわかりますか?

は私がVisualElementの対応プラットフォームビューがレンダリング終了したときに、何かを知りたい:Xamarin.Forms、すなわちVisualElementRenderer.csの内部にいくつかのコードを探し

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

を、そのIを思わ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クラスにイベントを追加することにあります。しかし、私はあなたが私が何をしているかを見ることができると思います。

私は、IsInNativeLayoutのようなVisualElementのプロパティに注目しました。しかし、それはWin/WP8で実装されているようです。また、VisualElementRendererのUpdateNativeWidgetについても、私はそれらを活用する適切な方法を理解できません。

アイデア? 非常に高く評価されています。

答えて

2

TL;DR:離れて実行し、この道を行っていない...画面にコンテンツを表示する

iOS上のすべてのものは、UIView(またはサブクラス)の中に起こるとdrawRect:は、描画を行う方法です。したがって、drawRect:が完了すると、UIViewが描画されます。

注:アニメーションが発生している可能性があり、完了した描画サイクルが数百回完了していることがあります。実際に「レンダリング」がいつ行われるかを判断するには、すべてのアニメーションの補完ハンドラにフックする必要があります。

注:図面をオフスクリーン行わとのiDeviceに応じされ、画面がHzの可能性30FPS、60FPSまたはiPadプロそれが可変である(30-60hz)の場合にはリフレッシュ...

例:

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

コンテンツを描画する共通方法はViewまたはサブクラス経由で、あなたが画面にOpenGLの経由/ BILTを描き、表面を得ることができ、等...とない可能性があることView内であるが、y私たちのユースケース、View Sを考える。..

View sがあなたがオーバーライドできるDrawメソッドを持って、あなたはまた、など、など、など、ViewTreeObserverにフックとOnPreDrawOnDrawを監視することができます...時にはあなたが監視する必要がありますビューの親(ViewGroup)を使用して、いつ描画を行うか、いつ終了するかを決定します。

また、すべての標準ウィジェットはxmlリソースで完全に膨らんでおり、描画/オンドローメソッドコールが表示されないように最適化されています(注:強制的には、OnPreDrawリスナーコールが常に得られます)。

異なるView 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}"); 
     } 
    } 

} 

その他:

注:レイアウトの最適化、コンテンツキャッシュ、GPUキャッシュ、ウィジェット/ビューでのハードウェアアクセラレーションなどは、Drawメソッドが呼び出されないようにすることができますこれらのメソッドは、と多くの、多くの、多くの時間を呼び出して、画面の領域が完全に表示され、ユーザーが操作できるようにすることができます。

個人的な注意:私はこのクライアントの要求に狂い、デスク上で頭を撫でた後、UIのその領域の実際の目標のレビューを行いました。

+0

- 「クリック」するのに1分かかりましたが、クリックしました。私はあなたのアドバイスを取って、このアプローチから速くて頑張ってしまいました。 –

2

私は自分自身の疑問に答えるつもりですが、この問題が今後この問題に苦労している人に役立つことを願っています。

@ SushiHangoverのアドバイスとRUNに従って、このようなことをしないでください。 (彼の推薦はうまくいくが健全だが)。プラットフォームがビューのレンダリングを完了したときに、リッスン/通知を試みるのはひどい考えです。 @SushiHangoverには、単に間違ってしまうことが多すぎることが書かれています。

pin code ui

だから何がこのパスを私を倒さ?

私はあなたのデバイスをロック解除するためのiOSのものと同様のピンコードUIと他の多くのアプリが必要です。ユーザーがパッド上の数字を押すと、対応するディスプレイ "ボックス"(パッドの上のボックス)を更新したいと考えています。ユーザーが最後の桁を入力すると、最後の "ボックス"を入力したい場合は、私の場合は背景色を変更し、ワークフローの次の画面に移行するために実行を続行します。

4番目のボックスにBackgroundColorプロパティを設定してから画面を移行しようとすると、問題が発生しました。しかし、実行は、変更がレンダリングされる前にプロパティが画面遷移を変更するのを待つことがないためです。もちろん、これは悪いユーザーエクスペリエンスになります。

これを修正するために、「ああ、ビューがレンダリングされたときに通知する必要がある」と思った。私が言及したように、スマートではありません。

類似のUIのいくつかの客観的なC実装を見た後、私はそれを非常に簡単に修正することを認識しています。 UIはしばらく待ってから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

関連する問題