之所以这一次尝试着利用AutoLayout来已毕那种功用,原来在底部之上10像素居中的view

在重重的电商类的APP中我们常常会用到一种滑动悬停的作用,所以本次尝试着利用AutoLayout来贯彻那种功用。话不多说先上图

1.AutoLayout是什么?

在Auto
Layout在此之前,不论是在IB里拖放,照旧在代码中写,每个UIView都会有协调的frame属性,来定义其在眼前视图中的地方和尺寸。

UIView *view = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 10, 10)];
[self.view addSubview:view];

动用AutoLayout的话,就改为了使用约束原则来定义view的职位和尺寸。大家用”这一个view距离底部10像素,距离顶部10像素,距离右侧10像素,距离y左侧像素”或”label
A左侧缘和button B右侧缘有20点的空域空间。”那样来叙述view。

那般最大利益是可以解决了分裂分辨率和显示器尺寸下view的适配问题,此外也简化了旋转时view的职位的定义,原来在底层之上10像素居中的view,不论在转动显示器或是更换设备,始终还在底层之上10像素居中的地方,不会暴发变化。

运用AutoLayout另一个紧要的益处就是本地化。比如各自语言中中的文本宽度分裂适配起来是一件很麻烦的事。AutoLayout能依照label须求出示的情节自动改变label的分寸。

效果:

xt.gif

2.AutoLayout和Autoresizing Mask的区别

只要你此前平昔是代码写UI的话,你早晚写过UIViewAutoresizingFlexibleWidth之类的枚举;要是你在此之前用IB比较多以来,一定留神到过每个view的size
inspector中都有一个革命线条的Autoresizing的提示器和呼应的动画缩放的示意图,那就是Autoresizing
Mask。autosizing
mask决定了当一个视图的父视图大小改变时,其自身须求做出什么改变。

autosizing
mask下,你需求为各样view指定各自的宽高,并累加和父视图的羁绊原则:

图片 1

AutoLayout1.png

图片 2

AutoLayout2.png

但AutoLayout则看起来简单明了多了,视图的分寸和职位再也不紧要了,只有约束要紧。当然,当你拖一个新建的button或label到画布上时,它会有自然的轻重,并且你会将它拖到某一职位,但这是只一个用来告诉Interface
Builder如何放置约束的宏图工具。

图片 3

AutoLayout3.png

作用上过了,仍旧理顺下思路上呢。从效率图上容易察觉大家的次序是依据UIScrollerView的。界面上的显得同样都是UIScrollView的子控件。当然了困难也就是基于UIScrollerView的内部子控件的布局以及AutoLayout约束的修改。

3.开始AutoLayout

我会从一个大家周边的用户注册页面的例子讲起

图片 4

AutoLayout4.PNG

俺们盼望它在横屏方式下也得以较好地出示出来。

大家在storyBoard中拖拽控件,注意当您拖拽的时候,肉色虚线将会冒出。大家相应用那几个虚线来做向导。通过preview(点击show
the Assistant
Editor,并且切换来preview即可开启)能够看来没有AutoLayout的时候控件摆放乱七八糟。

图片 5

AutoLayout4.png

图片 6

AutoLayout5.png

率先对此左上方的imageView,大家期待它不管显示器尺寸如何,都保持同一的大大小小,所以大家须求做的是将鼠标放在改view上,按住control键,并垂直拖拽。效果如下:

图片 7

AutoLayout5.png

大家点击Height,那样就确定了它的万丈稳定不变。同样的道理,大家点击Weight,这一次你需求程度拖拽。

现今咱们着眼preview,你会发现imageview跑到左上角去了。并且imageView会出现红色的线。为啥吗?因为您的AutoLayout是不完整的,你只规定了冲天和宽窄,你从未确定它离开它的父view边缘的离开是稍微。将鼠标放在改view上,按住control键,并拖拽至最外面的view上,放手:会看到上面的选项:

图片 8

AutoLayout6.png

Top Space to Superview:是指该五个view之间保存固定中度
Center Horizontal In Container:是指该三个view之间垂直居中
Equal Widths:保持一致宽度
Equal Heights:保持一如既往高度
Aspect Ratio:保存固定比例关系

很举世瞩目我们必要点击第二个选项和第三个选项。第四个挑选和imageView自身的width相当于规定了imageView到父view的左左边缘长度不变。第二个选项和imageView自身的Height相当于规定了imageView到父view的内外中度不变。因而,该imageView的束缚原则就总体了。

对此下面的UIText菲尔德,大家意在它离开上面的imageView中度固定,并且左左边缘的相距固定。

咱俩将UIText菲尔德(Field)拖拽至imageView,甩手如下:

图片 9

AutoLayout7.png

Vertical Spacing:是指多个view之间的垂直距离固定
Left:是指多个view左侧对齐
Center X:是指多少个view左侧对齐
Right:是指多少个viewX轴中央对齐

俺们须要点击第三个挑选来恒定自身和上边imageView之间的相距,然后大家须求一定自身和父view边缘的距离,所以大家拖拽至父view左右侧缘,如下图:

图片 10

AutoLayout8.png

图片 11

AutoLayout9.png

Leading Space to Superview:view至父view左边缘长度(前置距离)固定
Trailing Space to Superview:view至父view左侧缘长度(尾随距离)固定

俺们对首个UIText菲尔德以及上面的UIButton举办同样的操作。

当您对下边的UIButton举办相同的操作后你会意识依旧出现了表示警告的紫色线,为啥吗?借使你不精通为什么,你可以看来Document
Outline那里有一个香艳箭头,点击它,你会过来下图所示:

图片 12

AutoLayout11.png

它说:你愿意的view中度是30,但现在它实在52,你要求修补它

您恐怕疑心为啥button没有Width约束,自动布局是为何知道button有多厚(30)的?

作业是这么的:button自己是驾驭自己有多少厚度。它根据自己的title加上一些padding就行了。借使你为button的title设置更大的字号,它会自行调整它的小幅。

那正是我们耳熟能详的intrinsic content
size。并不是富有的控制器都有这几个,但大多数是(UILabel是一个例子)。即便一个视图可以总计自己理想的大大小小,那么您就不须要为它尤其指定Width或Height约束了。但在大家的例证中,我愿意这些button更高啊,那如何是好?

点击这个红色的三角形你会看出:

图片 13

AutoLayout12.png

Update Frame?不,大家不想它的可观变小。Update
Constrains?如果你点击这一个选项的话,你会意识什么样变动都尚未,因为在它要求你没有在Height上设置一个封锁原则,也就谈不上更新。那大家点击首个挑选试试。

可以发现警告消失了,那我们点击那一个选项之后,XCode为大家做了怎么?

图片 14

AutoLayout13.png

看那里大家得以发现,UIButton自身增加了一个可观不变的牢笼原则,所以警告消失了。

咱俩运行看看效果如何

竖屏:

图片 15

AutoLayout15.PNG

横屏:

图片 16

AutoLayout14.PNG

哦,竖屏看起来还不易,横屏看起来不是太好,UIButton看不见了。那很好掌握因为大家原则性了控件和父view顶部的偏离,但横屏下中度变小所以UIButton被挤到上边去了。那怎么做?如若大家一定了控件和父view底部的离开,很有可能会促成image在横屏情势下被挤到地点去,所以有没有更好的解决办法呢。

实在上边讲到的那么些约束规范也是目的,它们是NSLayoutConstraint对象,所以大家得以在程序运行是动态改变其中的羁绊原则,如下图,大家将imageView和父view的垂直距离约束原则拖动到代码中:

图片 17

AutoLayout16.png

在ViewController.m中写下以下代码:

-(void)viewWillLayoutSubviews{
    if (UIInterfaceOrientationIsLandscape(self.interfaceOrientation)){
        self.imageViewToViewSpace.constant = 30;
    }
    else{
        self.imageViewToViewSpace.constant = 82;
    }
}

功用看上去还不易:

图片 18

AutoLayout17.PNG

咱俩看一下我们的急需的部分骨干的控件布局:

Snip20150706_20.png

4.稍微复杂点的AutoLayout:

大家再将方面格外例子变得有点复杂一点,把下部的Button变为3个button,每个等宽。

大家首先为button1增添上左右3个离开宽度约束原则:

图片 19

为button2日增与button1等y轴,与button3离开约束,将button1与button2的距离和button2和button3的离开都安装为8:

图片 20

为button3增加与button2等y轴,与父view的Trailing space:

图片 21

显示器快照 2015-03-11 清晨5.19.06.png

看起来好多警示?恩上面是最首要,大家把button1,button2,button3,设置为同等中度平等宽度,警告就没有了。

现今运作效果如下:

图片 22

图片 23

好了,现在初阶上马搭建新的花色了,首先在Storyboard上搭建最基本的布局,并将控件基本布局到对应的职责,以备我们更便民的拉长约束。

Snip20150706_21.png

5.SizeClass

咱俩地方使用了NSLayoutConstraint的IBOutlet对象,所以大家得以在程序运行是动态改变其中的牢笼原则,不过有其它一种更优雅的法子来落到实处地点的机能:使用SizeClass。

随着三星6/HTC6
Plus的揭破,现在苹果生态圈中的设备尺寸也曾经变得种类不以为奇了。想必苹果也意识到那一点。都通晓苹果是以化繁为简的安插性管理学深刻人心的,这一次再两回表明了。SizeClass是对装备尺寸的一个抽象概念,现在其他设施的
长、宽 被精简地分为两种处境:普通 (Regular) 、紧密 (Compact)和任性(Any)
,那样,按照长和宽不相同的反衬就能发出 3*3=9
种差距尺寸。下图浮现个每种状态相应的设施。

图片 24

1411722627166330.png

俺们可以在不一致的屏幕尺寸下使用分裂的SizeClass,在正规状态下:

图片 25

点击
wAny,hAny可以变更需求布局的尺码,鲜明横屏的时候,高度处于压缩的情形,(height:
compact),大家需求先对正常的布局之外,还要添加一种(wAny, hCompact)

图片 26

接下来我们在这几个场所下再也设置大家的布局情势,把上边的imageView的topSpace
修改为10:

图片 27

你须要了然的是在那么些情景下的布局情势不会潜移默化其余size下的布局格局,预览效果如下:

图片 28

你有没有在意到imageView的图纸不相同了啊,你是或不是认为自己使用了区其他image?其实是同样张图纸,只然而大家可以在Images.xcassets上对分裂size下行使不一样的图纸:

图片 29

到了此处就起来对咱们的控件添加基本的羁绊了从上上马吧。上边的控件大家能确定是UIImageViewheigth以及topleft以及rihgt。至于bottom到了背后会首要设置的。

Snip20150706_22.png

1.AutoLayout与UITableView

你见识到了AutoLayout的强硬之处了吗,上面的例证让我们把AutoLayout应用到UITableView中,尝试来构建更复杂的利用。例如下边图片,当UITableView中情节不相同时,使用AutoLayout来动态调整UITableCell的惊人。

图片 30

IMG_0920.PNG

咱俩新建一个UITableViewController的子类,在大家的storyBoard中添加一个TableViewController,并将它的自定义类设置为DynamicCellHeightViewController。

图片 31

AutoLayout1.png

在我们的cell上添加如下imageView和Label八个控件:

图片 32

AutoLayout4.png

新建自定义的cell类CustomTableViewCell并将storyBoard中的cell关联至该类。

图片 33

AutoLayout7.png

并将UILabel的习性Lines设为了0以代表彰显多行。将cell的Identifier设置为”cell”。

让大家给那几个view一点约束。在上一篇作品你已经领会了经过按住ctrl在多少个view之间拖拽增添约束的法门,此外,大家还有其余二种艺术:用Editor\Pin和Align菜单:

图片 34

AutoLayout2.png

再有在Interface Builder窗口的底层有一行那样的按钮:

图片 35

AutoLayout3.png

从左到右分别是:对齐(Align),固定(Pin),解决机关布局问题(Resolve Auto
Layout Issues)和重定义尺寸(Resizing
Behavior)。前多个按钮鱼Editor菜单中的对应项有一致的功效。Resizing
Behavior按钮允许你在重新安装view的尺码的时候,改变一度添加的束缚。

顶部的Spacing to nearest
neighbor可以添加上下左右多个约束规范,点击者4个T字架,它们就会变成实体的丙戌革命:

图片 36

AutoLayout5.png

如上图所示,大家为imageView增添4个约束规范。同理大家为label扩张4个约束原则。

图片 37

AutoLayout6.png

好了,大家早已形成了AutoLayout的布局,下边大家须求贯彻UITableView的情商。

先讲明了一个NSArray变量来存放数据。

@interface DynamicCellHeightViewController ()
@property (nonatomic, strong) NSArray *tableData;
@end

@implementation DynamicCellHeightViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.tableData = @[@"1\n2\n3\n4\n5\n6", @"123456789012345678901234567890", @"1\n2", @"1\n2\n3", @"1"];
}

前些天落到实处UITableViewDataSource的protocol:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.tableData.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    CustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];
    cell.label.text = self.tableData[indexPath.row];
    return cell;
}

从self.tableData中的数据我们可以见见,每一个Cell突显的数量中度是不雷同的,那么大家必要动态总结Cell的冲天。由于是机关布局,所以大家需求使用一个systemLayoutSizeFittingSize:来计算UITableViewCell所占空间中度。

那里有一个亟待小心的题目,UITableView是五次性计算完所有Cell的万丈,假使有1W个Cell,那么heightForRowAtIndexPath就会触发1W次,然后才突显内容。可是在iOS7之后,提供了一个新办法可以避免那1W次调用,它就是estimatedHeightForRowAtIndexPath。需要回到一个Cell的推断值,达成了这一个主意,那唯有显示的Cell才会触发统计中度的protocol.
由于systemLayoutSizeFittingSize须要cell的一个实例才能计算,所以那儿用一个分子变量存一个Cell的实列,那样就不要求每趟总结Cell中度的时候去动态变化一个Cell实例,那样即方便也连忙也少用内存,可谓一举三得。

俺们声贝拉米(贝拉米(Bellamy))个存计算Cell中度的实例变量:

@property (nonatomic, strong) UITableViewCell *prototypeCell;

然后在viewDidLoad中先河化它:

self.prototypeCell  = [self.tableView dequeueReusableCellWithIdentifier:@"cell"];

算算Cell中度的达成:

#pragma mark - UITableViewDelegate
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    CustomTableViewCell *cell = (CustomTableViewCell *)self.prototypeCell;
    cell.label.text = [self.tableData objectAtIndex:indexPath.row];
    CGSize size = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
    NSLog(@"h=%f", size.height + 1);
    return 1  + size.height;//加1是因为分隔线的高度
}

- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return 66;
}

运转效果如下:

图片 38

AutoLayout8.PNG

恩,好像哪个地方不对,计算cell中度时应当考虑头像的莫大。

正如图,大家为头像和cell之间添加一个羁绊规范,并在右面板中校Constant设置为>=10,那样cell的很小中度也是头像高度地点加上10了。

图片 39

AutoLayout9.png

运行效果如下:

图片 40

AutoLayout10.PNG

万一不用systemLayoutSizeFittingSize,我们也足以手动计算cell的惊人,只要计算cell中label的文字中度即可,下边是该方法:

#import "NSString+addition.h"

@implementation NSString (addition)
- (CGSize)calculateSize:(CGSize)size font:(UIFont *)font {
    CGSize expectedLabelSize = CGSizeZero;

    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7) {
        NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
        paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping;
        NSDictionary *attributes = @{NSFontAttributeName:font, NSParagraphStyleAttributeName:paragraphStyle.copy};

        expectedLabelSize = [self boundingRectWithSize:size options:NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:nil].size;
    }
    else {
        expectedLabelSize = [self sizeWithFont:font
                                       constrainedToSize:size
                                           lineBreakMode:NSLineBreakByWordWrapping];
    }

    return CGSizeMake(ceil(expectedLabelSize.width), ceil(expectedLabelSize.height));
}
@end

像label那种控件会依照label中text的始末自动调整其入骨,那假如是UITextView呢,大家必要上边的法门来回到其尺寸。

CGSize textViewSize = [cell.label sizeThatFits:CGSizeMake(cell.t.frame.size.width, FLT_MAX)];

下一场继续来操作悬停的View。这一个View因为远在五个view的中级所以大家要临时确定height以及leftright的封锁就足足了了

Snip20150706_24.png

2.Self Sizing

在iOS8中引入了一个强硬的新特征,Self
Sizing.只要在viewDidLoad中参预以下那两行代码,然后到场地方的电动布局,大家就足以把总计高度的代码删掉了。

- (void)viewDidLoad {
    [super viewDidLoad];

    self.tableView.estimatedRowHeight = 60.0;
    self.tableView.rowHeight = UITableViewAutomaticDimension;    
}

自身要好在类型中也尝尝用过Self
Sizing这么些特性,不过当tableView加载越发多内容时会有明确的卡顿效果还要tableView有时还会上下跳动!所以我对它的选择保留谨慎态度。不过,在构建简单的tableView时,那是一个要命好用的特征。

好不简单到最终一个UIImageView了,同样的能确定的是heightrightleft以及bottom这四项。

Snip20150707_25.png

AutoLayout与ScrollView

ScrollView在AutoLayout上的突显多少有点至极,大家来讲话。首先大家拖动一个
ScrollView到视图中,并安装它的封锁规范:x , y , width , height.

图片 41

UIScrollView特殊在于:要求设置其ContentView!,所以您须求此外拖一个UIView上作为它的始末视图。

与此同时安装ContentView对应于UIScrollView的Leading Space、Trailing
Space、Top Space、Bottom Space以及其width、height.我设置Leading
Space、Trailing Space、Top Space、Bottom Space都为 0。

图片 42

在那么些例子里,大家须要内容视图在ScrollView中滑起来,而且只好垂直滑动而不可以水平滑动,所以大家必要把ContentView的宽设置成和ScrollView一样,不过高一定要当先ScrollView的高:

图片 43

您可以在这里下载完整的代码。借使你以为对您有协理,希望您不吝啬你的star:)

到了那边针对单个的控件的布局基本形成了,细心的你恐怕会发现上述的操作都尚未进行关联以及没有对width进展封锁。那么上面大家将要起来举办三者的涉及以及width上的设置。
因为悬停的view处与五个imageView的高中级,所以大家只必要对它举办拍卖就好了

Snip20150707_27.png

实在那七个约束完全是可以在设置悬停view的时候的丰裕,之所以在这里丰裕是我们在后边的控制器会用到那多少个约束,为了好辨认大家就给他俩定义上别名:

Snip20150707_29.png

接下来大家按住command挑选大家的多个控件然后按住control拖向scrollView的父控件view设置等width

Snip20150707_33.png

好了,到了此处大家的羁绊已经不会再报错了,然后在逻辑上也是基本是流畅的了,不过对于大家悬停的作用来说就少了要害的一个环节那么就是一旦悬停view悬停了,那么它与上下五个imageView的羁绊要怎么处理啊?所以大家还必要一个增援的牢笼用来终止之后的关系处理

Snip20150707_34.png

增加其后大家给那些约束起分别名hidden悬停,不过细心的您肯定会发觉丰裕之后会sb会提示出有争论的束缚,那么大家只必要对大家刚刚添加的羁绊举办一下操作就OK了

Snip20150707_36.png

好了,到了那边大家在AutoLayout上要做的业务就这几个了,上面我们就可以欣慰的写代码了。
@interface ViewController ()
/**中间的View*/
@property (weak, nonatomic) IBOutlet UIView *centreView;
/**上面的ImageView*/
@property (weak, nonatomic) IBOutlet UIImageView *topImageView;
/**centreView的top约束*/
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *topConstraint;
/**centreView的bottom约束*/
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *bottomConstraint;
/**topImageView暂禁用的约束*/
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *hiddenConstraint;

@end

然后在scrollView的滑行代理方法中落到实处

- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
    //获得top图片的高度
    CGFloat imageH = self.topImageView.frame.size.height;
    //获取偏移量
    CGFloat offsetY = scrollView.contentOffset.y;
    //centrView的frame
    CGRect centreFrame = self.centreView.frame;
    if (offsetY>=imageH) {
        //将centreView的向上和向下的约束禁用
        self.bottomConstraint.active = NO;
        self.topConstraint.active = NO;
        //将topImageView与bottomImageView的约束使用关联
        self.hiddenConstraint.active = YES;
        //悬停在位置
        centreFrame.origin.y = 0;
        self.centreView.frame = centreFrame;
        //添加在scrollView的父控件
        [self.view addSubview:self.centreView];
    }else{
        //添加在topIamgeView的下面
        centreFrame.origin.y = imageH;
        self.centreView.frame = centreFrame;

        [scrollView addSubview:self.centreView];
        //记住一定要先添加到scrollView上之后在修改约束的内容,不然添加的约束会不成,因为系统无法建立他们之间的联系。
        self.hiddenConstraint.active = NO;
        self.topConstraint.active = YES;
        self.bottomConstraint.active = YES;

    }
    //等比例的伸缩
    CGFloat scale= 1-(offsetY/60);
    scale = (scale>=1)?scale :1;
    self.topImageView.transform = CGAffineTransformMakeScale(scale, scale);

}

最终补充:

  • 在子控件的尺码不能通过UIScrollView来计量,可以透过以下格局测算

    • 设置固定值(width==100,height==300)
    • 相对于UIScrollView以外的其他控件来总括尺寸
  • 在UIScrollView里面布局子控件,sb里面默许是是索要子控件的尺寸以及子控件与UIScrollView之间的间距来计量出scroller的conentSize的。所以那就是地点的子控件要与父控件来等宽的原由了。

  • UIScrollView的frame应当经过子控件以外的其他控件来计算

相关文章