2016-03-22 25 views
7

是否可以在设置一次后更改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; 
    } 
} 

回答

11

它不正式可能与Xamarin形式的当前版本。 RelativeLayout容器仅在从其子集合中添加/删除项目(缓存解决的约束 - 为性能假设)时才会重新计算约束条件。即使各种约束条件都作为Bindable属性实现,但它们在更改时仍不会重新计算。

我假设意图是有朝一日尊重约束更新,这对于动画比较有用,但现在看起来并不这样。

无论其,我看了一下为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; 
      }); 
    } 
} 
+0

感谢您的出色答案!是否可以将'BoundsConstraint.FromExpression'和'Constraint.RelativeToParent'一起使用?或者你可以只设置'矩形'的值?我想要做的是改变占用屏幕一半的元素的宽度。因此你必须知道父母的身高。目前我正在使用'this.Content.Height',这似乎工作。尽管我必须进一步测试它。 – testing

+1

只要所修改的项目的所有约束都是Constant或RelativeToParent(BoundsConstraint是所有四个x/y /宽度/高度约束的组合,所有这些都必须满足此条件标准)。如果它们中的任何一个使用RelativeToView,则需要将数组中的这些视图作为第二个参数传递给'FromExpression()'。尽管如此,除非您尝试过,否则这种攻击只能用于Constant,但很难说清楚。当然,这取决于内部,因此可能会打破下一个XF版本。 –

+0

我试图使用'RelativeToParent',但努力使用正确的符号。我尝试使用'Constraint.RelativeToParent((parent)=> {return parent.Height;})'而不是常量,但我得到了一个消息,如*太多参数*。你有工作吗? – testing

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 . 
} 
+0

如果'SizeChanged'事件被触发,我可以访问约束?我怎样才能触发'SizeChanged'事件与相应的'RelativeLayout'? – testing

+0

'SizeChanged'事件不提供任何优势,除非可能如果您使用'Grid'来布局和手动定位/调整代码中的内容项目。另外,要触发'SizeChanged'事件,你需要调整容器的大小 - 如果有很多子视图,这可能是一件非常昂贵的事情。 –

+0

@ testing-正如Keith正确指出的那样,当你有很多孩子时,它可以是广泛的工作, 触发事件只是添加任何特定的布局,它会尝试更改容器和事件将被解雇,事件中,你如果可能, 或改变那些将会受到影响的孩子的位置,重写整个亲属布局。想象一种情况(纯粹假设的情况): - 你有一个布局,其上有4个按钮。 你想点击第四个,并获得一个新的btn出现在第四个。 在这种情况下。关于bttn点击事件,你可以触发sizeChange,并在那里做工作 –