那么我们先来看,什么是格式化的字符串约束。
说到格式化的字符串约束,要先提一个东西VFL:visual format language——格式化约束语言,这又是什么鬼?确实,这个东西写出来第一眼看上去真的不知道是什么鬼,就比如要设置一个label,距离上边100,左边20,宽高都为100,代码如下:
label.numberOfLines = 0;
label.translatesAutoresizingMaskIntoConstraints = NO;
label.backgroundColor = [UIColor redColor];
//label.text=@"12332322132131233213213";
[self.view addSubview:label];
NSArray * constraintArray = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-20-[label(100@1000)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(label)];
NSArray * constraintArray2 = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-100-[label(100)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(label)];
[self.view addConstraints:constraintArray];
[self.view addConstraints:constraintArray2];
效果如下:
代码少了很多,对吧,但是中间那部分字符串什么玩意?下面我们来解释一下。
VFL语言我个人而言,他很类似于古代的象形文字(不知道是否apple的工程师从其中得到灵感),对布局的约束设置是直观的用符号表达出来的,例如:
H:|-20-[label(100@1000)]
前面的H代表是水平的布局还是垂直的布局,H代表水平,V表示垂直,|表示父视图的边沿,-20-表示距离20px,[]内是要布局摆放的视图对象名,()中是约束的尺寸,H下则为宽度,V下则为高度,@后面的数字代表优先级。
创建方法中的options参数,用来设置对齐模式,不需要可以写0:
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参数是属性替换字典,例如我们上边用到的距离左边界20,如果这个20是一个变量width,我们可以将20的地方换成width,然后配置这个字典:@{@"width":@20},这样,在布局时,系统会把width换成20。
views是对象的映射字典,原理也是将字符串中的对象名label映射成真实的对象,NSDictionaryOfVariableBindings会帮我们生成这样的字典,我们只需要想对象传进去即可,如果要手动创建这字典,格式如下:@{@"label":label}.
三、使用aotulayout设计一个聊天界面的输入框
仔细观察QQ或者其他聊天工具的app上的输入框,会发现他非常智能,宽度会随着我们输入文字的行数进行自适应,并且这个宽度不是无限增大的,当我们文字多到一定行数,宽度会保持不变,文本框可以进行内容滑动,如果不用autolayout,这个功能会比较棘手一些,但是使用它,会发现这是如此的容易:
@interface ViewController ()<UITextViewDelegate>
{
UITextView * textView ;
NSArray * array1;
NSArray * array2;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
textView = [[UITextView alloc]init];
textView.layer.borderColor = [[UIColor grayColor]CGColor];
textView.layer.borderWidth = 1;
textView.translatesAutoresizingMaskIntoConstraints = NO;
textView.delegate=self;
[self.view addSubview:textView];
array1 = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-100-[textView]-100-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(textView)];
array2 = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-150-[textView(30)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(textView)];
[self.view addConstraints:array1];
[self.view addConstraints:array2];
}
-(BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text{
//当文本高度大于textView的高度并且小于100时,更新约束
if (textView.contentSize.height>textView.frame.size.height&&textView.contentSize.height<100) {
float hight =textView.contentSize.height;
//将以前的移除掉
[self.view removeConstraints:array1];
[self.view removeConstraints:array2];
array1 = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-100-[textView]-100-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(textView)];
array2 = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-150-[textView(hight)]" options:0 metrics:@{@"hight":[NSNumber numberWithFloat:hight]} views:NSDictionaryOfVariableBindings(textView)];
[self.view addConstraints:array1];
[self.view addConstraints:array2];
}
//更新约束
[self.view updateConstraintsIfNeeded];
return YES;
}
现在,当我们进行输入的时候,textView的高度可以自适应文字行数了。
四、通过动画改善更新约束时的效果
这一点非常coll,上面我们已经实现了textView随文本的行数高度进行自适应,但是变化的效果十分生硬,还要apple的动画框架支持autolayout,把刚才调用更新约束的地方进行如下修改:
[UIView animateWithDuration:1 animations:^{
[self.view layoutIfNeeded];
}];
试试看,变换的效果已经非常平滑了。