无限约束
现在这里有一些标记,起初看起来与前面的例子非常相似,但有很大的不同:
<ContentPage __ Padding="20">
<StackLayout>
<Label Text="Sample text" />
__
</StackLayout>
</ContentPage>
ContentPage仍然使用参数(0,0,360,640)进行初始布局调用,而LayoutChildren覆盖的参数是(20,20,320,600)。它有一个孩子,StackLayout。 StackLayout具有LayoutOptions.Fill的HorizontalOptions和VerticalOptions的默认设置,这意味着StackLayout可以相对于ContentPage定位,布局调用为(20,20,320,600)。
这导致StackLayout获得一个参数为(0,0,320,600)的LayoutChildren调用。 StackLayout如何确定其子女的大小和位置?
正如我们从第4章开始使用StackLayout所知道的那样,垂直StackLayout为其子级提供与其自身相同的水平大小,但是根据子级需要提供垂直大小。这意味着StackLayout必须在调用Layout之前在其所有子节点上调用GetSizeRequest。但是它应该用GetSizeRequest调用指定什么约束?
最初的冲动可能是StackLayout在其子节点上调用GetSizeRequest,其约束条件反映了它自己的大小(320,600)。但那不对。 StackLayout不会将其子项限制在自己的高度。它允许孩子成为他们需要的任何高度。这意味着高度约束实际上应该是无限的。
这是事实。 StackLayout在其子节点上调用GetSizeRequest,其高度为(320,∞),或者就.NET而言(320,Double.PositiveInfinity)。
这很重要:传递给GetSizeRequest和OnSizeRequest的约束可以从0到Double.PositiveInfinity。 但是,GetSizeRequest和OnSizeRequest永远不会通过返回SizeRequest值并将属性设置为Double.PositiveInfinity来请求无限维。
让我们尝试另一种常见的布局模式:
<ContentPage __ Padding="20">
<ScrollView>
<StackLayout>
<Label Text="Sample text" />
__
</StackLayout>
</ScrollView>
</ContentPage>
像往常一样,ContentPage使用边界矩形(0,0,360,640)调用Layout,并调用其参数为(20,20,320,600)的LayoutChildren方法。 ScrollView具有LayoutOptions.Fill的默认HorizontalOptions和VerticalOptions设置,因此页面不需要知道ScrollView的大小。该页面简单地调用ScrollView的Layout方法,其边界矩形为(20,20,320,600)。
然后ScrollView调用其LayoutChildren方法,参数为(0,0,320,600)。它需要确定其子项的大小(StackLayout),因此它调用StackLayout的GetSizeRequest方法。约束应该是什么?
在一般情况下,StackLayout的高度将大于ScrollView的高度。这就是为什么你在可视树中包含ScrollView的原因!如果要成功滚动其子项,ScrollView需要知道该高度。因此,ScrollView使用(320,Double.PositiveInfinity)的约束调用StackLayout的GetSizeRequest方法。这转换为使用相同的约束参数调用OnSizeRequest,StackLayout覆盖并处理这些参数。
您还可以将无限约束视为自动调整指示。垂直StackLayout请求具有无限高度约束的子大小以获取子请求的高度。类似地,行高或行宽为GridLength.Auto的Grid单元格的子节点将看到无限的heightConstraint或widthConstraint,或两者。具有LayoutBounds高度或宽度Auto的AbsoluteLayout的子项也将看到无限的heightConstraint或widthConstraint。
有时,受约束和不受约束的词语用于指代这些差异。当元素接收到具有非无限参数的GetSizeRequest方法的调用时,它会受到约束。该元素被约束为特定大小。当一个元素调用GetSizeRequest并且一个或两个参数等于Double.PositiveInfinity时,该元素是不受约束的。有时,部分约束这个术语用于引用带有一个Double.PositiveInfinity参数的GetSizeRequest调用,而术语完全约束则表明两个参数都不是无限的。
通过从Layout 派生编写自己的自定义布局类时,必须覆盖OnSizeRequest和LayoutChildren方法,并且必须注意在某些情况下,OnSizeRequest的一个或两个约束参数将为Double.PositiveInfinity。 但是,OnSizeRequest绝不能请求无限大小。