Xamarin.Forms:之后更改RelativeLayout约束

时间:2016-03-22 17:15:06

标签: c# layout xamarin relativelayout xamarin.forms

是否可以在设置一次后更改RelativeLayout的约束?

在文档中我看到像GetBoundsConstraint(BindableObject)这样的方法,但我认为只有拥有XAML文件才能使用它们。现在我正在尝试在代码中执行此操作。如果我尝试

,我会null
RelativeLayout.GetBoundsConstraint(this.label);

我发现的唯一方法是从布局中删除子项并再次使用新约束添加它。

示例:

public class TestPage : ContentPage
{
    private RelativeLayout relativeLayout;
    private BoxView view;
    private bool moreWidth = false;

    public TestPage()
    {
        this.view = new BoxView
        {
            BackgroundColor = Color.Yellow,
        };

        Button button = new Button
        {
            Text = "change",
            TextColor = Color.Black,
        };

        button.Clicked += Button_Clicked;

        this.relativeLayout = new RelativeLayout();

        this.relativeLayout.Children.Add(this.view,
            Constraint.Constant(0),
            Constraint.Constant(0),
            Constraint.Constant(80),
            Constraint.RelativeToParent((parent) =>
            {
                return parent.Height;
            }));

        this.relativeLayout.Children.Add(button,
            Constraint.RelativeToParent((parent) =>
            {
                return parent.Width / 2;
            }),
            Constraint.RelativeToParent((parent) =>
            {
                return parent.Height / 2;
            }));

        this.Content = this.relativeLayout;
    }

    private void Button_Clicked(object sender, EventArgs e)
    {
        double width = 0;
        if(this.moreWidth)
        {
            width = 120;
        }
        else
        {
            width = 80;
        }
        var c= BoundsConstraint.FromExpression((Expression<Func<Rectangle>>)(() => new Rectangle(0, 0, width, this.Content.Height)), new View[0]);
        RelativeLayout.SetBoundsConstraint(this.view, c);
        this.relativeLayout.ForceLayout();
        this.moreWidth = !this.moreWidth;
    }
}

3 个答案:

答案 0 :(得分:12)

当前版本的Xamarin Forms不能正式RelativeLayout容器仅在从子集合中添加/删除项目时重新计算约束(它缓存已解决的约束 - 可能需要性能)。尽管各种约束都是作为Bindable Properties实现的,但在更改时仍然无法重新计算。

我认为目的是有朝一日尊重约束更新,例如,这对于动画很有用,但是现在它看起来并不像那样。

HOWEVER ,我看了一下RelativeLayout的反编译源代码, 可以通过它来解决它 - 但它可能不适合你的需求,具体取决于您需要多少功能以及约束定义的复杂程度。

请参阅此示例代码(关键部分是使用SetBoundsConstraint设置约束,它会覆盖添加的视图的内部计算边界 - 然后调用ForceLayout()):

public partial class App : Application
{
    public App ()
    {
        var label = new Label {
            Text = "Test",
            HorizontalTextAlignment = TextAlignment.Center,
            VerticalTextAlignment = TextAlignment.Center,
            BackgroundColor = Color.Silver
        };
        var layout = new RelativeLayout ();
        layout.Children.Add (label,
            Constraint.Constant (50),
            Constraint.Constant (100),
            Constraint.Constant (260),
            Constraint.Constant (30));
        MainPage = new ContentPage {
            Content = layout
        };

        var fwd = true;
        layout.Animate ("bounce",
            (delta) => {
                var d = fwd ? delta : 1.0 - delta;
                var y = 100.0 + (50.0 * d);
                var c = BoundsConstraint.FromExpression ((Expression<Func<Rectangle>>)(() => new Rectangle (50, y, 260, 30)), new View [0]);
                RelativeLayout.SetBoundsConstraint(label, c);
                layout.ForceLayout ();
            }, 16, 800, Easing.SinInOut, (f, b) => {
                // reset direction
                fwd = !fwd;
            }, () => {
                // keep bouncing
                return true;
            });
    }
}

答案 1 :(得分:1)

如果我理解正确,我会尝试以下

为relativeLayout实现SizeChanged事件

喜欢: -

var relativeLayout = new RelativeLayout ();

relativeLayout.SizeChanged += someEventForTesting;

并在您想要调整相对布局或某个特定子项的大小时调用该事件。

public void someEventForTesting(Object sender , EventArgs)
{
var layout = (RelativeLayout)sender ;
//here you have access to layout and every child , you can add them again with new constraint .
}

答案 2 :(得分:0)

是的。这可能。 布局代码:

<StackLayout RelativeLayout.XConstraint="{Binding XConstaint}" ...>

VM代码:

public Constraint XConstaint
{
  get => _xConstaint;
  set { SetFieldValue(ref _xConstaint, value, nameof(XConstaint)); }
}

public override void OnAppearing()
{
  base.OnAppearing();
  XConstaint = Constraint.RelativeToParent((parent) => { return parent.Width - 128; });
}