Xamarin.iOS视图控制器约束失效:滑动转场后视图重叠
我来帮你搞定这个滑动转场的坑!你遇到的vc1和vc2重叠、约束失效的问题,主要是因为直接把子控制器的View加到父视图上时,没做正确的布局约束,还忽略了视图控制器的生命周期规范。下面给你两种靠谱的Xamarin.iOS解决方案:
方案一:使用自定义视图控制器转场(推荐,符合iOS规范)
这种方式严格遵循iOS的视图控制器生命周期,从根源上避免布局混乱,步骤如下:
- 让你的原视图控制器(vc1)实现
UIViewControllerTransitioningDelegate接口,用来提供自定义转场动画:
public class YourVC1 : UIViewController, UIViewControllerTransitioningDelegate { // 提供present时的动画控制器 public IUIViewControllerAnimatedTransitioning GetAnimationControllerForPresentedController(UIViewController presented, UIViewController presenting, UIViewController source) { return new SlideInAnimator(isPresenting: true); } // 提供dismiss时的动画控制器 public IUIViewControllerAnimatedTransitioning GetAnimationControllerForDismissedController(UIViewController dismissed) { return new SlideInAnimator(isPresenting: false); } }
- 创建自定义转场动画器类,实现滑动逻辑:
public class SlideInAnimator : NSObject, IUIViewControllerAnimatedTransitioning { private readonly bool _isPresenting; private const double _animationDuration = 1.0; public SlideInAnimator(bool isPresenting) { _isPresenting = isPresenting; } // 返回动画时长 public double TransitionDuration(IUIViewControllerContextTransitioning transitionContext) { return _animationDuration; } // 核心动画逻辑 public void AnimateTransition(IUIViewControllerContextTransitioning transitionContext) { var container = transitionContext.ContainerView; var toVC = transitionContext.GetViewControllerForKey(UITransitionContext.ToViewControllerKey); var fromVC = transitionContext.GetViewControllerForKey(UITransitionContext.FromViewControllerKey); var screenWidth = UIScreen.MainScreen.Bounds.Width; // 初始化和目标帧:present时从右侧滑入,dismiss时滑回右侧 var initialFrame = _isPresenting ? new CGRect(screenWidth, 0, screenWidth, UIScreen.MainScreen.Bounds.Height) : transitionContext.GetFinalFrameForViewController(toVC); var targetFrame = _isPresenting ? transitionContext.GetFinalFrameForViewController(toVC) : new CGRect(screenWidth, 0, screenWidth, UIScreen.MainScreen.Bounds.Height); if (_isPresenting) { toVC.View.Frame = initialFrame; container.AddSubview(toVC.View); } UIView.Animate(_animationDuration, 0, UIViewAnimationOptions.CurveLinear, () => { if (_isPresenting) toVC.View.Frame = targetFrame; else fromVC.View.Frame = targetFrame; }, () => { // 标记转场完成 transitionContext.CompleteTransition(!transitionContext.TransitionWasCancelled); }); } }
- 修改你的
SlideTo方法,用自定义转场present新控制器:
public void SlideTo(UIView view, string vcIdentifier) { var storyboard = UIStoryboard.FromName("Main", null); var vc2 = storyboard.InstantiateViewController(vcIdentifier); // 开启自定义转场 vc2.ModalPresentationStyle = UIModalPresentationStyle.Custom; vc2.TransitioningDelegate = this; // 这里的this是实现了TransitioningDelegate的vc1 PresentViewController(vc2, true, null); }
方案二:修复直接添加子视图的布局问题(适合特殊场景)
如果因为业务需求必须直接把vc2的View加到vc1上,一定要补全布局约束和子控制器生命周期的调用:
public void SlideTo(UIView parentView, string vcIdentifier) { var storyboard = UIStoryboard.FromName("Main", null); var vc2 = storyboard.InstantiateViewController(vcIdentifier); // 1. 必须将vc2作为子控制器添加,保证生命周期正常触发 AddChildViewController(vc2); // 2. 关闭自动布局转换,手动添加全屏约束 vc2.View.TranslatesAutoresizingMaskIntoConstraints = false; parentView.AddSubview(vc2.View); // 3. 添加全屏约束,确保vc2铺满父视图 NSLayoutConstraint.ActivateConstraints(new[] { vc2.View.TopAnchor.ConstraintEqualTo(parentView.TopAnchor), vc2.View.LeadingAnchor.ConstraintEqualTo(parentView.LeadingAnchor), vc2.View.TrailingAnchor.ConstraintEqualTo(parentView.TrailingAnchor), vc2.View.BottomAnchor.ConstraintEqualTo(parentView.BottomAnchor) }); // 4. 完成子控制器添加流程 vc2.DidMoveToParentViewController(this); // 5. 执行滑动动画:从右侧滑入 var screenWidth = UIScreen.MainScreen.Bounds.Width; vc2.View.Transform = CGAffineTransform.MakeTranslation(screenWidth, 0); UIView.Animate(1.0, 0, UIViewAnimationOptions.CurveLinear, () => { vc2.View.Transform = CGAffineTransform.Identity; }, null); }
原代码的问题总结:
- 没有关闭
TranslatesAutoresizingMaskIntoConstraints,也没添加AutoLayout约束,导致vc2的View无法自适应屏幕尺寸,动画后布局混乱 - 没有调用
AddChildViewController和DidMoveToParentViewController,vc2的生命周期方法(比如ViewDidLoad)不会正常触发,容易引发布局和内存泄漏问题
内容的提问来源于stack exchange,提问作者Alessandro Ledda
相关产品推荐
相关产品推荐

