iOS 8 Auto Layout界面自动布局系列5-自身内容尺寸约束、修改约束、布局动画
首先感谢众多网友的支持,最近我实在是事情太多,所以没有写太多。不过看到大家的反馈和评价,我还是要坚持挤出时间给大家分享我的经验。如果你对我写的东西有任何建议、意见或者疑问,请到我的CSDN博客留言:
好了,言归正传。本系列的前几篇文章讲解了自动布局的原理,以及如何添加约束。这篇文章主要介绍以下内容:
- 某些用户控件具有自身内容尺寸约束
- 使用视图调试工具在运行时查看和调试程序界面视图层次、尺寸和自动布局约束
- 创建约束的对象关联
- 通过修改约束的常量值、删除旧约束添加新约束、设置约束激活属性、设置约束优先级等方式,实现视图的布局更新
- 使用动画更新界面布局
- 设置带有自身内容控件的抗压缩与抗拉抻优先级
下面结合一个用户登录界面的例子来讲解。首先请下载初始项目:
http://yunpan.cn/cQDIbjtf98zzV (提取码:3d6b)
解压缩并使用Xcode打开该项目,选择任意一个iPhone模拟器,编译项目并运行,如图所示。
一、自身内容尺寸约束
回到Xcode打开Main.storyboard,选中用户头像图片视图Head Image View,并打开尺寸窗口(Size Inspector,快捷键⌥⌘5)查看其布局约束。
可以看到该图片视图当前具有2个约束:
- 水平中心点与其父视图水平中心点对齐(确定图片水平位置x)
- 底部与下方文本控件顶部相隔20点的距离(已知下方文本控件的垂直位置是确定的,因此也就确定了图片垂直位置y)
等等,这里貌似有问题。细心的读者可能会发问了,本系列的第一篇文章明确说过,要确定一个视图的精确位置,至少需要4个布局约束(以确定水平位置 x、垂直位置y、宽度w和高度h)。可现有的2个约束仅能确定x和y,缺少必要的信息来确定w和h。然而此时Interface Builder并没有提示缺少约束的错误(如果真的缺少约束,则Interface Builder会显示红色错误圆圈,并提示Missing Constraints),并且程序运行正常且没有报错,这是怎么回事呢?
请注意,某些用来展现内容的用户控件,例如文本控件UILabel、按钮UIButton、图片视图UIImageView等,它们具有自身内容尺 寸(Intrinsic Content Size),此类用户控件会根据自身内容尺寸添加布局约束。也就是说,如果开发者没有显式给出其宽度或者高度约束,则其自动添加的自身内容约束将会起作 用。因此看似“缺失”约束,实际上并非如此。
对于UIImageView,其自身内容尺寸就是图片(1倍图)的尺寸。打开Images.xcassets,选中head中的1x图,在属性窗口(Attribute Inspector)中可以看到其尺寸为133px*133px。
我们不妨使用Xcode提供的界面层次调试工具在运行时动态查看视图层次、尺寸以及布局约束等信息。如果当前没有运行程序,请编译运行,然后打开调 试导航窗口(Debug Navigator),点击进程查看选项按钮(Process View Option),选择界面层次(View UI Hierarchy)以开启界面层次调试工具。
此时Xcode左侧会列出视图层次、视图类型(包括系统私有类型)与布局约束。中间区域显示视图的详细样式、尺寸、层次等,可以在空白处拖动鼠标以不同视角观察和调试界面。右侧会根据所选内容显示其不同属性。
选中UIImageView,在右侧打开尺寸窗口,在Auto Layout区域可以看到4个黑色的约束,其中两个就定义了宽度w为133点,高度h为133点,并且后面加了(content size)表示此约束是自身内容尺寸约束。视图调试工具对解决界面自动布局问题很有帮助,当出现问题却又不知什么原因的时候,不妨用该工具调试。
当然,我们也可以使用代码打印出某个视图的自动布局约束,这也是常用的调试手段。在Main.storyboard中选中Head Image View并在属性窗口中设置其Tag为99,然后在ViewController.m中添加viewDidAppear:方法:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
UIView* headImageView = [self.view viewWithTag:99];
for (NSLayoutConstraint* eachCon in headImageView.constraints)
{
NSLog(@"\n%@\nPriority:%f", eachCon, eachCon.priority);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
运行后的输出为:
<NSContentSizeLayoutConstraint:0x7aeda9e0 H:[head(133)] Hug:251 CompressionResistance:750 (Names: head:0x7af84130 )>
Priority:1000.000000
<NSContentSizeLayoutConstraint:0x7aedab30 V:[head(133)] Hug:251 CompressionResistance:750 (Names: head:0x7af84130 )>
Priority:1000.000000
- 1
- 2
- 3
- 4
- 5
可以看到打印的每条约束都使用VFL语言进行描述。至于什么是Hug和CompressionResistance,在后面会讲到抗挤压与抗拉抻效果。另外我们还打印出了约束的优先级,在后面也会讲解优先级的作用。
(请思考,可否将上面的代码不放在viewDidAppear:方法中,而是放在viewDidLoad方法中执行?为什么?)
如果开发者显式给出了宽度和高度约束,则默认情况下,以显式约束为准。选中Head Image View并添加宽度120点、高度120点的约束,重新编译运行程序,则视图调试工具显示其布局约束为:
其中的自身内容尺寸约束为灰色,表示不起作用。同时控制台输出为:
<NSLayoutConstraint:0x7c189ac0 H:[head(120)] (Names: head:0x7c1897a0 )>
Priority:1000.000000
<NSLayoutConstraint:0x7c189af0 V:[head(120)] (Names: head:0x7c1897a0 )>
Priority:1000.000000
<NSContentSizeLayoutConstraint:0x7bea62a0 H:[head(133)] Hug:251 CompressionResistance:750 (Names: head:0x7c1897a0 )>
Priority:1000.000000
<NSContentSizeLayoutConstraint:0x7bea63f0 V:[head(133)] Hug:251 CompressionResistance:750 (Names: head:0x7c1897a0 )>
Priority:1000.000000
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
二、创建约束的对象关联并修改约束
我们这个用户登录的app有一个不太好的用户体验,那就是在输入用户名和密码时,键盘会遮挡住文本输入框和登录按钮:
我们需要在键盘弹出或者收回时更新界面布局,主要有以下几种方式来更新界面布局:
- 修改约束的常量值
- 设置约束激活属性(删除旧约束并添加新约束)
- 调整约束的优先级
当只需要平移视图的位置就能解决问题时,可以使用第一种方法直接修改某一约束的常量值。这种方式最简单最高效,但是不能解决所有问题,这时可以使用后两种方式。
1. 修改约束常量值
对于这个App来说,所有控件的垂直位置都是基于位于中央的文本控件的垂直位置而定。我们打算在键盘未弹出时,文本控件顶部距离Top Layout Guide的垂直间距为250(label.top = 250);在键盘弹出时,将该间距缩小为0(label.top = 0)。
Interface Builder不仅允许我们创建视图对象的IBOutlet对象关联,还可以创建约束对象的对象关联,这样就能通过代码来访问并修改某个约束。
回到Xcode打开Main.storyboard,选中文本控件User Name and Pwd Label,在右侧的尺寸窗口中单击顶部约束蓝线,并双击下方的Top Space to: Top Layout Guide约束:
此时左侧的项目窗口会高亮选中该约束。切换到助手编辑器,确认右侧窗口中打开的是ViewController.m,然后选中该约束并按住⌃键拖拽 到右侧ViewController类的类扩展区域,在弹出窗口中将其命名为userNamePwdLabelTopCons,点击Connect按钮就 创建了约束对象的对象关联,其步骤类似于创建视图的对象关联。
接下来ViewController类需要响应键盘弹出和收回事件,向ViewController类的viewDidLoad方法中添加如下代码:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
- 1
- 2
UIKeyboardWillShowNotification与UIKeyboardWillHideNotification这两个通知消息会 在键盘即将弹出以及键盘即将收回时抛出,我们可以在keyboardWillShow:和keyboardWillHide:这两个方法中修改 userNamePwdLabelTopCons约束。
注意,对于约束的如下几个重要属性:
/* accessors
firstItem.firstAttribute {==,<=,>=} secondItem.secondAttribute * multiplier + constant
*/
@property (readonly, assign) id firstItem;
@property (readonly) NSLayoutAttribute firstAttribute;
@property (readonly) NSLayoutRelation relation;
@property (readonly, assign) id secondItem;
@property (readonly) NSLayoutAttribute secondAttribute;
@property (readonly) CGFloat multiplier;
/* Unlike the other properties, the constant may be modified after constraint creation. Setting the constant on an existing constraint performs much better than removing the constraint and adding a new one that's just like the old but for having a new constant.
*/
@property CGFloat constant;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
当使用代码来修改约束时,只能修改约束的常量值constant。一旦创建了约束,其他只读属性都是无法修改的,特别要注意的是比例系数multiplier也是只读的。
然后向ViewController类添加如下代码:
- (void)keyboardWillShow:(NSNotification *)notification
{
//在键盘弹出时,文本控件顶部距离Top Layout Guide的垂直间距为0
self.userNamePwdLabelTopCons.constant = 0.0f;
}
- (void)keyboardWillHide:(NSNotification *)notification
{
//键盘未弹出时,文本控件顶部距离Top Layout Guide的垂直间距为250
self.userNamePwdLabelTopCons.constant = 250.0f;
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
别忘记在dealloc方法中移除键盘事件监听。编译运行程序,点击文本输入框,这一次键盘弹出后由于文本控件上移,所有界面控件的位置都上移了,就不会被键盘挡住了。
由于ViewController类重写了触屏方法,并取消了文本输入框的第一响应者状态,因此此时点击文本输入框之外的区域就会收起键盘,这样就会恢复到原始布局状态。
#pragma mark - Touch event Handler
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesBegan:touches withEvent:event];
[self.userNameTextField resignFirstResponder];
[self.userPwdTextField resignFirstResponder];
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
2. 修改约束激活属性,或者删除旧约束并添加新约束
现在我们打算这样布局界面:在键盘未弹出时,文本控件垂直中心与其父视图垂直中心相同(label.centerY = superView.centerY);在键盘弹出时,文本控件垂直中心是其父视图垂直中心的0.6倍(label.centerY = 0.6 * superView.centerY)。
对于刚才的例子,我们可以通过修改某个约束的常量值来解决问题。但是这次不一样了,比例系数是只读的,在约束创建之后就不可以修改。所以对于这种情况,我们就不能对某个约束进行修改,而是需要把不需要的约束去掉,然后添加一个新的约束。
在Main.storyboard中,在左侧视图层次窗口中选中文本控件距离顶部Top Layout Guide的约束Vertical Space - (250) - User Name and Pwd Label - Top Layout Guide,然后按下Delete键删除该约束。
然后选中文本控件User Name and Pwd Label,点击Align菜单,勾选Vertical Center in Container并取值为0,点击Add 1 Constraint按钮。这样就使得文本控件垂直居中。
重复上图中的步骤,再次创建一个文本控件垂直居中的约束。选中文本控件User Name and Pwd Label,在右侧尺寸窗口中单击垂直中心约束蓝线,下方会列出刚才我们创建的两个垂直居中约束。
双击上方的Align Center Y to: Superview约束,确保First Item为User Name and Pwd Label.Center Y,Second Item为SuperView.Center Y。如果不是,则点击First Item或者Second Item下拉菜单,选中Reverse First And Second Item,对调First Item与Second Item(本系列第二篇文章介绍过的相对关系与反函数)。然后在右侧尺寸窗口中将Multiplier的值由1改为0.6:
改完之后Interface Builder会出现错误提示,因为我们刚刚添加的这两个约束是彼此冲突的(label.centerY = superView.centerY && label.centerY = 0.6 * superView.centerY,这不可能同时满足)。
点击视图层次窗口上方的红色箭头,Interface Builder会列出上述两个彼此冲突的约束。选中某个约束,右侧尺寸窗口会列出该约束的详细信息。我们选中Multiplier为0.6的那个约束,然后在右侧尺寸窗口下方取消勾选Installed选框。
Installed选框的值就对应约束对象的active属性的值,即表示该约束是否为激活状态,勾选表示激活状态(生效状态,active属性为 YES),不勾选表示未激活状态(无效状态,active属性为NO)。现在Multiplier为0.6的那个约束不再生效,因此就不存在约束冲突了。
然后按照上文中介绍的方法,添加上面两个约束的对象关联,Multiplier为1的约束命名为 labelCenterYNormalCons,Multiplier为0.6的约束命名为labelCenterYKeyboardCons,且 Storage设置为Strong:
这是由于需要向视图动态添加或者移除约束,因此需要确保使用强引用确保约束对象不会被回收。
然后修改keyboardWillShow:与keyboardWillHide:方法:
- (void)keyboardWillShow:(NSNotification *)notification
{
self.labelCenterYNormalCons.active = NO;
self.labelCenterYKeyboardCons.active = YES;
}
- (void)keyboardWillHide:(NSNotification *)notification
{
self.labelCenterYKeyboardCons.active = NO;
self.labelCenterYNormalCons.active = YES;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
注意,尽量先设置需要将active置为NO的约束,然后再设置需要将active置为YES的约束,如果颠倒上面两条语句的话,可能会引起运行时 约束错误。另外由于active属性是iOS 8 SDK新添加的属性,对于iOS 6与iOS 7来说,需要调用addConstraint:与removeConstraint:方法。编译运行如图:
3. 调整不同约束的优先级
刚才的例子是通过调整不同约束的active属性(删旧添新)来实现界面布局调整。另外还有一种方式也很重要,就是下面说的调整不同约束的优先级。
每个约束都会具有优先级(Priority),对应NSLayoutConstraint对象的priority属性:
@interface NSLayoutConstraint : NSObject
......
/* If a constraint's priority level is less than UILayoutPriorityRequired, then it is optional. Higher priority constraints are met before lower priority constraints.
Constraint satisfaction is not all or nothing. If a constraint 'a == b' is optional, that means we will attempt to minimize 'abs(a-b)'.
This property may only be modified as part of initial set up. An exception will be thrown if it is set after a constraint has been added to a view.
*/
@property UILayoutPriority priority;
......
@end
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
优先级是一个浮点值,取值范围从1(最低)到1000(最高)。一些常用的优先级值被定义了别名:
typedef float UILayoutPriority;
static const UILayoutPriority UILayoutPriorityRequired NS_AVAILABLE_IOS(6_0) = 1000; // A required constraint. Do not exceed this.
static const UILayoutPriority UILayoutPriorityDefaultHigh NS_AVAILABLE_IOS(6_0) = 750; // This is the priority level with which a button resists compressing its content.
static const UILayoutPriority UILayoutPriorityDefaultLow NS_AVAILABLE_IOS(6_0) = 250; // This is the priority level at which a button hugs its contents horizontally.
static const UILayoutPriority UILayoutPriorityFittingSizeLevel NS_AVAILABLE_IOS(6_0) = 50;
- 1
- 2
- 3
- 4
- 5
具有优先级1000(UILayoutPriorityRequired)的约束为强制约束(Required Constraint),也就是必须要满足的约束;优先级小于1000的约束为可选约束(Optional Constraint)。默认创建的是强制约束。
在使用自动布局后,某个视图的具体位置和尺寸可能由多个约束来共同决定。这些约束会按照优先级从高到低的顺序来对视图进行布局,也就是视图会优先满足优先级高的约束,然后满足优先级低的约束。
对于上面的例子,我们曾经创建了两个相互冲突的约束,即label.centerY = superView.centerY && label.centerY = 0.6 * superView.centerY。之所以出现冲突,是因为这两者的优先级相同,都是1000。但是如果将其中一个的优先级降低,那么就不会存在冲突, 因为优先级高的那个约束会优先起作用。
打开Main.storyboard,将Multiplier为0.6的约束的Installed选框勾上,此时再次出现布局冲突。接着在右侧尺寸 窗口中将其Priority设置为250,此时布局冲突消失,同时注意到界面中代表该约束的蓝线变为虚线,表示这是一个优先级较低的可选约束。
以同样的方式,设置另外的Multiplier为1的垂直居中约束的Priority为750。
然后将keyboardWillShow:与keyboardWillHide:方法修改如下:
- (void)keyboardWillShow:(NSNotification *)notification
{
self.labelCenterYNormalCons.priority = UILayoutPriorityDefaultLow;
self.labelCenterYKeyboardCons.priority = UILayoutPriorityDefaultHigh;
}
- (void)keyboardWillHide:(NSNotification *)notification
{
self.labelCenterYKeyboardCons.priority = UILayoutPriorityDefaultLow;
self.labelCenterYNormalCons.priority = UILayoutPriorityDefaultHigh;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
重新编译运行,效果同上。
需要注意的是,只能修改可选约束的优先级,也就是说:
- 不允许将优先级由小于1000的值改为1000
- 不允许将优先级由1000修改为小于1000的值
例如,如果将优先级由250修改为1000,则会抛出异常:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Mutating a priority from required to not on an installed constraint (or vice-versa) is not supported. You passed priority 1000 and the existing priority was 250.'
- 1
这就是为什么在storyboard中要先将两者的约束分别设置为750和250的原因。
4. 使用动画更新界面布局
由于修改的约束会立即生效,因此当键盘弹出或者收回时,控件位置的变化显得非常生硬。我们不妨使用动画来更新界面布局,方法是调用UIView的静 态动画方法,在动画块代码体中向需要更新约束的视图对象调用layoutIfNeeded方法即可。分别向keyboardWillShow:和 keyboardWillHide:方法的最后插入如下代码:
[UIView animateWithDuration:0.25f animations:^
{
[self.view layoutIfNeeded];
}];
- 1
- 2
- 3
- 4
重新编译运行,由于使用了动画来重新对界面布局,变化的过程就显得非常自然了。
三、自身内容尺寸约束的抗挤压与抗拉抻效果
前面讲了,某些控件具有自身内容尺寸约束,也就是根据自身内容的大小添加必要的约束。我们不妨将这类控件看作是一个弹簧。
弹簧会有自身固有长度,当有外力作用时,弹簧会抵抗外力作用,尽量接近固有长度。
- 抗拉抻:当外力拉长弹簧时,弹簧长度大于固有长度,且产生向内收的力阻止外力拉抻,且尽量维持长度接近自身固有长度。
- 抗挤压:当外力挤压弹簧时,弹簧长度小于固有长度,且产生向外顶的力阻止外力挤压,且尽量维持长度接近自身固有长度。
ViewController类的viewDidAppear:方法打印出了头像图片视图的所有约束:
<NSLayoutConstraint:0x7c189ac0 H:[head(120)] (Names: head:0x7c1897a0 )>
Priority:1000.000000
<NSLayoutConstraint:0x7c189af0 V:[head(120)] (Names: head:0x7c1897a0 )>
Priority:1000.000000
<NSContentSizeLayoutConstraint:0x7bea62a0 H:[head(133)] Hug:251 CompressionResistance:750 (Names: head:0x7c1897a0 )>
Priority:1000.000000
<NSContentSizeLayoutConstraint:0x7bea63f0 V:[head(133)] Hug:251 CompressionResistance:750 (Names: head:0x7c1897a0 )>
Priority:1000.000000
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
对于自身内容尺寸约束,Hug值表示抗拉抻优先级,CompressionResistance值表示抗压缩优先级。Hug值越高越难被拉抻,CompressionResistance值越高越难被压缩。
由于自身内容是运行时动态变化的,我们可以通过这两个优先级来决定控件是否允许在某些条件下被压缩、拉抻。对于上面的输出结果,图片本身大小 133*133,抗压优先级CompressionResistance为750,显式宽度约束为120优先级为1000。由于显示宽度优先级大于抗压优 先级,所以最终图片宽度为120。但是,当我们降低显式宽度约束的优先级,令其小于抗压优先级时,以自身宽度133为主。在 Main.storyboard中选中用户头像,双击图片下方的显式宽度约束,将其优先级Priority设置为500。
注意到上图中红圈部分,头像宽度变为133,高度维持120。这说明当显式约束优先级高于抗压抗拉优先级时,以显式约束为准;当显式约束优先级小于抗压抗拉优先级时,以自身内容约束为准。
再举一个例子,当我们输入用户名和密码,然后点击程序的登录按钮后,下方的两个文本控件会显示出输入的用户名和密码:
两个文本控件不超过父视图的两边,且两者间具有水平间距互不覆盖。当输入的用户名和密码比较短时,两者都能完整显示。但是当内容较长时,我们发现左 侧文本控件被截断了。如果我们希望保持左侧文本框完整,必要时截断右侧文本框,则可以令左侧文本框的抗压优先级高于右侧文本框抗压优先级。可以在IB中直 接设置抗压抗拉优先级。在Main.storyboard的左侧视图结构窗口中,选中左侧文本控件User Name Label,在右侧尺寸窗口的Content Compression Resistance Priority部分,将Horizontal的值改为751。重新编译运行,输入用户名和密码,现在左侧文本控件完整,右侧文本控件被截断。
这是由于左侧抗压优先级高于右侧抗压优先级的缘故。
当然我们也可以使用代码来设置水平和垂直抗压抗拉优先级,方法是调用UIView的如下几个方法:
- (UILayoutPriority)contentCompressionResistancePriorityForAxis:(UILayoutConstraintAxis)axis;
- (void)setContentCompressionResistancePriority:(UILayoutPriority)priority forAxis:(UILayoutConstraintAxis)axis;
- (UILayoutPriority)contentHuggingPriorityForAxis:(UILayoutConstraintAxis)axis;
- (void)setContentHuggingPriority:(UILayoutPriority)priority forAxis:(UILayoutConstraintAxis)axis;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
在此就不举例赘述了。
四、总结
本篇文章讲解的内容比较繁杂,程序最终的代码如下。
http://yunpan.cn/cQ4snekTsfyMC (提取码:57f6)
如果你有关于Autolayout的任何问题,请在我的CSDN博客留言。
在下一篇文章中,我想讲一讲iOS 8中关于设备适配、Adaptive Layout与Size Class的使用,敬请期待。
iOS 8 Auto Layout界面自动布局系列5-自身内容尺寸约束、修改约束、布局动画的更多相关文章
- iOS 8 Auto Layout界面自动布局系列2-使用Xcode的Interface Builder添加布局约束
http://blog.csdn.net/pucker/article/details/41843511 上一篇文章<iOS 8界面自动布局系列-1>简要介绍了iOS界面布局方式的前世今生 ...
- 【转 iOS 8 Auto Layout界面自动布局系列2-使用Xcode的Interface Builder添加布局约束
原文网址:http://blog.csdn.net/pucker/article/details/41843511 上一篇文章<iOS 8界面自动布局系列-1>简要介绍了iOS界面布局方式 ...
- iOS Programming Auto Layout: Programmatic Constraints 自动布局:通过编程限制
iOS Programming Auto Layout: Programmatic Constraints 1. However, if your views are created in co ...
- (iOS)使用auto layout进行复杂布局时,UILabel的相关trick
本文转载至 http://blog.csdn.net/madongchunqiu/article/details/47960745 本文首发于CSDN:http://blog.csdn.net/ma ...
- 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 Stac ...
- IOS使用Auto Layout中的VFL适配
做登录页面,之前做都是用frame做,今天想着用Auto Layout中的VFL来做.觉得做的效果还是可以的(自恋一下下). 首先看下效果图和标记图 自己在做的过程中也遇到了好多问题,不过也一个一个的 ...
- iOS之 Auto Layout
1. 动画 // 修改从 StoryBoard 绑定到类的约束的值 self.boxView.constant += 80 // 在动画闭包里对其父级进行 layoutIfNeeded() UIVie ...
- iOS 开发实践之 Auto Layout
原:http://xuexuefeng.com/autolayout/?utm_source=tuicool 本文是博主 iOS 开发实践系列中的一篇,主要讲述 iOS 中 Auto Layout(自 ...
- 【转】使用 Auto Layout 的典型痛点和技巧
layoutIfNeeded()强制立刻更新布局 原文网址:http://www.jianshu.com/p/0f031606e5f2 官方文档:Auto Layout Guide 加上去年WWDC上 ...
随机推荐
- 运行第一个Hadoop程序,WordCount
系统: Ubuntu14.04 Hadoop版本: 2.7.2 参照http://www.cnblogs.com/taichu/p/5264185.html中的分享,来学习运行第一个hadoop程序. ...
- phpcms v9升级后台无法上传缩略图的原因分析
phpcms V9 是目前国内使用人数最多的一款开源免费的CMS系统,正是由于他的免费性,开源性,以及其自身的功能性比较强大,所以倍受许多站长朋友们的亲来,以及许多的公司的喜欢.phpcms也为了完善 ...
- GridView Footer页脚统计实现多行
在使用GridView时有时会需要多行显示页脚Footer的统计,下面是一种解决方法,仅仅供各位参考 在GridView的RowCreated事件中添加多行页脚,实例代码如下: protected v ...
- asp.net 的那点事(2、浏览器和一般处理程序)
从今天开始我们接着来学习:asp.net中一般处理程序和浏览器的通信. 一.第一个图解: 从图解中我们看出,整个过程是:"请求---处理---响应".这个也就是经常面试的时候,面试 ...
- Python函数小结(1)--参数类型(*, ** 的区别), 闭包
刚开始学习python,python相对于java确实要简洁易用得多.内存回收类似hotspot的可达性分析, 不可变对象也如同java得Integer类型,with函数类似新版本C++的特性,总体来 ...
- uC/OS-II内核架构解析(2)---uC/OS-II基本介绍(转)
1. uC/OS-II文件结构 2. uC/OS-II组成部分 uC/OS-II大致可以分成系统核心(包含任务调度).任务管理.时间管理.多任务同步与通信.内存管理.CPU移植等部分. (1) 核心部 ...
- ZooKeeper笔记--集群安装配置 【转】
ZooKeeper是一个分布式开源框架,提供了协调分布式应用的基本服务,它向外部应用暴露一组通用服务——分布式同步(Distributed Synchronization).命名服务(Naming S ...
- 安卓 eclipse项目创建
一. 创建项目工程 1. 点击 file -> new -> Android Application project -> 2. 创建工程项目名字 自己命名 (注: 不要出现 ...
- 对CNN模块的分析
对 CNN 模块的分析,该论文(Systematic evaluation of CNN advances on the ImageNet)已经做过了,里面的发现是非常有帮助的: 使用没有 bat ...
- Android 源码编译环境搭建(64位Ubuntu)各种依赖包安装
1.准备: 普通PC(要求能上网), PC的操作系统Ubuntu 10.04 LTS(64位的),已经下载好的Android 1.6_r1的源代码. 2.Linux的依赖package安装: 为了更快 ...