本文可能涉及很多零碎的知识点,其中包括iOS应用开发的相关基础知识。以后会针对每个条目在进行深入研究,这里只是先做一个相关知识的概述总结。
Apple建议使用一种特殊化的语法在代码中创建约束——-视觉化格式语言。
例如:
两个UIView对象的水平间距始终保持在10点
左边UIView对象父视图的左边距保持在20点
右边UIView对象与父视图右边距保持在20点
@”H:|-20-[imageViewleft]-10-[imageViewRight]-20-|”
(H标示水平,|标示父窗口)
例如设置水平宽度:
@”V:[someView(==50)]”
约束是NSLayoutConstraint类的对象,在代码中创建和添加约束需要分为两个不同的步骤:
1.根据视觉化格式字符创建约束:
+ (NSArray<__kindof NSLayoutConstraint *> *)constraintsWithVisualFormat:(NSString *)format options:(NSLayoutFormatOptions)opts metrics:(NSDictionary<NSString *,id> *)metrics views:(NSDictionary<NSString *,id> *)views;
第一个参数:视觉格式化字符串,第二个和第三个一般都可以省略(0和nil),第四个参数是需要使用的视图对象名称数组(仅仅是一个字符串名称数组,所以如果想让他知道具体对象的话,还需要用字典将名称与视图关联起来。例如@“imageView”表示的是self.imageView对象);
具体事例代码:
[super viewDidLoad];
NSDictionary *nameMap = @{@"cView":self.cview,
@"label":self.label};
NSArray *horizontalConstraints =
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[cView]-0-"
options:0
metrics:nil
views:nameMap];
NSArray *verticalConstraints = [
NSLayoutConstraint constraintsWithVisualFormat:@"V:|-8-[cView]-8-"
options:0
metrics:nil
views:nameMap];
现在在代码中已经添加了NSLayoutConstraint对象数组,UIView有两个同时添加约束的实例方法
-(void)addContraints:(NSArray *)constraints
如何判断约束添加到那个视图里面了呢?以下是判断法则:
自动布局系统会根据内容大小为视图添加相应的约束,与其它约束不同,这类约束有两个优先级属性,放大优先级和缩小优先级。如果优先级大于1000,表示不允许自动布局系统机遇固有内容大小放大视图,如果小于1000,会在适当的时候放大。
- (void)setContentHuggingPriority:(UILayoutPriority)priority forAxis:(UILayoutConstraintAxis)axis;
视觉化格式语言能够实现大部分布局,但是如果想设置某个控件是根据另外一个计算而来的,那么就需要NSLayoutConstraint的另一个工厂方法:
+ (instancetype)constraintWithItem:(id)view1 attribute:(NSLayoutAttribute)attr1 relatedBy:(NSLayoutRelation)relation toItem:(id)view2 attribute:(NSLayoutAttribute)attr2 multiplier:(CGFloat)multiplier constant:(CGFloat)c;
苹果在引入自动布局系统之前,iOS应用移植使用自动缩放掩码来管理视图布局。
在默认情况下,视图会讲自动缩放掩码转化为对应的约束,这类约束一般会和手动添加的约束产生冲突,所以一般将translateAutoresizingMaskIntoConstraints设置NO
父-子关系:(当使用容器控制器的话,就是父子关系)
当使用view controller container的时候,就会产生拥有父子关系的试图控制器。
视图控制器容器的特性是:容器对象会将viewControllers中的视图作为子视图加入到自己的视图中。此外,容器对象通过都会有自己的默认外观。以UINavigationController对象为例,顶部是一个UINavigationBar对象,然后在余下的空间中显示topViewController的视图。
处在同一个父子关系下的视图控制器形成一个族系(family)。
以UINavigationController为例,某个UINavigationController对象和其下的viewController都属于同一个族系。
同一个族系可以有多个级别,例如,一个UITabBarController对象都可以包含一个UINavigation对象,而这个UINavigationController又可以包含一个UIViewController对象,在这种情况下三个视图控制器都处在同一个族系中。任何容器都可以通过viewController访问其子对象,而子对象也可以通过UIViewController对象的四个特定属性来访问其容器对象。
介绍四个特定属性:
navigationController、tabBarController、splitController。当某个视图控制器收到navigationController消息、tabBarController消息或splitViewController消息后,会沿着族系向上查找,直到找到对应的视图容器控制器,然后没有找到,相应的方法会返回nil
第四个属性:parentViewController;
显示-被显示关系
当某个视图控制器以模态形式显示另一个视图控制器时,就会产生拥有这种关系的视图控制器。当某个视图控制器(A)以模态形式显示另一个视图控制器(B)时,B的视图会覆盖A的视图。
此外,任何一个UIViewController对象都可以以模态的形式显示另一个试图控制器。
通过UIViewController对象的presentingViewController属性和presentedViewController属性,可以得到指向相应视图控制器的指针。当某个视图控制器(A)以模态显示试图控制器B,那么A的presentedViewController属性指向B,B的presentingViewController属性指向A。
显示与被显示关系中的族系
在显示-被显示关系中,位于关系两头的视图控制器不会处于同一个族系中。被显示的视图控制器会有自己的族系,这个族系可以只有一个UIViewController对象,也可以有多个UIViewController对象组成。
一根手指对应一个UITouch对象。
UITouch对象和事件响应方法的工作机制做一个归纳:
1.UITouch对象对一个手指。只要手指没有离开屏幕,相应的UITouch就会一直存在。这些UITouch对象会保存手指的相应位置。
2.触摸事件持续过程中,无论发生什么,最初发生触摸事件的那个试图都会在各个阶段收到相应的触摸事件消息。即使离开了该试图的Frame,系统还是会向该试图发送touchesMove:withEvent:和touchesEnded:withEvent:消息。也就是说,当某个试图发生触摸事件后,试图将永远拥有所有的UITouch对象。
(如果用户在执行触摸操作时感觉反应迟钝,就很有可能是因为应用程序的某个方法占用了大量CPU时间,导致队列堵塞)
本博客主要来自对《疯狂iOS讲义》、《iOS编程(第四版)》的总结。如有不不同见解,请留言交流。