C# Forms:随后更改RelativeLayout约束
是否可以在设置一次约束后更改约束 在文档中我看到了像C# Forms:随后更改RelativeLayout约束,c#,xamarin,layout,xamarin.forms,C#,Xamarin,Layout,Xamarin.forms,是否可以在设置一次约束后更改约束 在文档中我看到了像GetBoundsConstraint(BindableObject)这样的方法,但我认为只有在拥有XAML文件的情况下才能使用它们。目前,我正试图在代码中实现这一点。如果我尝试,我会得到null RelativeLayout.GetBoundsConstraint(this.label); 我发现的唯一方法是从布局中删除子项,然后再次添加新约束 示例: public class TestPage : ContentPage { pr
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;
}
}
public类测试页:ContentPage
{
私人亲戚;
私有BoxView视图;
private bool moreWidth=false;
公共测试页()
{
this.view=new-BoxView
{
背景颜色=颜色。黄色,
};
按钮=新按钮
{
Text=“更改”,
TextColor=Color.Black,
};
按钮。点击+=按钮\点击;
this.relativeLayout=新的relativeLayout();
this.relativeLayout.Children.Add(this.view,
约束常数(0),
约束常数(0),
约束常数(80),
约束。RelativeToParent((父项)=>
{
返回父项高度;
}));
此.relativeLayout.Children.Add(按钮,
约束。RelativeToParent((父项)=>
{
返回父项宽度/2;
}),
约束。RelativeToParent((父项)=>
{
返回父项高度/2;
}));
this.Content=this.relativeLayout;
}
已单击私有无效按钮(对象发送者,事件参数e)
{
双倍宽度=0;
如果(此.moreWidth)
{
宽度=120;
}
其他的
{
宽度=80;
}
var c=BoundsConstraint.FromExpression((表达式)(()=>新矩形(0,0,width,this.Content.Height)),新视图[0]);
RelativeLayout.SetBoundsConstraint(this.view,c);
此.relativeLayout.ForceLayout();
this.moreWidth=!this.moreWidth;
}
}
对于当前版本的Xamarin表单,官方不允许这样做。RelativeLayout
容器仅在从其子集合中添加/删除项时重新计算约束(它缓存已解决的约束-可能是为了性能)。即使各种约束被实现为可绑定属性,它们在更改时仍然不会重新计算
我假设其目的是为了有一天尊重约束更新,例如,这对动画很有用,但目前看来它似乎不是这样工作的
然而,我查看了RelativeLayout的反编译源代码,可以找到一种解决方法-但它可能不适合您的需要,这取决于您需要多少功能以及约束定义有多复杂
请参阅此示例代码(关键部分是使用SetBoundsConstraint设置约束,该约束覆盖添加视图的内部计算边界,然后调用ForceLayout()
):
公共部分类应用程序:应用程序
{
公共应用程序()
{
变量标签=新标签{
Text=“测试”,
HorizontalTextAlignment=TextAlignment.Center,
VerticalTextAlignment=TextAlignment.Center,
背景颜色=颜色。银色
};
var布局=新的RelativeLayout();
layout.Children.Add(标签,
约束常数(50),
约束常数(100),
约束常数(260),
常数(30);
主页=新内容页{
内容=布局
};
var fwd=真;
布局。动画(“反弹”,
(增量)=>{
var d=fwd?增量:1.0-增量;
变量y=100.0+(50.0*d);
var c=BoundsConstraint.FromExpression((表达式)(()=>新矩形(50,y,260,30)),新视图[0]);
相对立根约束(标签c);
layout.ForceLayout();
},16800,Easing.SinInOut,(f,b)=>{
//重置方向
fwd=!fwd;
}, () => {
//继续跳
返回true;
});
}
}
如果我理解正确,我会尝试以下方法
为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 .
}
对。这是可能的。
布局代码:
<StackLayout RelativeLayout.XConstraint="{Binding XConstaint}" ...>
谢谢你的回答!是否可以将
BoundsConstraint.FromExpression
与Constraint.RelativeToParent
一起使用?或者只能为矩形设置值?我想做的是改变占据屏幕一半的元素的宽度。因此,您必须知道父级高度。目前我正在使用this.Content.Height
,这似乎很有效。尽管我必须进一步测试它。只要您要修改的项上的所有约束都是常量或相对父项(BoundsConstraint是所有四个x/y/宽度/高度约束的组合,因此所有这些约束都必须满足此标准),它就应该可以工作。如果其中任何一个使用RelativeToView,则需要将这些视图作为第二个参数在数组中传递给FromExpression()
。不过,除非您尝试一下,否则很难确定这种破解方法是否适用于常数以外的任何东西。当然,这取决于内部结构,所以在下一个XF版本中可能会出现中断。我尝试使用RelativeToParent
,但难以使用正确的表示法。我尝试使用Constraint.RelativeToParent((parent)=>{return parent.Height;})代替常量
<StackLayout RelativeLayout.XConstraint="{Binding XConstaint}" ...>
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; });
}