How to add Xamarin Forms content as a subview in X

2019-04-12 05:42发布

问题:

We have a "legacy" Xamarin.Android and Xamarin.iOS project. We would like to inject a Xamarin Forms component as a subview into a "native" Android and iOS view. The component is only available as a Xamarin Forms component and it is too expensive rewrite the entire app to Xamarin.Forms.

The main question is how can we add complex Xamarin.Forms layouts as a subview in a "native" Xamarin.Android or Xamarin.iOS view?

We have done some proof of concept work, and have successfully injected a XF third party component as a single Xamarin Forms element. However, this technique does not fully work when we inject a layout with children elements as eg a StackLayout.

The central pieces of code is e.g in MainActivity.cs and ViewController.cs

MainActivity.cs:

    protected override void OnCreate (Bundle savedInstanceState)
    {
        base.OnCreate (savedInstanceState);
        Xamarin.Forms.Forms.Init (this, savedInstanceState);
        SetContentView (Resource.Layout.Main);

        _stackedLabels = new StackedLabels ();
        var renderer = Xamarin.Forms.Platform.Android.Platform.CreateRenderer (_stackedLabels.LabelStack);  // LabelStack is a StackLayout

        var rootLayout = this.FindViewById<LinearLayout> (Resource.Id.root);
        rootLayout.AddView (renderer.ViewGroup);

    }

ViewController.cs:

    public override void ViewDidLoad ()
    {
        base.ViewDidLoad ();

        _stackedLabels = new StackedLabels ();
        var renderer = Xamarin.Forms.Platform.iOS.Platform.CreateRenderer (_stackedLabels.LabelStack);  // LabelStack is a StackLayout

        var rootLayout = this.View;
        rootLayout.Add (renderer.NativeView);

        renderer.NativeView.Frame = this.View.Bounds;
        renderer.SetElementSize (new Xamarin.Forms.Size (this.View.Bounds.Width, this.View.Bounds.Height)); // Companion method not found for Android since we do not know exact size in the Android activity OnCreate method.
    }

Here, we create a renderer and adds the "native view/view group" manually to the iOS root view present in the view controller or the Android layout which is loaded by the activity.

Expected result would be that the entire StackLayout is displayed with its children. However, none of the children are visible.

We think this has do with how Xamarin.Forms calculates sizes for the VisualElements in the StackLayout, but we have not succeded to trigger this calculation.

We also note that the iOS renderer sucessfully computes sizes when WidthRequest and HeigthRequest is added to the childs of StackLayout, but not when only HorizontalOptions and VerticalOptions are set.

The main question is how can we add complex layouts as a subview in a "native" Xamarin.Android or Xamarin.iOS view?