C# 如何将RelativeLayout与依赖于其自身位置大小的控件一起使用?

C# 如何将RelativeLayout与依赖于其自身位置大小的控件一起使用?,c#,xamarin,xamarin.forms,C#,Xamarin,Xamarin.forms,我在布局方面还有很多其他问题,需要大量额外的InvalidateLayout()调用,所以我开始怀疑我是否理解RelativeLayout是如何工作的 下面是一个非常简单的UI示例,它需要右对齐的标签: public class MainPage : ContentPage { public MainPage() { var layout = new RelativeLayout(); var label = new Label() {

我在布局方面还有很多其他问题,需要大量额外的InvalidateLayout()调用,所以我开始怀疑我是否理解RelativeLayout是如何工作的

下面是一个非常简单的UI示例,它需要右对齐的标签:

public class MainPage : ContentPage {
    public MainPage() {
        var layout = new RelativeLayout();

        var label = new Label() {
            Text = "I want to be right-aligned."
        };
        layout.Children.Add(label,
            Constraint.RelativeToParent((rl) => rl.Width - label.Width),
            Constraint.Constant(10));

        var button = new Button() {
            Text = "Invalidate"
        };
        button.Clicked += (object sender, EventArgs e) => layout.ForceLayout();
        layout.Children.Add(button,
            Constraint.Constant(10),
            Constraint.Constant(10));

        Content = layout;
    }
}
我希望这是从正确对齐标签开始的,但在强制另一个布局过程之前,它不会正确对齐标签。通过在自定义控件中重写OnSizeRequest()等方法,我确定这是因为对OnSizeRequest()的调用直到调用RelativeLayout的约束lambdas之后才会发生。因此,当页面布局时,标签的宽度为-1。稍后调用ForceLayout()时,标签有机会执行布局逻辑,并正确设置了Width属性,因此可以正确布局

在更大的背景下,我试图制作一个按钮,当点击时,按钮会淡出,标签会滑入原来的位置。它应该在布局的右下角对齐,但我发现修改不透明度或IsVisible只会不一致地更新布局。唯一一致的行为是RelativeLayout真的喜欢在控件有机会调整自身大小之前询问控件的大小

我是在解释如何使用RelativeLayout时出错了,还是这是逻辑上的错误?

深入研究
RelativeLayout
的(当前)实现,我发现了一个我没有预料到的事实:它没有参考视图的
GetSizeRequest()
方法或调用其
布局()
方法,因为这些约束可能会影响控件的最终大小。结果是:在计算约束时,控件的边界反映了它原来的位置和大小

要“修复”此问题,请在需要控件最新大小的约束内调用视图的GetSizeRequest():

public class MainPage : ContentPage {
    public MainPage() {
        var layout = new RelativeLayout();

        var label = new Label() {
            Text = "I want to be right-aligned."
        };
        Func<RelativeLayout, double> getLabelWidth = (parent) => label.GetSizeRequest(parent.Width, parent.Height).Request.Width;
        layout.Children.Add(label,
            Constraint.RelativeToParent((rl) => rl.Width - getLabelWidth(rl)),
            Constraint.Constant(10));

        var button = new Button() {
            Text = "Invalidate"
        };
        button.Clicked += (object sender, EventArgs e) => layout.ForceLayout();
        layout.Children.Add(button,
            Constraint.Constant(10),
            Constraint.Constant(10));

        Content = layout;
    }
}
public类主页:ContentPage{
公共主页(){
var layout=新的RelativeLayout();
var label=新标签(){
Text=“我想右对齐。”
};
Func getLabelWidth=(parent)=>label.GetSizeRequest(parent.Width,parent.Height).Request.Width;
布局.Children.Add(标签,
Constraint.RelativeToParent((rl)=>rl.Width-getLabelWidth(rl)),
常数(10);
var按钮=新按钮(){
Text=“失效”
};
按钮。单击+=(对象发送者,事件参数)=>layout.ForceLayout();
布局.Children.Add(按钮,
约束常数(10),
常数(10);
内容=布局;
}
}