抛出问题:为何在用到用到constraint的动画时以下代码无法实现动画的功能 ,没有动画直接刷新UI跳到80

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[UIView animateWithDuration:2.0 animations:^{ self.blueViewH.constant = ; }];
}

而我们直接使用frame的时候动画是可以实现的

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{ [UIView animateWithDuration:2.0 animations:^{ CGRect size =self.blueView.frame; size.size.height = ; self.blueView.frame = size;//注意 frame的更改会调用父控件的 layoutSubviews 更新UI }];
}

思考尝试解决

没有动画效果 系统直接刷新渲染了

我们 手动强制更新刷新UI 放到动画里面试一下:对NSLayoutConstraint的对象赋值之后调用layoutIfNeeded方法

注意:layoutIfNeeded方法只会刷新子控件,因此要使用必须通过它的父类

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
self.blueViewW.constant = ; //frame/bound发生改变 (系统会对布局进行渲染 但是想做动画的话 需要如下自己执行渲染) [UIView animateWithDuration:2.0 animations:^{
// 对布局进行渲染
[self.view layoutIfNeeded]; //layoutIfNeeded方法只会刷新子控件,因此要使用必须通过它的父类 }]; // //动画的方式2(没有上面的常用)
// [UIView beginAnimations:nil context:nil];
// [UIView setAnimationRepeatCount:10];
// [self.view layoutIfNeeded];
// [UIView commitAnimations];
}

原理推测:

NSLayoutConstraint的本质就是在系统底层转换为frame。立刻渲染 要想动画需要把手动更新刷新UI 放到动画里 这样才能动画 要不然就没有动画直接刷新UI跳到80

一个view的frame或bounds发生变化时,系统会设置一个flag给这个view,当下一个渲染时机到来时系统会重新按新的布局来渲染视图;

因此我们调用layoutIfNeeded方法对"self.blueViewW.constant = 80;" 不等下一渲染时机了 只要有标记,就直接刷新 实现了动画

实例应用如下(AutoLayout/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/;
self.lineTopConstraint.constant = ; //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(@);
make.width.lessThanOrEqualTo(@)

约束的优先级

.priority允许你指定一个精确的优先级,数值越大优先级越高.最高1000.
.priorityHigh等价于 UILayoutPriorityDefaultHigh .优先级值为 .
.priorityMedium介于高优先级和低优先级之间,优先级值在 ~750之间.
.priorityLow等价于 UILayoutPriorityDefaultLow , 优先级值为 .

优先级可以在约束的尾部添加:

make.left.greaterThanOrEqualTo(label.mas_left).with.priorityLow();
make.top.equalTo(label.mas_top).with.priority();

center 中心

//使 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))

指定宽度为父视图的 1/4.

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();
// make.right.mas_equalTo(-60);
make.centerX.equalTo(weakSelf.view);
make.height.mas_equalTo();
make.bottom.mas_equalTo();
}]; // 注册键盘通知
[[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();
}]; // 重新布局
[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(, )];
[@[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:
leadSpacing:
tailSpacing:];
[arrayList mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo();
make.height.mas_equalTo();
}];

方法二

array 的 mas_distributeViewsAlongAxis withFixedItemLength 控件size不变,变化的是间隙

// 竖直方向高度不变60 宽度左边右边20  间距变
- (void)getVertical
{
/**
* 多个固定大小的控件的等间隔排列,变化的是间隔的空隙
*
* @param axisType 轴线方向MASAxisTypeVertical 这时候withFixedItemLength是固定高度
* @param fixedItemLength 每个控件的固定长度或者宽度值
* @param leadSpacing 头部间隔
* @param tailSpacing 尾部间隔
*/
[arrayList mas_distributeViewsAlongAxis:MASAxisTypeVertical
withFixedItemLength:
leadSpacing:
tailSpacing:];
[arrayList mas_makeConstraints:^(MASConstraintMaker *make) {
// make.top.mas_equalTo(100);
// make.height.mas_equalTo(100);
make.left.mas_equalTo();
make.right.mas_equalTo(-);
}];

方法三 :直接设置multiplier实现等间距

for (NSUInteger i = ; i < ; 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 + ) / ((CGFloat)ITEM_COUNT + ));
}];
}

方法四: 利用透明等宽度的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 = ; 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 方法。

iOS - 布局NSLayoutConstraint动画的实现的更多相关文章

  1. iOS - 布局重绘机制相关方法的研究

    iOS View布局重绘机制相关方法 布局 - (void)layoutSubviews - (void)layoutIfNeeded- (void)setNeedsLayout —————————— ...

  2. iOS 视图,动画渲染机制探究

    腾讯Bugly特约作者:陈向文 终端的开发,首当其冲的就是视图.动画的渲染,切换等等.用户使用 App 时最直接的体验就是这个界面好不好看,动画炫不炫,滑动流不流畅.UI就是 App 的门面,它的体验 ...

  3. IOS中的动画菜单

    SvpplyTable(可折叠可张开的菜单动画) 允许你简单地创建可折叠可张开的菜单动画效果,灵感来自于Svpply app.不同表格项目使用JSON定义,你可以定义每个菜单项和任何子菜单,为每个项目 ...

  4. iOS 转场动画探究(一)

    什么是转场动画: 转场动画说的直接点就是你常见的界面跳转的时候看到的动画效果,我们比较常见的就是控制器之间的Push和Pop,还有Present和Dismiss的时候设置一下系统给我们的modalTr ...

  5. iOS学习——核心动画之Layer基础

    iOS学习——核心动画之Layer基础 1.CALayer是什么? CALayer我们又称它叫做层.在每个UIView内部都有一个layer这样一个属性,UIView之所以能够显示,就是因为它里面有这 ...

  6. iOS关于CoreAnimation动画知识总结

    一:UIKit动画 在介绍CoreAnimation动画前先简单介绍一下UIKit动画,大部分简单的动画都可以使用UIKit动画实现,如果想实现更复杂的效果,则需要使用Core Animation了: ...

  7. 转 iOS Core Animation 动画 入门学习(一)基础

    iOS Core Animation 动画 入门学习(一)基础 reference:https://developer.apple.com/library/ios/documentation/Coco ...

  8. iOS中的动画

    iOS中的动画 Core Animation Core Animation是一组非常强大的动画处理API,使用它能做出非常绚丽的动画效果,而且往往是事半功倍,使用它需要添加QuartzCore .fr ...

  9. IOS UIVIEW layer动画 总结(转)

    转发自:http://www.aichengxu.com/article/%CF%B5%CD%B3%D3%C5%BB%AF/16306_12.html   IOS UIVIEW layer动画 总结, ...

随机推荐

  1. mysql小题趣事

    题一 答案: case when +条件 +then 显示什么 +else+显示另外什么+end

  2. Pandas DataFrame 函数应用和映射

    apply Numpy 的ufuncs通用函数(元素级数组方法)也可用于操作pandas对象: 另一个常见的操作是,将函数应用到由各列或行所形成的一维数组上.Dataframe的apply方法即可实现 ...

  3. 7款开源ERP系统比较

    [网络转载] 现在有许多企业将ERP项目,在企 业中没有实施好,都归咎于软件产品不好.其实,这只是你们的借口.若想要将ERP软件真正与企业融合一体,首先得考虑企业的自身情况,再去选择适合的 ERP软件 ...

  4. 通过C#脚本实现旋转的立方体

    一.介绍 目的:通过一个简单的例子(鼠标点击,使立方体旋转和变色)熟悉Unity中C#脚本的编写. 软件环境:Unity 2017.3.0f3 . VS2013. 二.C#脚本实现 1,启动Unity ...

  5. Maven项目文档

    本教程学习如何一步到位地创建应用程序的文档.因此现在开始我们进入到  C:\MVN 创建 java 应用程序项目:consumerBanking. 进入到项目文件夹中执行以下命令 mvn 命令. C: ...

  6. MarkDown 使用说明示例

    一.标题 一级标题 二级标题 三级标题 四级标题 五级标题 六级标题 一级标题 这是 H2 这是 H3 一级和二级标题还有一种写法 就是下面加横杆,同时 超过2个的 = 和 - 都可以有效果. Thi ...

  7. Java 从静态代理到动态代理

    先举个静态代理的例子,可能多少有些不恰当,不过本次学习记录,重点不在于通信协议. 比如你在一个机房里,你不能联网,只能连通过一台能连公网的代理机器上网.你发送了一个http请求,将由代理帮你上网. 首 ...

  8. Http Cookie Manager、session

     1. JMeter Http Cookie Manager的作用: (1)自动管理 (2)象浏览器一样的存储和发送Cookie.如果你请求一个站点,然后他的Response中包含Cookie,Coo ...

  9. tomcat启动时设定环境变量

    在tomcat的bin目录中修改startup.bat 设置CATALINA_HOME set "CATALINA_HOME=F:\solr\apache-tomcat\apache-tom ...

  10. vue加百度统计代码(亲测有效)

    申请百度统计后,会得到一段JS代码,需要插入到每个网页中去,在Vue.js项目首先想到的可能就是,把统计代码插入到index.html入口文件中,这样就全局插入,每个页面就都有了;这样做就涉及到一个问 ...