protected override 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; } base.AddChildView(childView); } 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; } }
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 FragmentManager.EnableDebugLogging(true); #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) { AnimateArrowIn(); } } else if (_drawerToggle != null && NavigationPageController.StackDepth == 2) { 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 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); // This is a removal of a fragment that's not going on the back stack; there's no reason to care // whether its state gets successfully saved, since we'll never restore it. Ergo, CommitAllowingStateLoss transaction.CommitAllowingStateLossEx(); _currentFragment = null; } base.AddChildView(childView); } 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; SetDefaultBackgroundColor(pc.Child); }); FragmentTransaction transaction = FragmentManager.BeginTransactionEx(); if (_currentFragment != null) { transaction.RemoveEx(_currentFragment); } transaction.AddEx(Id, fragment); transaction.SetTransitionEx((int)FragmentTransit.None); // We don't currently support fragment restoration // So we don't need to worry about loss of this fragment's state transaction.CommitAllowingStateLossEx(); _currentFragment = fragment; } }