You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

收到通知时如何实现UIViewController的尺寸调整动画?

嘿,我来帮你搞定这个子视图控制器尺寸调整的动画问题!结合你已经写的关键帧动画思路,我给你梳理下正确的实现步骤和注意点:

第一步:先做好通知监听的基础工作

首先得确保你的容器VC能正确收到通知,别漏了注册和移除的步骤:

- (void)viewDidLoad {
    [super viewDidLoad];
    // 注册你需要监听的通知,替换成你的通知名称
    [[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(handleResizeNotification:) 
                                                 name:@"Notification_Name_For_Resize" 
                                               object:nil];
}

- (void)dealloc {
    // 记得移除监听,避免内存泄漏
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}
第二步:根据布局方式选择动画实现

iOS里布局分Frame和Auto Layout两种,处理方式不一样,我分别给你示例:

情况1:用Frame直接布局(适合简单场景)

如果你的子VC是用Frame来控制尺寸位置的,直接在动画块里修改frame就行:

- (void)handleResizeNotification:(NSNotification *)notification {
    // 定义你要调整到的目标尺寸,这里示例是缩到容器的80%并居中
    CGSize targetSize = CGSizeMake(self.view.bounds.size.width * 0.8, 
                                  self.view.bounds.size.height * 0.8);
    CGRect targetFrame = CGRectMake((self.view.bounds.size.width - targetSize.width)/2,
                                   (self.view.bounds.size.height - targetSize.height)/2,
                                   targetSize.width,
                                   targetSize.height);

    // 用你一开始想用的关键帧动画,或者普通动画都可以
    [UIView animateKeyframesWithDuration:0.5 delay:0 options:UIViewKeyframeAnimationOptionCalculationModeLinear animations:^{
        // 第一阶段:前0.5秒先缩到90%
        [UIView addKeyframeWithRelativeStartTime:0.0 relativeDuration:0.5 animations:^{
            for (UIViewController *vc in self.viewControllers) {
                CGRect midFrame = CGRectMake((self.view.bounds.size.width - self.view.bounds.size.width*0.9)/2,
                                            (self.view.bounds.size.height - self.view.bounds.size.height*0.9)/2,
                                            self.view.bounds.size.width*0.9,
                                            self.view.bounds.size.height*0.9);
                vc.view.frame = midFrame;
            }
        }];
        // 第二阶段:后0.5秒缩到最终的80%
        [UIView addKeyframeWithRelativeStartTime:0.5 relativeDuration:0.5 animations:^{
            for (UIViewController *vc in self.viewControllers) {
                vc.view.frame = targetFrame;
            }
        }];
    } completion:^(BOOL finished) {
        // 动画完成后如果有后续操作,比如更新状态,放这里
    }];
}

情况2:用Auto Layout布局(推荐,适配性更好)

如果你的项目用Auto Layout,那不能直接改frame,要通过修改约束来实现动画:
首先,在添加子VC的时候,保存全屏约束的引用:

// 容器VC里定义属性来保存约束
@property (nonatomic, strong) NSLayoutConstraint *childTopConstraint;
@property (nonatomic, strong) NSLayoutConstraint *childLeadingConstraint;
@property (nonatomic, strong) NSLayoutConstraint *childTrailingConstraint;
@property (nonatomic, strong) NSLayoutConstraint *childBottomConstraint;

- (void)addChildVC:(UIViewController *)childVC {
    [super addChildViewController:childVC];
    [self.view addSubview:childVC.view];
    childVC.view.translatesAutoresizingMaskIntoConstraints = NO;

    // 添加初始全屏约束
    self.childTopConstraint = [childVC.view.topAnchor constraintEqualToAnchor:self.view.topAnchor];
    self.childLeadingConstraint = [childVC.view.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor];
    self.childTrailingConstraint = [childVC.view.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor];
    self.childBottomConstraint = [childVC.view.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor];

    [NSLayoutConstraint activateConstraints:@[self.childTopConstraint, 
                                             self.childLeadingConstraint, 
                                             self.childTrailingConstraint, 
                                             self.childBottomConstraint]];
    [childVC didMoveToParentViewController:self];
}

然后在通知处理方法里修改约束并触发动画:

- (void)handleResizeNotification:(NSNotification *)notification {
    // 调整约束常量,比如上下左右各缩进20pt
    CGFloat inset = 20.0;
    self.childTopConstraint.constant = inset;
    self.childLeadingConstraint.constant = inset;
    self.childTrailingConstraint.constant = -inset;
    self.childBottomConstraint.constant = -inset;

    // 关键!在动画块里调用layoutIfNeeded,约束变化才会以动画呈现
    [UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
        [self.view layoutIfNeeded];
    } completion:^(BOOL finished) {
        // 动画完成后的操作
    }];
}
几个重要的注意事项
  • 确保子VC已经正确添加到容器VC:必须调用addChildViewController:、didMoveToParentViewController:这些方法,不然子VC的生命周期不对,动画可能出问题。
  • 如果有多个子VC,别盲目遍历所有,只调整当前显示的那个就行,避免不必要的动画。
  • 关键帧动画的relativeDuration是相对于总时长的比例,比如总时长0.5秒,relativeDuration:0.5就是0.25秒的动画时间,别搞混了。

内容的提问来源于stack exchange,提问作者user4992124

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:29:03