Xamarin Forms Android端PopAsync自定义关闭动画实现求助
Android平台Xamarin.Forms PopAsync自定义动画实现方案
你遇到的问题根源在于OnDetachedFromWindow的触发时机:当这个方法执行时,页面已经从Window中移除,视图不再可见,所以动画根本不会被用户看到——这不是底层BUG,是方法的设计逻辑导致的。
要实现PopAsync时的自定义动画,必须在页面开始移除前启动动画,等动画完成后再执行Pop的最终逻辑,以下是两种可行的实现方案:
方案一:自定义NavigationPageRenderer(全局生效,推荐)
通过重写NavigationPage的Renderer,直接拦截Pop操作,在动画完成后再执行默认的Pop逻辑:
[assembly: ExportRenderer(typeof(NavigationPage), typeof(CustomNavigationRenderer))] namespace YourAppNamespace.Droid.Renderers { public class CustomNavigationRenderer : NavigationPageRenderer { public CustomNavigationRenderer(Context context) : base(context) { } public override async Task<bool> PopViewControllerAsync(bool animated) { // 判断是否启用自定义动画 if (animated && Preferences.Get("ModelAnimationDetach", false)) { var currentViewController = TopViewController; if (currentViewController?.View != null) { // 创建自定义退出动画(可根据需求修改参数调整方向) var displayMetrics = Context.Resources.DisplayMetrics; var exitAnimation = new TranslateAnimation(0, displayMetrics.WidthPixels, 0, 0) { Duration = 2000, FillAfter = true // 保持动画结束后的位置 }; // 动画完成后执行不带默认动画的Pop exitAnimation.AnimationEnd += async (sender, e) => { await base.PopViewControllerAsync(false); }; // 启动动画 currentViewController.View.StartAnimation(exitAnimation); return true; // 告知系统已处理Pop操作 } } // 不满足条件时使用默认Pop逻辑 return await base.PopViewControllerAsync(animated); } } }
方案二:单个页面Renderer中处理(仅针对特定页面)
如果只需要给某个特定页面添加Pop动画,可以在该页面的Renderer中监听Disappearing事件,拦截默认导航后执行动画:
[assembly: ExportRenderer(typeof(YourTargetPage), typeof(YourPageRenderer))] namespace YourAppNamespace.Droid.Renderers { public class YourPageRenderer : PageRenderer { private bool _isAnimating; protected override void OnElementChanged(ElementChangedEventArgs<Page> e) { base.OnElementChanged(e); if (e.NewElement != null) { e.NewElement.Disappearing += HandlePageDisappearing; } if (e.OldElement != null) { e.OldElement.Disappearing -= HandlePageDisappearing; } } private async void HandlePageDisappearing(object sender, EventArgs e) { if (_isAnimating || !Preferences.Get("ModelAnimationDetach", false)) return; _isAnimating = true; var currentPage = sender as Page; var navigation = currentPage?.Navigation; if (navigation != null && navigation.NavigationStack.Count > 1 && navigation.NavigationStack.Last() == currentPage) { // 创建自定义动画 var displayMetrics = Resources.DisplayMetrics; var exitAnimation = new TranslateAnimation(0, displayMetrics.HeightPixels, 0, 0) { Duration = 2000, FillAfter = true }; exitAnimation.AnimationEnd += async (s, args) => { _isAnimating = false; // 动画完成后执行无动画的Pop await navigation.PopAsync(false); }; // 启动动画 View.StartAnimation(exitAnimation); // 阻止默认的Pop流程 ((IElementController)currentPage).SendAppearing(); } } } }
注意事项
- 动画完成后一定要调用不带动画的Pop方法(
PopViewControllerAsync(false)或PopAsync(false)),避免默认动画和自定义动画冲突。 FillAfter = true属性可以确保动画结束后视图保持在最终位置,直到被移除。- 可根据需求调整动画的方向、时长等参数。
内容的提问来源于stack exchange,提问作者ThisQRequiresASpecialist
相关产品推荐
相关产品推荐

