關於Autolayout製作動畫的坑

SuperDanny發表於2017-12-13

需求

一直以來iOS的 Autolayout 都是一個很不錯的功能,結合第三方 Masonry 可以節省很多工作成本。但是如果使用 Autolayout 來製作動畫,那麼就需要注意一下。不然就會像我一樣,遇坑踩坑,越陷越深。

使用xib實現動畫

使用情景:自定義一個UIView ViewA,實現由下往上彈窗效果。

效果如下

效果圖

假如我們是使用xib建立自定義彈窗檢視,一般我們都會在xib上做好了約束的條件,之後在.m檔案裡面實現檢視的初始化操作。

自定義UIView

實現動畫的原則是,在ViewA執行動畫之前,需要將ViewA最終約束條件設定好,之後在執行動畫程式碼塊裡面只需要呼叫layoutIfNeeded即可。

另外呼叫layoutIfNeeded方法的物件必須是ViewA的父檢視,不然會出現ViewA的子檢視跟著執行動畫的情況。

如下面的程式碼中,ViewA的父檢視就是window,所以呼叫layoutIfNeeded方法的物件是window

- (instancetype)init {
    self = [[[NSBundle mainBundle] loadNibNamed:@"DDJoinView" owner:self options:nil] lastObject];
    if (self) {
        self.frame = CGRectMake(0, kScreenHeight, kScreenWidth, 195);
    }
    return self;
}
- (void)show {
    UIWindow *window = [UIApplication sharedApplication].keyWindow;
    _bgView = [[UIButton alloc] init];
    _bgView.backgroundColor = UIColorHex(0x000000);
    _bgView.alpha = 0.25;
    _bgView.frame = CGRectMake(0, 0, kScreenWidth, kScreenHeight);
    [_bgView addTarget:self action:@selector(close:) forControlEvents:UIControlEventTouchUpInside];
    [window addSubview:_bgView];
    [window addSubview:self];
    [self mas_updateConstraints:^(MASConstraintMaker *make) {
        (void)make.left;
        (void)make.centerX;
        make.height.offset(195);
        make.bottom.offset(0);
    }];
    [UIView animateWithDuration:0.3f animations:^{
        [window layoutIfNeeded];
    }];
}
#pragma mark - 關閉
- (void)close:(id)sender {
    UIWindow *window = [UIApplication sharedApplication].keyWindow;
    [self mas_updateConstraints:^(MASConstraintMaker *make) {
        (void)make.left;
        (void)make.centerX;
        make.height.offset(195);
        make.bottom.offset(195);
    }];
    [UIView animateWithDuration:0.3f animations:^{
        [window layoutIfNeeded];
    } completion:^(BOOL finished) {
        for (UIView *v in [self subviews]) {
            [v removeFromSuperview];
        }
        [self removeFromSuperview];
        [_bgView removeFromSuperview];
    }];
}
複製程式碼

總結

//...
//執行下面動畫前,設定自定義view的最終位置的約束條件
//...
[UIView animateWithDuration:0.3f animations:^{
        [xxx layoutIfNeeded];
    } completion:^(BOOL finished) {
        //do something
}];
複製程式碼

再一次感謝您花費時間閱讀這篇文章!

微博: @Danny_呂昌輝
部落格: SuperDanny

相關文章