(每次学习一点xamarin就做个学习笔记和视频来加深记忆巩固知识)
如有不正确的地方,请帮我指正。
Autolayout简介
Autolayout是一种自动布局技术,很方便进行屏幕适配。在这之前有Autoresizing技术,但只能设置控件自己和父控件之间的位置关系,有点类似于Winform中的Anchor。而Autolayout可以设置任意控件之间的位置关系。
Autolayout原理
原理就是通过公式 View1.Property = (View2.Property * multiplier) + constant 最终得到Frame值(X,Y,Width,Height)。
视图1的属性值 = (视图2的属性值乘以乘数)加上一个常量值。
举几个例子:
例A:UIImageView的宽为150,高为150,距离UIView的左边和上边都是10。那么:
imageView.Width=(0 * 1.0)+150
imageView.Height=(0 * 1.0)+150
imageView.X=(UIView.Left*1.0)+10
imageView.Y=(UIView.Top*1.0)+10
例B:UILabel的上边距离图片是7,下边距离UIView是8,左边距离UIView是10,右边距离UIView的右边是16。那么:
label.Y=(imageView.Bottom*1.0)+7
label.Height=((UIView.Bottom*1.0-8) – label.Y
label.X=(UIView.Left*1.0)+10
label.Width=(UIView.Right*1.0-16) – label.X
例C:UILabel的宽永远等于UIView的宽的一半。那么:
label.Width=(UIView.Width*0.5)+0
Autolayout基本使用
例如要实现下图这样的布局:
条件如下:
1. 有三个控件,图片控件UIImageView,文本控件UILabel,和它俩的父控件灰色的UIView。
2. UIImageView的宽为150,高为150,距离UIView的左边和上边都是10。
3. UILabel的上边距离图片是7,下边距离UIView是8,左边距离UIView是10,右边距离UIView的右边是16,宽度则是跟随UIView的宽度自动变化,高度则跟随文本内容自动变化。
4. UIView距离屏幕的左和右都是20,宽度跟随屏幕宽度自动变化,高度则跟随它里面的子控件的高度自动变化,即刚好包住它们。距离屏幕上边暂时随变吧。
1. 通过界面设计工具来布局
首先查看storyboard的属性,默认是勾选了“UseAutoLayout”的。
还得注意要加如下代码 //因为默认会有Autoresizing设置,所以要禁止IOS把默认的Autoresizing转成约束 grayView.TranslatesAutoresizingMaskIntoConstraints = false; imageView.TranslatesAutoresizingMaskIntoConstraints = false; label.TranslatesAutoresizingMaskIntoConstraints = false;
分别拖三个控件并调好大概的位置。第一步是切换到约束编辑模式,下图少了一个“模”字。第二步则进行相关拖线来设置约束。第三步在Layout栏可看到结果,可以点击设置图标来进行修改或删除约束。
在使用下面三个方式之前先做好准备工作,通过代码先添加好三个控件
//1.添加灰色View UIView grayView2 = new UIView(); grayView2.BackgroundColor = UIColor.Gray; grayView2.Frame = new CGRect(0, 400, 300, 300); this.View.AddSubview(grayView2); //2.添加图片View UIImage image = UIImage.FromBundle("a1"); UIImageView imageView2 = new UIImageView(image); imageView2.BackgroundColor = UIColor.Cyan; imageView2.Frame = new CGRect(0, 0, 150, 150); grayView2.AddSubview(imageView2); //3.添加文本View UILabel label2 = new UILabel(); label2.BackgroundColor = UIColor.White; label2.Frame = new CGRect(5, imageView2.Frame.Size.Height + 7, 200, 20); label2.Text = "BookName"; label2.Font = UIFont.SystemFontOfSize(UIFont.LabelFontSize, UIFontWeight.Bold); label2.Lines = 0;//设置允许自动换行 grayView2.AddSubview(label2); _label2 = label2; //默认会有Autoresizing设置,禁止IOS把默认的Autoresizing转成约束 grayView2.TranslatesAutoresizingMaskIntoConstraints = false; imageView2.TranslatesAutoresizingMaskIntoConstraints = false; label2.TranslatesAutoresizingMaskIntoConstraints = false;
2. 通过NSLayoutConstraint类来布局
直接上代码//4添加grayView2的约束 //4.1添加X值约束 NSLayoutConstraint grayView2CT_X = NSLayoutConstraint.Create(grayView2, NSLayoutAttribute.Left, NSLayoutRelation.Equal , this.View, NSLayoutAttribute.Left, 1.0F, 20); this.View.AddConstraint(grayView2CT_X); //4.2添加Y值约束 NSLayoutConstraint grayView2CT_Y = NSLayoutConstraint.Create(grayView2, NSLayoutAttribute.Top, NSLayoutRelation.Equal , this.View, NSLayoutAttribute.Top, 1.0F, 300); this.View.AddConstraint(grayView2CT_Y); //4.3添加Width约束(因为有X值约束了,所以再来个Trailing就行了) NSLayoutConstraint grayView2CT_Trailing = NSLayoutConstraint.Create(grayView2, NSLayoutAttribute.Trailing, NSLayoutRelation.Equal , this.View, NSLayoutAttribute.Trailing, 1.0F, -20); this.View.AddConstraint(grayView2CT_Trailing); //4.4添加Height约束 //不需添加高约束,因为可以根据里面的imageView和label自动计算出来 //5.添加imageView2的约束 //4.1添加X值约束 NSLayoutConstraint imageView2CT_X = NSLayoutConstraint.Create(imageView2, NSLayoutAttribute.Left, NSLayoutRelation.Equal , imageView2.Superview, NSLayoutAttribute.Left, 1.0F, 10); grayView2.AddConstraint(imageView2CT_X); //5.2添加Y值约束 NSLayoutConstraint imageView2CT_Y = NSLayoutConstraint.Create(imageView2, NSLayoutAttribute.Top, NSLayoutRelation.Equal , imageView2.Superview, NSLayoutAttribute.Top, 1.0F, 10); grayView2.AddConstraint(imageView2CT_Y); //5.3添加Width约束 NSLayoutConstraint imageView2CT_W = NSLayoutConstraint.Create(imageView2, NSLayoutAttribute.Width, NSLayoutRelation.Equal , null, NSLayoutAttribute.NoAttribute, 1.0F, 150); imageView2.AddConstraint(imageView2CT_W); //5.4添加Height约束 NSLayoutConstraint imageView2CT_H = NSLayoutConstraint.Create(imageView2, NSLayoutAttribute.Height, NSLayoutRelation.Equal , null, NSLayoutAttribute.NoAttribute, 1.0F, 150); imageView2.AddConstraint(imageView2CT_H); //6.添加label2的约束 //6.1添加X值约束 NSLayoutConstraint label2CT_X = NSLayoutConstraint.Create(label2, NSLayoutAttribute.Left, NSLayoutRelation.Equal , label2.Superview, NSLayoutAttribute.Left, 1.0F, 10); grayView2.AddConstraint(label2CT_X); //6.2添加Y值约束 NSLayoutConstraint label2CT_Y = NSLayoutConstraint.Create(label2, NSLayoutAttribute.Top, NSLayoutRelation.Equal , imageView2, NSLayoutAttribute.Bottom, 1.0F, 7); grayView2.AddConstraint(label2CT_Y); //6.3添加Width约束(因为有X值约束了,所以再来个Trailing就行了) NSLayoutConstraint label2CT_Trailing = NSLayoutConstraint.Create(label2, NSLayoutAttribute.Trailing, NSLayoutRelation.Equal , label2.Superview, NSLayoutAttribute.Trailing, 1.0F, -16); grayView2.AddConstraint(label2CT_Trailing); //6.4添加Height约束所以再来个Bottom就行了(因为有Y值约束了,所以再来个Bottom就行了) NSLayoutConstraint label2CT_Bottom = NSLayoutConstraint.Create(label2, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal , label2.Superview, NSLayoutAttribute.Bottom, 1.0F, -8); grayView2.AddConstraint(label2CT_Bottom);
3. 通过VFL(VisualFormatLanguage可视化格式语言)来布局
直接上代码。
NSDictionary viewDict = NSDictionary.FromObjectsAndKeys(new UIView[] { grayView2, imageView2, label2 }, new string[] { "grayView", "imageView", "label" }); string grayView2VFL_H = "H:|-20-[grayView]-20-|";//距父控件左边和右边都是20(X值和With值也就确定了) string grayView2VFL_V = "V:|-350-[grayView]"; //距父控件上边是350,下边自动计算(Y值和Height值也就确定了) NSLayoutConstraint[] grayView2VFLArray_H=NSLayoutConstraint.FromVisualFormat(grayView2VFL_H, 0 , null, viewDict); NSLayoutConstraint[] grayView2VFLArray_V =NSLayoutConstraint.FromVisualFormat(grayView2VFL_V,0 ,null, viewDict); this.View.AddConstraints(grayView2VFLArray_H); this.View.AddConstraints(grayView2VFLArray_V); string imageView2VFL_H = "H:|-10-[imageView(150)]";//距父控件左边为10,自已宽为150(X值和With值也就确定了) string imageView2VFL_V = "V:|-10-[imageView(150)]";//距父控件上边是10,自已高为150(Y值和Height值也就确定了) NSLayoutConstraint[] imageView2VFLArray_H =NSLayoutConstraint.FromVisualFormat(imageView2VFL_H, 0 , null, viewDict); NSLayoutConstraint[] imageView2VFLArray_V =NSLayoutConstraint.FromVisualFormat(imageView2VFL_V, 0 , null, viewDict); imageView2.Superview.AddConstraints(imageView2VFLArray_H); imageView2.Superview.AddConstraints(imageView2VFLArray_V); string label2VFL_H = "H:|-10-[label]-16-|";//距父控件左边为10,右边为16(X值和With值也就确定了) string label2VFL_V = "V:[imageView]-7-[label]-8-|";//距上边(imageView)是7,下边(grayView)是8(Y值和Height值也就确定了) NSLayoutConstraint[] label2VFLArray_H =NSLayoutConstraint.FromVisualFormat(label2VFL_H, 0 , null, viewDict); NSLayoutConstraint[] label2VFLArray_V =NSLayoutConstraint.FromVisualFormat(label2VFL_V, 0 , null, viewDict); label2.Superview.AddConstraints(label2VFLArray_H); label2.Superview.AddConstraints(label2VFLArray_V);
4. 通过第三方开源框架Masonry来布局
从Nuget中下载安装Masonry这个包。grayView2.MakeConstraints((ConstraintMaker obj) => { obj.Left.EqualTo(this.View.Left()).Offset(20); obj.Right.EqualTo(this.View.Right()).Offset(-20); obj.Top.EqualTo(this.View.Top()).Offset(350); }); imageView2.MakeConstraints((ConstraintMaker obj) => { obj.Left.EqualTo(imageView2.Superview.Left()).Offset(10); obj.Width.EqualTo(new NSNumber(150)); obj.Top.EqualTo(imageView2.Superview.Top()).Offset(10); obj.Height.EqualTo(new NSNumber(150)); }); label2.MakeConstraints((ConstraintMaker obj) =>{ obj.Left.EqualTo(label2.Superview.Left()).Offset(10); obj.Right.EqualTo(label2.Superview.Right()).Offset(-16); obj.Top.EqualTo(imageView2.Bottom()).Offset(7); obj.Bottom.EqualTo(label2.Superview.Bottom()).Offset(-8); });
注意,最后记得注掉这三个控件的Frame代码。
Autolayout的约束的优先级
约束可以设置优先级,优先级高的生效。
例如有三个UIView,它们之间的水平间距都是10,当删掉中间青色的视图后,红色要自动贴到橙色的右边来且间距还是10。上代码
//约束优先级 UIView orangeView = new UIView(); orangeView.BackgroundColor = UIColor.Orange; UIView cyanView = new UIView(); cyanView.BackgroundColor = UIColor.Cyan; UIView redView = new UIView(); redView.BackgroundColor = UIColor.Red; this.View.AddSubview(orangeView); this.View.AddSubview(cyanView); this.View.AddSubview(redView); _cyanView1 = cyanView; orangeView.MakeConstraints((ConstraintMaker obj) => { obj.Left.EqualTo(this.View.Left()).Offset(10); obj.Bottom.EqualTo(this.View.Bottom()).Offset(-5); obj.Width.EqualTo(new NSNumber(100)); obj.Height.EqualTo(new NSNumber(100)); }); cyanView.MakeConstraints((ConstraintMaker obj) => { obj.Left.EqualTo(orangeView.Right()).Offset(10).Priority(260); obj.Bottom.EqualTo(this.View.Bottom()).Offset(-5); obj.Width.EqualTo(new NSNumber(100)); obj.Height.EqualTo(new NSNumber(100)); }); redView.MakeConstraints((ConstraintMaker obj) => { obj.Left.EqualTo(cyanView.Right()).Offset(10); obj.Bottom.EqualTo(this.View.Bottom()).Offset(-5); obj.Width.EqualTo(new NSNumber(100)); obj.Height.EqualTo(new NSNumber(100)); obj.Left.EqualTo(orangeView.Right()).Offset(10).Priority(250); }); public override void TouchesBegan(Foundation.NSSet touches, UIEvent evt) { base.TouchesBegan(touches, evt); //label.Text = "BookNameBookNameBookNameBookNameBookNameBookNameBookNameBookName"; //_label2.Text = "BookNameBookNameBookNameBookNameBookNameBookNameBookNameBookName"; _cyanView1.RemoveFromSuperview(); }
注意cyanView的Left约束的优先级
obj.Left.EqualTo(orangeView.Right()).Offset(10).Priority(260);
和redView的Left约束的优先级
obj.Left.EqualTo(orangeView.Right()).Offset(10).Priority(250);
由于redView的优先级250低于cyanView的优先级260,所以开始显示出来不会生效,当删掉cyanView后,cyanView的约束也没了,所以redView约束中的第一句就失效了并且最后一句的就生效了。
结果如下图