WWDC12 视频"最佳做法,掌握自动布局",涵盖动画。它讨论了如何更新限制使用 CoreAnimation
由此可得: 要想用约束设置动画效果需要在动画方法中更新布局
//第一种 只执行一次 [UIView animateWithDuration:0.25 animations:^{ //想要用约束实现动画需要更新布局 [self.view layoutIfNeeded];//调用layoutIfNeeded 告知页面布局立刻更新。(系统内部调用layoutSubviews重写布局) } completion:^(BOOL finished) { }]; //第二种 [UIView beginAnimations:nil context:nil]; [UIView setAnimationRepeatCount:10]; [self layoutIfNeeded];//调用更改约束的view 的父视图的layoutIfNeeded 不要掉自己 [UIView commitAnimations];
两种方式一个是用在 xib 中加的约束 一个是用Masonry 加的约束 (对约束进行更改都可以实现动画)
AutoLayout
这是自定义了一个view 里面放里一个蓝色的lineView
#import "CustomView.h" #import "Masonry.h" @interface CustomView () @property (weak, nonatomic) IBOutlet UILabel *label; @property (weak, nonatomic) IBOutlet UIView *lineView; @property (weak, nonatomic) IBOutlet NSLayoutConstraint *lineCenterConstraint; @property (weak, nonatomic) IBOutlet NSLayoutConstraint *lineTopConstraint; @end @implementation CustomView + (instancetype)loadCustomView{ return [[[NSBundle mainBundle]loadNibNamed:@"CustomView" owner:nil options:nil]firstObject]; } //注意constraint是约束限制 constant是常数 - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ //1.先更改约束 (y = kx + b b是常数 (constant) 基于中心的0 负数是减 整数是加) self.lineCenterConstraint.constant = -self.frame.size.width/4; self.lineTopConstraint.constant = 70; //2.在动画中更改布局 [UIView animateWithDuration:1.0 animations:^{ self.lineView.transform = CGAffineTransformRotate(self.lineView.transform, M_PI); [self layoutIfNeeded];//调用更改约束的view 的父视图的layoutIfNeeded 不要掉自己self.lineView } completion:^(BOOL finished) { }]; // [UIView beginAnimations:nil context:nil]; // [UIView setAnimationRepeatCount:10]; // [self layoutIfNeeded];//调用更改约束的view 的父视图的layoutIfNeeded 不要掉自己self.lineView // self.lineView.transform = CGAffineTransformRotate(self.lineView.transform, M_PI); // [UIView commitAnimations]; }
运行结果
动画前
动画后
第三方框架Masonry
常用方法
// 设置约束 初次设置约束使用 (NSArray *)mas_makeConstraints // 更改约束 更新mas_makeConstraints里面的约束使用 (NSArray *)mas_updateConstraints // 重新设置约束 先移除所有约束,再新增约束 (NSArray *)mas_remakeConstraints
常用属性
//width >= 200 && width <= 400 make.width.greaterThanOrEqualTo(@200); make.width.lessThanOrEqualTo(@400)
.priority允许你指定一个精确的优先级,数值越大优先级越高.最高1000. .priorityHigh等价于 UILayoutPriorityDefaultHigh .优先级值为 750. .priorityMedium介于高优先级和低优先级之间,优先级值在 250~750之间. .priorityLow等价于 UILayoutPriorityDefaultLow , 优先级值为 250.
make.left.greaterThanOrEqualTo(label.mas_left).with.priorityLow(); make.top.equalTo(label.mas_top).with.priority(600);
//使 make 的centerX和 centerY = button1 make.center.equalTo(button1) //使make的 centerX = superview.centerX - 5, centerY = superview.centerY + 10 make.center.equalTo(superview).centerOffset(CGPointMake(-5, 10))
make.width.equalTo(superview).multipliedBy(0.25);
- (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; } - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. __weak typeof(self) weakSelf = self; _textField = [UITextField new]; _textField.backgroundColor = [UIColor redColor]; [self.view addSubview:_textField]; [_textField mas_makeConstraints:^(MASConstraintMaker *make) { //left,right,centerx,y 不能共存只能有其二 make.left.mas_equalTo(20); // make.right.mas_equalTo(-60); make.centerX.equalTo(weakSelf.view); make.height.mas_equalTo(40); make.bottom.mas_equalTo(0); }]; // 注册键盘通知 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrameNotification:) name:UIKeyboardWillChangeFrameNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHideNotification:) name:UIKeyboardWillHideNotification object:nil]; } - (void)keyboardWillChangeFrameNotification:(NSNotification *)notification { // 获取键盘基本信息(动画时长与键盘高度) NSDictionary *userInfo = [notification userInfo]; CGRect rect = [userInfo[UIKeyboardFrameBeginUserInfoKey] CGRectValue]; CGFloat keyboardHeight = CGRectGetHeight(rect); CGFloat keyboardDuration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]; // 修改下边距约束 [_textField mas_updateConstraints:^(MASConstraintMaker *make) { make.bottom.mas_equalTo(-keyboardHeight); }]; // 重新布局 [UIView animateWithDuration:keyboardDuration animations:^{ [self.view layoutIfNeeded]; }]; } - (void)keyboardWillHideNotification:(NSNotification *)notification { // 获得键盘动画时长 NSDictionary *userInfo = [notification userInfo]; CGFloat keyboardDuration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]; // 修改为以前的约束(距下边距0) [_textField mas_updateConstraints:^(MASConstraintMaker *make) { make.bottom.mas_equalTo(0); }]; // 重新布局 [UIView animateWithDuration:keyboardDuration animations:^{ [self.view layoutIfNeeded]; }]; } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesBegan:touches withEvent:event]; [self.view endEditing:YES]; }
以上是动画 下面是用masony三控件等宽间距(xib 加约束的方式还没有找到合适的)
假设有多个View,我们需要对其尺寸做批量设置
NSValue *sizeValue = [NSValue valueWithCGSize:CGSizeMake(100, 50)]; [@[view1,view2,view3] mas_makeConstraints:^(MASConstraintMaker *make) { make.size.equalTo(sizeValue); }];
用masony三控件等宽间距
方法一和方法二都在 NSArray+MASAdditions
中
方法一:
array 的 mas_distributeViewsAlongAxis withFixedSpacing
变化的是控件的长度或宽度 间距不变
定义一个存放三个控件的数组NSArray *array;
array = @[greenView,redView,blueView];
注意:
数组里面的元素不能小于1个,要不会报错 views to distribute need to bigger than one
- (void)getHorizontalone { //方法一,array 的 mas_distributeViewsAlongAxis /** * 多个控件固定间隔的等间隔排列,变化的是控件的长度或者宽度值 * * @param axisType 轴线方向 * @param fixedSpacing 间隔大小 * @param leadSpacing 头部间隔 * @param tailSpacing 尾部间隔 */ // MASAxisTypeHorizontal 水平 // MASAxisTypeVertical 垂直 [arrayList mas_distributeViewsAlongAxis:MASAxisTypeHorizontal withFixedSpacing:20 leadSpacing:5 tailSpacing:5]; [arrayList mas_makeConstraints:^(MASConstraintMaker *make) { make.top.mas_equalTo(60); make.height.mas_equalTo(100); }];
方法二
array 的 mas_distributeViewsAlongAxis withFixedItemLength
控件size不变,变化的是间隙
// 竖直方向高度不变60 宽度左边右边20 间距变 - (void)getVertical { /** * 多个固定大小的控件的等间隔排列,变化的是间隔的空隙 * * @param axisType 轴线方向MASAxisTypeVertical 这时候withFixedItemLength是固定高度 * @param fixedItemLength 每个控件的固定长度或者宽度值 * @param leadSpacing 头部间隔 * @param tailSpacing 尾部间隔 */ [arrayList mas_distributeViewsAlongAxis:MASAxisTypeVertical withFixedItemLength:60 leadSpacing:40 tailSpacing:10]; [arrayList mas_makeConstraints:^(MASConstraintMaker *make) { // make.top.mas_equalTo(100); // make.height.mas_equalTo(100); make.left.mas_equalTo(20); make.right.mas_equalTo(-20); }];
方法三 :直接设置multiplier
实现等间距
for (NSUInteger i = 0; i < 4; i++) { UIView *itemView = [self getItemViewWithIndex:i]; [_containerView addSubview:itemView]; [itemView mas_makeConstraints:^(MASConstraintMaker *make) { make.width.and.height.equalTo(@(ITEM_SIZE)); make.centerY.equalTo(_containerView.mas_centerY); make.centerX.equalTo(_containerView.mas_right).multipliedBy(((CGFloat)i + 1) / ((CGFloat)ITEM_COUNT + 1)); }]; }
方法四: 利用透明等宽度的SpaceView实现等间距
UIView *lastSpaceView = [UIView new]; lastSpaceView.backgroundColor = [UIColor greenColor]; [_containerView1 addSubview:lastSpaceView]; [lastSpaceView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.and.top.and.bottom.equalTo(_containerView1); }]; for (NSUInteger i = 0; i < ITEM_COUNT; i++) { UIView *itemView = [self getItemViewWithIndex:i]; [_containerView1 addSubview:itemView]; [itemView mas_makeConstraints:^(MASConstraintMaker *make) { make.height.and.width.equalTo(@(ITEM_SIZE)); make.left.equalTo(lastSpaceView.mas_right); make.centerY.equalTo(_containerView1.mas_centerY); }]; UIView *spaceView = [UIView new]; spaceView.backgroundColor = [UIColor greenColor]; [_containerView1 addSubview:spaceView]; [spaceView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.equalTo(itemView.mas_right).with.priorityHigh(); // 降低优先级,防止宽度不够出现约束冲突 make.top.and.bottom.equalTo(_containerView1); make.width.equalTo(lastSpaceView.mas_width); }]; lastSpaceView = spaceView; } [lastSpaceView mas_makeConstraints:^(MASConstraintMaker *make) { make.right.equalTo(_containerView1.mas_right); }];
项目中还没有用到(一般这些方法都是重写然后再调用super 方法 然后在写一些其他的操作)
更新约束的方法 在view中
setNeedsUpdateConstraints:告知需要更新约束,但是不会立刻开始
updateConstraintsIfNeeded:告知立刻更新约束
updateConstraints:系统更新约束
在viewController 中
- (void)updateViewConstraints ; ViewController的View在更新视图布局时,会先调用ViewController的updateViewConstraints 方法。 我们可以通过重写这个方法去更新当前View的内部布局,而不用再继承这个View去重写-updateConstraints方法。我们在重写这个方法时,务必要调用 super 或者 调用当前View的 -updateConstraints 方法。
原文:http://www.cnblogs.com/junhuawang/p/6008536.html