收到通知时如何实现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
相关产品推荐
相关产品推荐

