Masonry框架详细解析(七) —— Masonry与动画(一)

2,033 阅读4分钟
原文链接: www.jianshu.com

版本记录

版本号 时间
V1.0 2019.01.05 星期六

前言

我们做APP界面,也就是布局UI,那么关于布局,我们有很多方法,苹果也都提供了支持,市场上我们用的并不是系统提供原生的layout,对于OC语言一般都是使用一个第三方的布局框架 —— Masonry。接下来几篇我们就一起深入看一下这个框架。感兴趣的看上面几篇文章。
1. Masonry框架详细解析(一) —— 基本概览(一)
2. Masonry框架详细解析(二) —— 基本结构API和约束入口(一)
3. Masonry框架详细解析(三) —— MASConstraintMaker工厂类(一)
4. Masonry框架详细解析(四) —— MASConstraint类解析(一)
5. Masonry框架详细解析(五) —— MASCompositeConstraint类解析(一)
6. Masonry框架详细解析(六) —— MASViewConstraint类解析(一)

常见的UIView的类动画

UIView有一个分类,专门针对视图的动画的,主要API如下所示,也是大家都用过的。

@interface UIView(UIViewAnimationWithBlocks)

+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(4_0);

+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(4_0); // delay = 0.0, options = 0

+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations NS_AVAILABLE_IOS(4_0); // delay = 0.0, options = 0, completion = NULL

/* Performs `animations` using a timing curve described by the motion of a spring. When `dampingRatio` is 1, the animation will smoothly decelerate to its final model values without oscillating. Damping ratios less than 1 will oscillate more and more before coming to a complete stop. You can use the initial spring velocity to specify how fast the object at the end of the simulated spring was moving before it was attached. It's a unit coordinate system, where 1 is defined as travelling the total animation distance in a second. So if you're changing an object's position by 200pt in this animation, and you want the animation to behave as if the object was moving at 100pt/s before the animation started, you'd pass 0.5. You'll typically want to pass 0 for the velocity. */ 
+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay usingSpringWithDamping:(CGFloat)dampingRatio initialSpringVelocity:(CGFloat)velocity options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(7_0);

+ (void)transitionWithView:(UIView *)view duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void (^ __nullable)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(4_0);

+ (void)transitionFromView:(UIView *)fromView toView:(UIView *)toView duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(4_0); // toView added to fromView.superview, fromView removed from its superview

/* Performs the requested system-provided animation on one or more views. Specify addtional animations in the parallelAnimations block. These additional animations will run alongside the system animation with the same timing and duration that the system animation defines/inherits. Additional animations should not modify properties of the view on which the system animation is being performed. Not all system animations honor all available options.
 */
+ (void)performSystemAnimation:(UISystemAnimation)animation onViews:(NSArray<__kindof UIView *> *)views options:(UIViewAnimationOptions)options animations:(void (^ __nullable)(void))parallelAnimations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(7_0);

@end

这个相信大家都用过,这里就弄个简单的例子吧,直接上代码。

#import "AVC.h"
#import "Masonry.h"

@interface AVC ()

@property (nonatomic, strong) UIView *animatedView;

@end

@implementation AVC

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    self.title = NSStringFromClass([self class]);
    
    UIView *animatedView = [[UIView alloc] initWithFrame:CGRectMake(50.0, 150.0, 100.0, 100.0)];
    animatedView.backgroundColor = [UIColor redColor];
    [self.view addSubview:animatedView];
    self.animatedView = animatedView;
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    NSLog(@"animatedView = %@", self.animatedView);
    
    [UIView transitionWithView:self.animatedView duration:2.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
        self.animatedView.frame = CGRectMake(self.animatedView.frame.origin.x, 600.0, self.animatedView.frame.size.width, self.animatedView.frame.size.height);
    } completion:^(BOOL finished) {
        
    }];
}

@end

这里首先看下输出

2019-01-05 17:24:40.100905+0800 JJTest[41091:334070] animatedView = <UIView: 0x7fb690519830; frame = (50 150; 100 100); layer = <CALayer: 0x60000237d3c0>>

可以看见这个view是布局好我们可以看到其frame不是CGRectZero,下面我们就看下效果


Masonry约束与动画

上面的我们看见UIView实例化的时候是给了frame的,那么如果我们布局使用Masonry布局呢?还是一样的吗?我们平时项目中最常用的就是使用Masonry进行相对布局,不会这么写死数据。

因为有的时候正在加载视图,所以view只是相对布局还没有生效,没有frame,打印出来就会发现全部是0。

//如果约束还没有生成,要强制约束生成才行,不然动画没用
[self.view layoutIfNeeded];
    
[self.animatedView mas_updateConstraints:^(MASConstraintMaker *make) {
        make.bottom.equalTo(self.view.mas_bottom).offset(-(44 + 44));}];
    
[UIView animateWithDuration:0.25
                      delay:0.0
                    options:UIViewAnimationOptionCurveEaseInOut
                 animations:^{
                        //告知父视图生效约束
                       [self.view layoutIfNeeded];
                  } completion:^(BOOL finished) {
                         
                 }];

所以,这里需要注意的是,在我们添加完视图并且设置了约束后若是想要立即获得该视图的frame 或者 想要进行该视图的动画的话,就必须要在设置完约束后立即调用layoutIfNeeded方法强制进行刷新。

查阅了下资料,还有像IOS开发-利用Masonry实现简单动画写的。

和普通的方法实现差不多,重点只是修改约束后调用而已

[view.superview layoutIfNeeded];

[view mas_makeConstraints:^(MASConstraintMaker *make) {
    make.top.mas_equalTo(400);
    make.left.mas_equalTo(100);
    make.size.mas_equalTo(CGSizeMake(100, 100));
}];

//如果其约束还没有生成的时候需要动画的话,就请先强制刷新后才写动画,否则所有没生成的约束会直接跑动画
[view.superview layoutIfNeeded];

[UIView animateWithDuration:3 animations:^{
    [view mas_updateConstraints:^(MASConstraintMaker *make) {
        make.left.mas_equalTo(200);
    }];
    [view.superview layoutIfNeeded];//强制绘制
}];

后记

本篇主要说的就是一个小点,那就是使用Masonry做动画的时候需要注意的事情,感兴趣的给个赞或者关注~~~