Xamarin.Forms: rendering Xamarin.Froms Control in native Dialog - wrap_content is ignored
Let's say I want to display a Xamarin.Froms control (for example Xamarin.Forms.Label
) in a native Android view.
The following code works. But it ignores the width and height of the control ( wrap_content
).
// create a Xamarin.Froms.Label
Xamarin.Forms.Label view = new Xamarin.Forms.Label()
{
Text = "This is a Xamarin.Forms.Label",
BackgroundColor = Color.Red,
};
// create a Renderer
var renderer = Xamarin.Forms.Platform.Android.Platform.CreateRenderer(view);
// create an AlertDialog
var builder = new AlertDialog.Builder(Xamarin.Forms.Forms.Context);
builder.SetView(renderer.ViewGroup); // Use the ViewGroup of the renderer
builder.SetTitle("Dialog");
// create and show the dialog
builder.Create().Show();
Produces the following:
Performing the same action with a native label:
var view = new Android.Widget.TextView(Xamarin.Forms.Forms.Context)
{
Text = "This is a Android.Widget.TextView",
Background = new Android.Graphics.Drawables.ColorDrawable(Android.Graphics.Color.Red),
};
var builder = new AlertDialog.Builder(Xamarin.Forms.Forms.Context);
builder.SetView(view);
builder.SetTitle("Dialog");
builder.Create().Show();
Produces expected output:
I'm looking for any hints or advice regarding measuring width and height in Xamarin.Forms and / or solutions for this kind of problem.
Update
Also note that this is independent of AlertDialog
, using LinearLayout
instead results AlertDialog
for the same behavior.
source to share
The following code works. But it ignores the width and height of the control (wrap_content).
Cause:
You have transferred ViewGroup
to AlertDialog
. But internally, AlertDialog
the layout options ViewGroup
won't work at all. Referring to this blog :
Every rule has an exception
...
The problem here is that AlertDialog.Builder supports a custom view, but does not provide a setView () implementation that accepts a layout resource; so you have to inflate the XML manually. However, since the result will go into a dialog that doesn't expose its root view (it doesn't actually exist yet), we don't have access to the final parent of the layout, so we can't use it for inflation. It turns out it doesn't matter because the AlertDialog will erase any LayoutParams on the layout anyway and replace them with match_parent .
So instead of passing ViewGroup
, pass the view AlertDialog
as your second attempt.
Update (some more research):
if try the following codes to set the height ViewGroup
to 400:
// create a Renderer
var renderer = Xamarin.Forms.Platform.Android.Platform.CreateRenderer(view);
// create an AlertDialog
var builder = new AlertDialog.Builder(Xamarin.Forms.Forms.Context);
renderer.ViewGroup.LayoutParameters = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WrapContent, 400);
builder.SetView(renderer.ViewGroup); // Use the ViewGroup of the renderer
builder.SetTitle("Dialog");
// create and show the dialog
builder.Create().Show();
It doesn't work, the dialog still almost covers the entire screen:
But if you add rendered ViewGroup
in LinearLayout
like this:
var renderer = Xamarin.Forms.Platform.Android.Platform.CreateRenderer(view);
//The following codes works correctly
renderer.ViewGroup.LayoutParameters = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WrapContent, 400);
LinearLayout linearLayout = new LinearLayout(Xamarin.Forms.Forms.Context);
linearLayout.LayoutParameters = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.WrapContent);
linearLayout.AddView(renderer.ViewGroup);
this.AddContentView(linearLayout,new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.WrapContent));
The height is set correctly:
So, at this level, the problem is AlertDialog
, as I mentioned above.
But If the height was set to Wrap_content
like this:
var renderer = Xamarin.Forms.Platform.Android.Platform.CreateRenderer(view);
//set the height again to wrap_content
renderer.ViewGroup.LayoutParameters = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WrapContent, ViewGroup.LayoutParams.WrapContent);
LinearLayout linearLayout = new LinearLayout(this);
linearLayout.LayoutParameters = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.WrapContent);
linearLayout.AddView(renderer.ViewGroup);
this.AddContentView(linearLayout,new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.WrapContent));
rendererd ViewGroup
will start filling the whole screen again:
On this layer I found that the problem is with the renderingViewGroup
because after changing ViewGroup
to native LinearLayout
everything is fine.
I checked the Xamarin.Forms Source Codes and found the following Inherit hierarchy:
Xamarin.Forms.Platform.AndroidLabelRenderer ->
Xamarin.Forms.Platform.Android.ViewRenderer<TView, TNativeView> ->
Xamarin.Forms.Platform.Android.VisualElementRenderer<TElement> ->
Xamarin.Forms.Platform.Android.FormsViewGroup ->
Android.Views.ViewGroup
I found that none of these classes implemented the method ViewGroup.OnMeasure
. Thus, it Wrap_content
will never work. You can refer to Custom ViewGroup for a detailed example of custom implementation ViewGroup
.
source to share
I am answering my own question since this is the simplest way to solve the problem:
Since Xamarin.Forms 2.3.5 (as tentatively written) a new property appears View
next to ViewGroup
in IVisualElementRenderer
.
The solution is to use Xamarin.Froms 2.5.3 and properties View
:
Xamarin.Forms.Label view = new Xamarin.Forms.Label()
{
Text = "This is a Xamarin.Forms.Label",
BackgroundColor = Color.Red,
};
var renderer = Xamarin.Forms.Platform.Android.Platform.CreateRenderer(view);
var builder = new AlertDialog.Builder(Xamarin.Forms.Forms.Context);
builder.SetView(renderer.View); // Use View instead of ViewGroup
builder.SetTitle("Dialog");
builder.Create().Show();
source to share