void RemovePage(Page page) { if (!_isAttachedToWindow) { PushCurrentPages(); } Fragment fragment = GetPageFragment(page); if (fragment == null) { return; } #if DEBUG // Enables logging of moveToState operations to logcat #pragma warning disable CS0618 // Type or member is obsolete FragmentManager.EnableDebugLogging(true); #pragma warning restore CS0618 // Type or member is obsolete #endif // Go ahead and take care of the fragment bookkeeping for the page being removed FragmentTransaction transaction = FragmentManager.BeginTransactionEx(); transaction.RemoveEx(fragment); transaction.CommitAllowingStateLossEx(); // And remove the fragment from our own stack _fragmentStack.Remove(fragment); Device.StartTimer(TimeSpan.FromMilliseconds(10), () => { UpdateToolbar(); return(false); }); }
void AddTransitionTimer(TaskCompletionSource <bool> tcs, Fragment fragment, FragmentManager fragmentManager, IReadOnlyCollection <Fragment> fragmentsToRemove, int duration, bool shouldUpdateToolbar) { Device.StartTimer(TimeSpan.FromMilliseconds(duration), () => { tcs.TrySetResult(true); Current?.SendAppearing(); if (shouldUpdateToolbar) { UpdateToolbar(); } if (fragmentsToRemove.Count > 0) { FragmentTransaction fragmentTransaction = fragmentManager.BeginTransactionEx(); foreach (Fragment frag in fragmentsToRemove) { fragmentTransaction.RemoveEx(frag); } fragmentTransaction.CommitAllowingStateLossEx(); } return(false); }); }
protected override void Dispose(bool disposing) { if (_disposed) { return; } _disposed = true; if (disposing) { if (_currentFragment != null && !FragmentManager.IsDestroyed) { FragmentTransaction transaction = FragmentManager.BeginTransactionEx(); transaction.RemoveEx(_currentFragment); transaction.SetTransitionEx((int)FragmentTransit.None); transaction.CommitAllowingStateLossEx(); FragmentManager.ExecutePendingTransactionsEx(); _currentFragment = null; } _parent = null; _pageContainer = null; _fragmentManager = null; RemoveAllViews(); DisposeChildRenderers(); } base.Dispose(disposing); }
void AddTransitionTimer(TaskCompletionSource <bool> tcs, Fragment fragment, FragmentManager fragmentManager, IReadOnlyCollection <Fragment> fragmentsToRemove, int duration, bool shouldUpdateToolbar) { PostDelayed(() => { tcs.TrySetResult(true); Current?.SendAppearing(); if (shouldUpdateToolbar) { UpdateToolbar(); } if (fragmentsToRemove.Count > 0) { FragmentTransaction fragmentTransaction = fragmentManager.BeginTransactionEx(); foreach (Fragment frag in fragmentsToRemove) { fragmentTransaction.RemoveEx(frag); } fragmentTransaction.CommitAllowingStateLossEx(); } }, duration); }
Task <bool> SwitchContentAsync(Page page, bool animated, bool removed = false, bool popToRoot = false) { if (!Element.IsAttachedToRoot()) { return(Task.FromResult(false)); } var tcs = new TaskCompletionSource <bool>(); Fragment fragment = GetFragment(page, removed, popToRoot); #if DEBUG // Enables logging of moveToState operations to logcat #pragma warning disable CS0618 // Type or member is obsolete FragmentManager.EnableDebugLogging(true); #pragma warning restore CS0618 // Type or member is obsolete #endif Current?.SendDisappearing(); Current = page; if (Platform != null) { Platform.NavAnimationInProgress = true; } FragmentTransaction transaction = FragmentManager.BeginTransactionEx(); if (animated) { SetupPageTransition(transaction, !removed); } var fragmentsToRemove = new List <Fragment>(); if (_fragmentStack.Count == 0) { transaction.AddEx(Id, fragment); _fragmentStack.Add(fragment); } else { if (removed) { // pop only one page, or pop everything to the root var popPage = true; while (_fragmentStack.Count > 1 && popPage) { Fragment currentToRemove = _fragmentStack.Last(); _fragmentStack.RemoveAt(_fragmentStack.Count - 1); transaction.HideEx(currentToRemove); fragmentsToRemove.Add(currentToRemove); popPage = popToRoot; } Fragment toShow = _fragmentStack.Last(); // Execute pending transactions so that we can be sure the fragment list is accurate. FragmentManager.ExecutePendingTransactionsEx(); if (FragmentManager.Fragments.Contains(toShow)) { transaction.ShowEx(toShow); } else { transaction.AddEx(Id, toShow); } } else { // push Fragment currentToHide = _fragmentStack.Last(); transaction.HideEx(currentToHide); transaction.AddEx(Id, fragment); _fragmentStack.Add(fragment); } } // We don't currently support fragment restoration, so we don't need to worry about // whether the commit loses state transaction.CommitAllowingStateLossEx(); // The fragment transitions don't really SUPPORT telling you when they end // There are some hacks you can do, but they actually are worse than just doing this: if (animated) { if (!removed) { UpdateToolbar(); if (_drawerToggle != null && NavigationPageController.StackDepth == 2 && NavigationPage.GetHasBackButton(page)) { AnimateArrowIn(); } } else if (_drawerToggle != null && NavigationPageController.StackDepth == 2 && NavigationPage.GetHasBackButton(page)) { AnimateArrowOut(); } AddTransitionTimer(tcs, fragment, FragmentManager, fragmentsToRemove, TransitionDuration, removed); } else { AddTransitionTimer(tcs, fragment, FragmentManager, fragmentsToRemove, 1, true); } Context.HideKeyboard(this); if (Platform != null) { Platform.NavAnimationInProgress = false; } return(tcs.Task); }
protected override void Dispose(bool disposing) { if (_disposed) { return; } _disposed = true; if (disposing) { DeviceDisplay.MainDisplayInfoChanged -= DeviceInfoPropertyChanged; if (NavigationPageController != null) { var navController = NavigationPageController; navController.PushRequested -= OnPushed; navController.PopRequested -= OnPopped; navController.PopToRootRequested -= OnPoppedToRoot; navController.InsertPageBeforeRequested -= OnInsertPageBeforeRequested; navController.RemovePageRequested -= OnRemovePageRequested; } if (Current != null) { Current.PropertyChanged -= CurrentOnPropertyChanged; } FragmentManager fm = FragmentManager; if (!fm.IsDestroyed) { FragmentTransaction trans = fm.BeginTransactionEx(); foreach (Fragment fragment in _fragmentStack) { trans.RemoveEx(fragment); } trans.CommitAllowingStateLossEx(); fm.ExecutePendingTransactionsEx(); } _toolbar.RemoveView(_titleView); _titleView?.Dispose(); _titleView = null; if (_titleViewRenderer != null) { Platform.ClearRenderer(_titleViewRenderer.View); _titleViewRenderer.Dispose(); _titleViewRenderer = null; } _toolbar.RemoveView(_titleIconView); _titleIconView?.Dispose(); _titleIconView = null; _imageSource = null; if (_toolbarTracker != null) { _toolbarTracker.CollectionChanged -= ToolbarTrackerOnCollectionChanged; _toolbar.DisposeMenuItems(_currentToolbarItems, OnToolbarItemPropertyChanged); _toolbarTracker.Target = null; _toolbarTracker = null; } if (_currentMenuItems != null) { _currentMenuItems.Clear(); _currentMenuItems = null; } if (_currentToolbarItems != null) { _currentToolbarItems.Clear(); _currentToolbarItems = null; } if (_toolbar != null) { _toolbar.SetNavigationOnClickListener(null); _toolbar.Menu.Clear(); RemoveView(_toolbar); _toolbar.Dispose(); _toolbar = null; } if (_drawerLayout.IsAlive() && _drawerListener.IsAlive()) { _drawerLayout.RemoveDrawerListener(_drawerListener); RemoveView(_drawerLayout); } if (_drawerListener != null) { _drawerListener.Dispose(); _drawerListener = null; } if (_drawerToggle != null) { _drawerToggle.ToolbarNavigationClickListener = null; _drawerToggle.Dispose(); _drawerToggle = null; } if (_backgroundDrawable != null) { _backgroundDrawable.Dispose(); _backgroundDrawable = null; } Current = null; // We dispose the child renderers after cleaning up everything related to DrawerLayout in case // one of the children is a FlyoutPage (which may dispose of the DrawerLayout). if (Element != null) { foreach (Element element in PageController.InternalChildren) { var child = element as VisualElement; if (child == null) { continue; } IVisualElementRenderer renderer = Platform.GetRenderer(child); renderer?.Dispose(); } } } base.Dispose(disposing); }
protected virtual void AddChildView(VisualElement childView) { _pageContainer = null; Page page = childView as NavigationPage ?? (Page)(childView as TabbedPage); if (page == null) { // The thing we're adding is not a NavigationPage or TabbedPage, so we can just use the old AddChildView if (_currentFragment != null) { if (!_parent.IsAttachedToRoot()) { return; } // But first, if the previous occupant of this container was a fragment, we need to remove it properly FragmentTransaction transaction = FragmentManager.BeginTransactionEx(); transaction.RemoveEx(_currentFragment); transaction.SetTransitionEx((int)FragmentTransit.None); if (IsAttachedToWindow) { ExecuteTransaction(transaction); } else { _transaction = transaction; } _currentFragment = null; } IVisualElementRenderer renderer = APlatform.GetRenderer(childView); if (renderer == null) { APlatform.SetRenderer(childView, renderer = APlatform.CreateRenderer(childView, Context)); } if (renderer.View.Parent != this) { if (renderer.View.Parent != null) { renderer.View.RemoveFromParent(); } SetDefaultBackgroundColor(renderer); AddView(renderer.View); renderer.UpdateLayout(); } } else { if (!_parent.IsAttachedToRoot()) { return; } // The renderers for NavigationPage and TabbedPage both host fragments, so they need to be wrapped in a // FragmentContainer in order to get isolated fragment management Fragment fragment = FragmentContainer.CreateInstance(page); var fc = fragment as FragmentContainer; fc?.SetOnCreateCallback(pc => { _pageContainer = pc; UpdateFlowDirection(); SetDefaultBackgroundColor(pc.Child); }); FragmentTransaction transaction = FragmentManager.BeginTransactionEx(); if (_currentFragment != null) { transaction.RemoveEx(_currentFragment); } transaction.AddEx(Id, fragment); transaction.SetTransitionEx((int)FragmentTransit.None); if (IsAttachedToWindow) { ExecuteTransaction(transaction); } else { _transaction = transaction; } _currentFragment = fragment; } }