iOS 8 Auto Layout界面自动布局系列4-使用VFL添加布局约束

本系列第一篇文章介绍了自动布局的基本原理,第二篇通过一个简单的例子演示了如何使用IB以可视化方式创建自动布局约束,第三篇使用代码直接创建NSLayoutConstraint实例来定义自动布局约束。本篇文章在第三篇文章的基础上,使用Visual Format Language(暂且翻译为可视化格式语言,简称VFL)创建约束。

在第三篇文章中,我们仅仅创建了4个视图,就需要创建将近20个NSLayoutConstraint实例,而且每次创建NSLayoutConstraint实例时都需要传入7个参数(firstItem.firstAttribute {==,<=,>=} secondItem.secondAttribute * multiplier + constant),非常繁琐而且容易出错。在实际项目中,视图的层次会更复杂,约束的数量就会成倍增加,有没有办法既直观又简单地创建约束?那你不妨试试VFL,这也是这篇文章的主题。

VFL的使用非常简单直观,不过既然是一门语言,必然就有其语法要求。。。

好吧,我们还是以之前的例子边做边讲吧。

打开Xcode,新建项目,选择iOS -> Application -> Single View Application。项目命名为AutoLayoutByVFL,语言任意选择(本篇文章使用的是Objective-C),设备选择Universal。下载苹果Logo图片apple.jpg,并将其拖入项目中。文件下载地址:

http://yunpan.cn/cfmJB82dfSwf6(提取码:4049)

界面上方用来显示苹果Logo图片的是一个UIImageView,其具有如下4个约束:

- logoImageView左侧与父视图左侧对齐

- logoImageView右侧与父视图右侧对齐

- logoImageView顶部与父视图顶部对齐

- logoImageView高度为父视图高度一半

将ViewController类的viewDidLoad方法修改如下:

- (void)viewDidLoad
{
    [super viewDidLoad];

    UIImageView* logoImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"apple.jpg"]];
    logoImageView.translatesAutoresizingMaskIntoConstraints = NO;
    logoImageView.contentMode = UIViewContentModeScaleAspectFit;
    [self.view addSubview:logoImageView];

    //水平方向上,logoImageView左侧与父视图左侧对齐,logoImageView右侧与父视图右侧对齐
    NSArray* hConstraintArray = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[logoImageView]-0-|" options:0 metrics:nil views:@{@"logoImageView": logoImageView}];
    [NSLayoutConstraint activateConstraints:hConstraintArray];

    //垂直方向上,logoImageView顶部与父视图顶部对齐
    NSArray* vConstraintArray = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[logoImageView]" options:0 metrics:nil views:@{@"logoImageView": logoImageView}];
    [NSLayoutConstraint activateConstraints:vConstraintArray];

    //logoImageView高度为父视图高度一半
    NSLayoutConstraint* heightConstraint = [NSLayoutConstraint constraintWithItem:logoImageView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeHeight multiplier:0.5f constant:0.0f];
    heightConstraint.active = YES;
}

viewDidLoad方法首先调用了NSLayoutConstraint类的一个静态方法constraintsWithVisualFormat:…..,根据传入的VFL字符串生成若干约束,该方法定义如下:

+ (NSArray *)constraintsWithVisualFormat:(NSString *)format options:(NSLayoutFormatOptions)opts metrics:(NSDictionary *)metrics views:(NSDictionary *)views;

参数format是一个符合VFL语法的字符串。上述代码中的H:表示本VFL字符串描述的是水平方向的约束,与之相对的是V:表示垂直方向。如果VFL字符串没有指明H:还是V:,则默认为水平方向。|表示父视图。VFL要求所有视图的名字必须放在中括号之内,[logoImageView]指代的就是logoImageView。-0-表示的是间距值为0。

所以@”H:|-0-[logoImageView]-0-|”表示在水平方向上,logoImageView左侧与其父视图左侧的间距为0,logoImageView右侧与其父视图右侧的间距为0。@”V:|-0-[logoImageView]”表示在垂直方向上,logoImageView顶部与其父视图顶部的间距为0。

另外说一句,-0-可以不写,也就是说如果间距为0则不用明确写出,所以@”H:|-0-[logoImageView]-0-|”可以精简为@”H:|[logoImageView]|”,@”V:|-0-[logoImageView]”可以精简为@”V:|[logoImageView]”,是不是很直观?

参数opts表示布局的对齐方式与方向:

typedef NS_OPTIONS(NSUInteger, NSLayoutFormatOptions)
{
    NSLayoutFormatAlignAllLeft = (1 << NSLayoutAttributeLeft),
    NSLayoutFormatAlignAllRight = (1 << NSLayoutAttributeRight),
    NSLayoutFormatAlignAllTop = (1 << NSLayoutAttributeTop),
    NSLayoutFormatAlignAllBottom = (1 << NSLayoutAttributeBottom),
    NSLayoutFormatAlignAllLeading = (1 << NSLayoutAttributeLeading),
    NSLayoutFormatAlignAllTrailing = (1 << NSLayoutAttributeTrailing),
    NSLayoutFormatAlignAllCenterX = (1 << NSLayoutAttributeCenterX),
    NSLayoutFormatAlignAllCenterY = (1 << NSLayoutAttributeCenterY),
    NSLayoutFormatAlignAllBaseline = (1 << NSLayoutAttributeBaseline),
    NSLayoutFormatAlignAllLastBaseline = NSLayoutFormatAlignAllBaseline,
    NSLayoutFormatAlignAllFirstBaseline NS_ENUM_AVAILABLE_IOS(8_0) = (1 << NSLayoutAttributeFirstBaseline),

    NSLayoutFormatAlignmentMask = 0xFFFF,

    /* choose only one of these three */
    NSLayoutFormatDirectionLeadingToTrailing = 0 << 16, // default
    NSLayoutFormatDirectionLeftToRight = 1 << 16,
    NSLayoutFormatDirectionRightToLeft = 2 << 16,  

    NSLayoutFormatDirectionMask = 0x3 << 16,
};

参数metrics是一个字典。其中的键(Key)是字符串,出现在VFL语句中;值(Value)是NSNumber对象。在解析VFL字符串时,编译器将自动把键替换为其对应的值,目的是使VFL更容易明白和理解。

另外,在解析VFL时,UIKit需要知道VFL字符串中的视图名称究竟对应哪个真实的视图,视图映射字典参数views就用来提供这个信息。其中的键(Key)是字符串,出现在VFL语句中;值(Value)是UIView对象。上述代码中的@{@”logoImageView”: logoImageView}表示的就是字符串@”logoImageView”对应视图logoImageView。

不过有个很遗憾的事实要告诉你,VFL并不能表达所有的约束,例如“logoImageView高度为父视图高度一半”这样的具有比例关系的约束,就无法使用VFL表达出来,所以这时我们只能直接创建NSLayoutConstraint实例了,就像上面的代码那样。

接着我们添加UIScrollView,在viewDidLoad方法中添加如下代码:

    UIScrollView* scrollView = [UIScrollView new];
    scrollView.translatesAutoresizingMaskIntoConstraints = NO;
    scrollView.backgroundColor = [UIColor blueColor]; //为了方便查看效果,暂时将scrollView背景色设置为蓝色
    [self.view addSubview:scrollView];

    //水平方向上,scrollView左侧与父视图左侧对齐,scrollView右侧与父视图右侧对齐
    NSArray* hScrollViewConstraintArray = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scrollView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(scrollView)];
    [NSLayoutConstraint activateConstraints:hScrollViewConstraintArray];

    //垂直方向上,scrollView顶部与logoImageView底部对齐,scrollView底部与父视图底部对齐
    NSArray* vScrollViewConstraintArray = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[logoImageView][scrollView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(logoImageView, scrollView)];
    [NSLayoutConstraint activateConstraints:vScrollViewConstraintArray];

需要额外说明的是,这里调用了一个NSDictionaryOfVariableBindings宏,它能够方便我们构建字典参数。简单说来,NSDictionaryOfVariableBindings(scrollView)就等于@{@”scrollView”: scrollView},NSDictionaryOfVariableBindings(logoImageView, scrollView)就等于@{@”logoImageView”: logoImageView, @”scrollView”: scrollView}。

另外,在垂直方向上,我们可以把之前的@”V:|[logoImageView]”与刚才的@”V:[logoImageView][scrollView]|”合并为一句@”V:|[logoImageView][scrollView]|”,就不需要分别创建heightConstraint与vScrollViewConstraintArray了,达到进一步精简的目的。

接着我们添加scrollView中的两个UILabel对象,在viewDidLoad方法中添加如下代码:

    UILabel* nameLabel = [UILabel new];
    nameLabel.translatesAutoresizingMaskIntoConstraints = NO;
    nameLabel.text = @"苹果公司";
    nameLabel.backgroundColor = [UIColor greenColor];
    [scrollView addSubview:nameLabel];

    UILabel* descriptionLabel = [UILabel new];
    descriptionLabel.translatesAutoresizingMaskIntoConstraints = NO;
    descriptionLabel.text = @"苹果公司(Apple Inc. )是美国的一家高科技公司。由史蒂夫·乔布斯、斯蒂夫·沃兹尼亚克和罗·韦恩(Ron Wayne)等三人于1976年4月1日创立,并命名为美国苹果电脑公司(Apple Computer Inc. ), 2007年1月9日更名为苹果公司,总部位于加利福尼亚州的库比蒂诺。\n苹果公司创立之初主要开发和销售的个人电脑,截至2014年致力于设计、开发和销售消费电子、计算机软件、在线服务和个人计算机。苹果的Apple II于1970年代助长了个人电脑革命,其后的Macintosh接力于1980年代持续发展。该公司硬件产品主要是Mac电脑系列、iPod媒体播放器、iPhone智能手机和iPad平板电脑;在线服务包括iCloud、iTunes Store和App Store;消费软件包括OS X和iOS操作系统、iTunes多媒体浏览器、Safari网络浏览器,还有iLife和iWork创意和生产力套件。苹果公司在高科技企业中以创新而闻名世界。\n苹果公司1980年12月12日公开招股上市,2012年创下6235亿美元的市值记录,截至2014年6月,苹果公司已经连续三年成为全球市值最大公司。苹果公司在2014年世界500强排行榜中排名第15名。2013年9月30日,在宏盟集团的“全球最佳品牌”报告中,苹果公司超过可口可乐成为世界最有价值品牌。2014年,苹果品牌超越谷歌(Google),成为世界最具价值品牌 。";
    descriptionLabel.numberOfLines = 0;
    descriptionLabel.backgroundColor = [UIColor yellowColor];
    [scrollView addSubview:descriptionLabel];

    //水平方向上,nameLabel左侧与父视图左侧对齐,nameLabel右侧与父视图右侧对齐,nameLabel宽度与logoImageView宽度相同
    NSArray* hNameLabelConstraintArray = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[nameLabel(==logoImageView)]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(nameLabel, logoImageView)];
    [NSLayoutConstraint activateConstraints:hNameLabelConstraintArray];

    //水平方向上,descriptionLabel左侧与父视图左侧对齐,descriptionLabel右侧与父视图右侧对齐,descriptionLabel宽度与logoImageView宽度相同
    NSArray* hDescriptionLabelConstraintArray = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[descriptionLabel(==logoImageView)]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(descriptionLabel, logoImageView)];
    [NSLayoutConstraint activateConstraints:hDescriptionLabelConstraintArray];

    //垂直方向上,nameLabel顶部与父视图顶部对齐,nameLabel高度为20,nameLabel底部与descriptionLabel顶部对齐,descriptionLabel底部与父视图底部对齐
    NSArray* vLabelConstraintArray = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[nameLabel(20)][descriptionLabel]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(nameLabel, descriptionLabel)];
    [NSLayoutConstraint activateConstraints:vLabelConstraintArray];

其中@”H:|[nameLabel(==logoImageView)]|”表示nameLabel宽度与logoImageView宽度相等,@”V:|[nameLabel(20)][descriptionLabel]|”表示nameLabel的宽度为20。到此我们就完成了这个例子,在此附上全部代码:

- (void)viewDidLoad
{
    [super viewDidLoad];

    UIImageView* logoImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"apple.jpg"]];
    logoImageView.translatesAutoresizingMaskIntoConstraints = NO;
    logoImageView.contentMode = UIViewContentModeScaleAspectFit;
    [self.view addSubview:logoImageView];

    UIScrollView* scrollView = [UIScrollView new];
    scrollView.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:scrollView];

    //水平方向上,logoImageView左侧与父视图左侧对齐,logoImageView右侧与父视图右侧对齐
    NSArray* hConstraintArray = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[logoImageView]|" options:0 metrics:nil views:@{@"logoImageView": logoImageView}];
    [NSLayoutConstraint activateConstraints:hConstraintArray];

    //垂直方向上,logoImageView顶部与父视图顶部对齐,logoImageView底部与scrollView顶部对齐,scrollView底部与父视图底部对齐
    NSArray* vConstraintArray = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[logoImageView][scrollView]|" options:0 metrics:nil views:@{@"logoImageView": logoImageView, @"scrollView": scrollView}];
    [NSLayoutConstraint activateConstraints:vConstraintArray];

    //logoImageView高度为父视图高度一半
    NSLayoutConstraint* heightConstraint = [NSLayoutConstraint constraintWithItem:logoImageView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeHeight multiplier:0.5f constant:0.0f];
    heightConstraint.active = YES;

    //水平方向上,scrollView左侧与父视图左侧对齐,scrollView右侧与父视图右侧对齐
    NSArray* hScrollViewConstraintArray = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scrollView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(scrollView)];
    [NSLayoutConstraint activateConstraints:hScrollViewConstraintArray];

    UILabel* nameLabel = [UILabel new];
    nameLabel.translatesAutoresizingMaskIntoConstraints = NO;
    nameLabel.text = @"苹果公司";
    nameLabel.backgroundColor = [UIColor greenColor];
    [scrollView addSubview:nameLabel];

    UILabel* descriptionLabel = [UILabel new];
    descriptionLabel.translatesAutoresizingMaskIntoConstraints = NO;
    descriptionLabel.text = @"苹果公司(Apple Inc. )是美国的一家高科技公司。由史蒂夫·乔布斯、斯蒂夫·沃兹尼亚克和罗·韦恩(Ron Wayne)等三人于1976年4月1日创立,并命名为美国苹果电脑公司(Apple Computer Inc. ), 2007年1月9日更名为苹果公司,总部位于加利福尼亚州的库比蒂诺。\n苹果公司创立之初主要开发和销售的个人电脑,截至2014年致力于设计、开发和销售消费电子、计算机软件、在线服务和个人计算机。苹果的Apple II于1970年代助长了个人电脑革命,其后的Macintosh接力于1980年代持续发展。该公司硬件产品主要是Mac电脑系列、iPod媒体播放器、iPhone智能手机和iPad平板电脑;在线服务包括iCloud、iTunes Store和App Store;消费软件包括OS X和iOS操作系统、iTunes多媒体浏览器、Safari网络浏览器,还有iLife和iWork创意和生产力套件。苹果公司在高科技企业中以创新而闻名世界。\n苹果公司1980年12月12日公开招股上市,2012年创下6235亿美元的市值记录,截至2014年6月,苹果公司已经连续三年成为全球市值最大公司。苹果公司在2014年世界500强排行榜中排名第15名。2013年9月30日,在宏盟集团的“全球最佳品牌”报告中,苹果公司超过可口可乐成为世界最有价值品牌。2014年,苹果品牌超越谷歌(Google),成为世界最具价值品牌 。";
    descriptionLabel.numberOfLines = 0;
    descriptionLabel.backgroundColor = [UIColor yellowColor];
    [scrollView addSubview:descriptionLabel];

    //水平方向上,nameLabel左侧与父视图左侧对齐,nameLabel右侧与父视图右侧对齐,nameLabel宽度与logoImageView宽度相同
    NSArray* hNameLabelConstraintArray = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[nameLabel(==logoImageView)]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(nameLabel, logoImageView)];
    [NSLayoutConstraint activateConstraints:hNameLabelConstraintArray];

    //水平方向上,descriptionLabel左侧与父视图左侧对齐,descriptionLabel右侧与父视图右侧对齐,descriptionLabel宽度与logoImageView宽度相同
    NSArray* hDescriptionLabelConstraintArray = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[descriptionLabel(==logoImageView)]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(descriptionLabel, logoImageView)];
    [NSLayoutConstraint activateConstraints:hDescriptionLabelConstraintArray];

    //垂直方向上,nameLabel顶部与父视图顶部对齐,nameLabel高度为20,nameLabel底部与descriptionLabel顶部对齐,descriptionLabel底部与父视图底部对齐
    NSArray* vLabelConstraintArray = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[nameLabel(20)][descriptionLabel]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(nameLabel, descriptionLabel)];
    [NSLayoutConstraint activateConstraints:vLabelConstraintArray];
}

与第三篇文章中逐个去创建NSLayoutConstraint对象相比,是不是简单直观了不少?程序最终项目文件链接:

http://yunpan.cn/cVE8i8WmnpJwv(提取码:d348)

本篇文章我们初步了解了VFL的基本使用方式,关于VFL的具体语法格式请参看苹果的《Auto Layout Guide》,链接:

https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/Introduction/Introduction.html#//apple_ref/doc/uid/TP40010853

在本系列后续文章中,我将继续介绍自动布局中的动画实现、事件处理、调试,以及iOS 8中新添加的Size Class的使用,敬请期待吧。

时间: 2024-10-10 06:28:08

iOS 8 Auto Layout界面自动布局系列4-使用VFL添加布局约束的相关文章

iOS 8 Auto Layout界面自动布局系列3-使用代码添加布局约束

本系列的第一篇文章介绍了自动布局的基本原理,第二篇文章通过一个简单的例子演示了如何使用Xcode的Interface Builder(简称IB)以可视化方式添加约束.本篇为该系列的第三篇文章,主要介绍如何通过代码来添加布局约束. 其实,我个人认为本篇才应该是系列的第二篇,因为通过代码构建自动布局约束是最基础的,也是最灵活的方式.而IB只不过是把复杂的过程以直观简单的方式呈现出来,而且并非所有的情况都能用IB来解决,所以学习并掌握通过代码来添加自动布局约束是非常必要的.但是为了降低学习的难度,提高

转////iOS 8 Auto Layout界面自动布局系列1-自动布局的基本原理

iOS 8 Auto Layout界面自动布局系列1-自动布局的基本原理 http://blog.csdn.net/pucker/article/details/41832939 标签: iosinterface苹果布局界面 2014-12-10 00:25 11286人阅读 评论(2) 收藏 举报  分类: iOS开发(19)  版权声明:本文为博主原创文章,未经博主允许不得转载. 苹果今年如约放出了新的iPhone 6与iOS 8系统,SDK针对新的设备和系统的界面适配也进行了若干改进,因此

【转 iOS 8 Auto Layout界面自动布局系列2-使用Xcode的Interface Builder添加布局约束

原文网址:http://blog.csdn.net/pucker/article/details/41843511 上一篇文章<iOS 8界面自动布局系列-1>简要介绍了iOS界面布局方式的前世今生.本篇文章将详细介绍如何使用自动布局实现不同屏幕尺寸的适配. 添加自动布局约束(下文简称约束)有以下三种方式: 使用Xcode的Interface Builder界面设计器添加并设置约束 通过代码逐条添加约束 通过可视化格式语言VFL添加约束 本文将以一个简单的例子来演示如何使用这几种方式添加约束,

iOS 8 Auto Layout界面自动布局系列5-自身内容尺寸约束、修改约束、布局动画

首先感谢众多网友的支持,最近我实在是事情太多,所以没有写太多.不过看到大家的反馈和评价,我还是要坚持挤出时间给大家分享我的经验.如果你对我写的东西有任何建议.意见或者疑问,请到我的博客留言: http://blog.csdn.net/pucker 好了,言归正传.本系列的前几篇文章讲解了自动布局的原理,以及如何添加约束.这篇文章主要介绍以下内容: 某些用户控件具有自身内容尺寸约束 使用视图调试工具在运行时查看和调试程序界面视图层次.尺寸和自动布局约束 创建约束的对象关联 通过修改约束的常量值.删

iOS 8 Auto Layout界面自动布局系列2-使用Xcode的Interface Builder添加布局约束

http://blog.csdn.net/pucker/article/details/41843511 上一篇文章<iOS 8界面自动布局系列-1>简要介绍了iOS界面布局方式的前世今生.本篇文章将详细介绍如何使用自动布局实现不同屏幕尺寸的适配. 添加自动布局约束(下文简称约束)有以下三种方式: 使用Xcode的Interface Builder界面设计器添加并设置约束 通过代码逐条添加约束 通过可视化格式语言VFL添加约束 本文将以一个简单的例子来演示如何使用这几种方式添加约束,如下图所示

iOS 9 Auto Layout界面自动布局系列6-自适应布局

设计MM小尹:"小李,邮件里是我们设计的用户登录界面初稿,请你看一下技术上有没有什么问题." 程序猿小李:"好的,我看一下." 小李打开邮件,看到界面设计初稿为: 这是一个同时支持iPhone和iPad的统一App(Universal App).尽管小李对Auto Layout很熟悉,但是看到设计稿之后,小李却犯了难.因为设计稿中的iPhone横屏的界面布局方式是特殊情况,如果按照图1的方式添加一套自动布局约束,程序就需要判断设备类型(当前是iPhone还是iPad

iOS Programming Auto Layout: Programmatic Constraints 自动布局:通过编程限制

iOS Programming? Auto Layout: Programmatic Constraints? 1.? However, if your views are created in code, then you will need to constrain them programmatically. 如果你的view是由代码创建的,那么你需要用编程限制它了. To have a view to work with, you are going to recreate the im

iOS 7 - Auto Layout on iOS Versions prior to 6.0

链接地址:http://stackoverflow.com/questions/18735847/ios-7-auto-layout-on-ios-versions-prior-to-6-0 Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required. iOS 7 - Auto Layout on

uinty3d Auto Layout(自动布局)

1.Auto Layout (自动布局) 自动布局系统提供方法在layout groups中嵌套放置元素,例如horizontal horizontal groups, vertical groups, 或者grids.它也允许元素包换的内容自动地设置大小.例如一个按钮可以根据它的文本内容动态地重新设置大小. 自动布局系统是一个基于基础的Rect Transform之上的布局系统,它可以随意的用在一些或者全部元素上. 2.理解Layout Elements(布局元素) 自动布局系统基于layou