我在StackLayout中嵌套了RelativeLayouts有一个奇怪的问题,看来StackLayout计算其元素的宽度应该使用RelativeLayout宽度,然后RelativeLayout再次重新计算它。这导致子控件是相对宽度的平方,但是下面的控件被放置为相对宽度。
这是一个错误还是我做错了什么?
例如
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage x:Class="MyClass"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
>
<StackLayout Orientation="Horizontal" BackgroundColor="Blue">
<RelativeLayout>
<ContentView BackgroundColor="Red"
RelativeLayout.XConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Width,
Factor=0}"
RelativeLayout.WidthConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Width,
Factor=0.707106}"
RelativeLayout.YConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Height,
Factor=0}"
RelativeLayout.HeightConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Height,
Factor=1}">
</ContentView>
</RelativeLayout>
<RelativeLayout>
<ContentView BackgroundColor="Green"
RelativeLayout.XConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Width,
Factor=0}"
RelativeLayout.WidthConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Width,
Factor=0.5}"
RelativeLayout.YConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Height,
Factor=0}"
RelativeLayout.HeightConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Height,
Factor=1}">
</ContentView>
</RelativeLayout>
</StackLayout>
</ContentPage>
答案 0 :(得分:6)
两个RelativeLayout
元素可能是一个令人困惑的因素,并且每个元素都被指定为相对于父StackLayout
位于X位置0,这似乎是一个冲突。
从评论中可以看出,如果预期每个RelativeLayout
都是父StackLayout
宽度的一半,则可以通过消除其中一个RelativeLayout
元素来简化布局。 / p>
然后可以将子条带的指定宽度除以2,使得每个子条带的宽度相对于父StackLayout
的预期宽度,并且相对于父级设置的X位置也将它们水平放置
以下是我提出的建议:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage x:Class="App1.HomePage"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
>
<StackLayout Orientation="Horizontal" BackgroundColor="Blue">
<RelativeLayout>
<ContentView BackgroundColor="Red"
RelativeLayout.XConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Width,
Factor=0}"
RelativeLayout.WidthConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Width,
Factor=0.35}"
RelativeLayout.YConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Height,
Factor=0}"
RelativeLayout.HeightConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Height,
Factor=1}">
</ContentView>
<!--
</RelativeLayout>
<RelativeLayout>
-->
<ContentView BackgroundColor="Green"
RelativeLayout.XConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Width,
Factor=0.5}"
RelativeLayout.WidthConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Width,
Factor=0.25}"
RelativeLayout.YConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Height,
Factor=0}"
RelativeLayout.HeightConstraint=
"{ConstraintExpression Type=RelativeToParent,
Property=Height,
Factor=1}">
</ContentView>
</RelativeLayout>
</StackLayout>
</ContentPage>
这会产生更接近预期的东西吗?
答案 1 :(得分:2)
没有任何内容定位或覆盖任何指定的值。
这不太正确。只要看一眼,红色乐队看起来与第一个蓝色乐队的宽度大约是7:3。换句话说,这是第一个RelativeLayout。第二个RelativeLayout部分被推离屏幕,但它看起来像第二个ContentView完全在屏幕上,并且与前两个波段成比例地进行了褶皱 - 即绿色波段与红色波段的比例大约为5:7
换句话说,两个RelativeViews确实获得了相等的空间分配,两个ContentView完全在屏幕上。但是,两个RelativeLayouts的总宽度大于屏幕的宽度!
您可以在此处查看StackLayout的源代码: https://github.com/xamarin/Xamarin.Forms/blob/master/Xamarin.Forms.Core/StackLayout.cs
和RelativeLayout在这里: https://github.com/xamarin/Xamarin.Forms/blob/master/Xamarin.Forms.Core/RelativeLayout.cs。
我没有详细介绍过所有内容,但StackLayout有两个布局,首先尝试做一个“天真”的布局,希望所有的孩子都适合。如果没有,它将通过压缩传递。由于RelativeLayout子节点没有指定任何宽度,因此它们最初尝试抓取父节点的整个宽度,并从那里进行压缩。
基本上它归结为这是一个来自Xamarin.Forms视角的欠约束系统。像这样使用StackLayout,没有任何东西给父母或孩子一个特定的宽度,可能会导致令人惊讶的结果。对于这样的情况,您不需要动态布局,其他布局(如Grid)可以提供更可预测的结果。
修改强>
经过进一步调查,如果你有一个包含多个子节点的StackLayout,包括一个(或多个)没有宽度规范的RelativeLayout,你可能做错了。其中一部分是有道理的,但您也看到了可疑(IMO)设计决策的症状。
默认情况下,RelativeLayout假定它的宽度与其父级相同。 StackLayout有一个多阶段的过程,先做一个Measure传递,然后是一个Layout传递,最后是一个压缩传递(在这种情况下实际上不会发挥作用)。在测量期间,RelativeLayout计算出实际布置其子项所需的空间。对于第一个RelativeLayout,这意味着它需要其父节点总宽度的大约70%(即总屏幕宽度的70% - 我忽略了小数量)。下一个RelativeLayout表示它需要总宽度的50%。
然后是布局传递。第一个RelativeLayout被给予它所要求的70%,因此它将其子项列出,这将是其中的70%(同意您的观察结果)。第二个RelativeLayout给出了它要求的50%,并将其50%分配给它的孩子。是的,这意味着StackLayout分配的屏幕宽度超过100%。当然它只显示前100%。
所以Xamarin.Forms的布局方式似乎有点奇怪,但我也不确定你对所需解决方案的限制。
假设您需要在StackLayout下拥有多个RelativeLayout兄弟,请按照这些说明获取您想要的内容:
填充每个RelativeLayout的整个宽度,即使它只是一个空的ContentView。如果不这样做,上面描述的测量/布局通过将导致严重的麻烦。
为每个RelativeLayout分配一个小的MinimumWidthRequest和一个包括Expand的HorizontalOptions。这将允许压缩传递(如上所述)启动,并为每个RelativeLayout提供相同的宽度分配。在测试中,我使用了MinimumWidthRequest =“20”和HorizontalOptions =“StartAndExpand”,并且工作正常。
这样做会为Xamarin.Forms布局引擎提供足够的约束,使其按照您期望的方式运行。