Detect when pages are popped from clicking on tab (#9086)
This commit is contained in:
Родитель
418e2f994a
Коммит
8fb1bb0eea
|
@ -0,0 +1,83 @@
|
|||
using Xamarin.Forms.CustomAttributes;
|
||||
using Xamarin.Forms.Internals;
|
||||
|
||||
#if UITEST
|
||||
using Xamarin.UITest;
|
||||
using NUnit.Framework;
|
||||
using Xamarin.Forms.Core.UITests;
|
||||
#endif
|
||||
|
||||
namespace Xamarin.Forms.Controls.Issues
|
||||
{
|
||||
[Preserve(AllMembers = true)]
|
||||
[Issue(IssueTracker.Github, 9006, "[Bug] Unable to open a new Page for the second time in Xamarin.Forms Shell Tabbar",
|
||||
PlatformAffected.iOS)]
|
||||
#if UITEST
|
||||
[NUnit.Framework.Category(UITestCategories.Shell)]
|
||||
#endif
|
||||
public class Issue9006 : TestShell
|
||||
{
|
||||
protected override void Init()
|
||||
{
|
||||
Routing.RegisterRoute("Issue9006_ContentPage", typeof(ContentPage));
|
||||
Routing.RegisterRoute("Issue9006_FinalPage", typeof(ContentPage));
|
||||
|
||||
var contentPage = AddBottomTab("Tab 1");
|
||||
Items[0].CurrentItem.AutomationId = "Tab1AutomationId";
|
||||
AddBottomTab("Ignore Me");
|
||||
|
||||
Label label = new Label()
|
||||
{
|
||||
Text = "Clicking on the first tab should pop you back to the root",
|
||||
AutomationId = "FinalLabel"
|
||||
};
|
||||
|
||||
Button button = null;
|
||||
bool navigated = false;
|
||||
button = new Button()
|
||||
{
|
||||
Text = "Click Me",
|
||||
AutomationId = "Click Me",
|
||||
Command = new Command(async () =>
|
||||
{
|
||||
await GoToAsync("Issue9006_ContentPage");
|
||||
await GoToAsync("Issue9006_FinalPage");
|
||||
|
||||
button.Text = "Click me again. If pages get pushed again then test has passed.";
|
||||
DisplayedPage.Content = new StackLayout()
|
||||
{
|
||||
Children =
|
||||
{
|
||||
label
|
||||
}
|
||||
};
|
||||
if (navigated)
|
||||
label.Text = "Success";
|
||||
|
||||
navigated = true;
|
||||
})
|
||||
};
|
||||
|
||||
contentPage.Content = new StackLayout()
|
||||
{
|
||||
Children =
|
||||
{
|
||||
button
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#if UITEST && __IOS__
|
||||
[Test]
|
||||
public void ClickingOnTabToPopToRootDoesntBreakNavigation()
|
||||
{
|
||||
RunningApp.Tap("Click Me");
|
||||
RunningApp.WaitForElement("FinalLabel");
|
||||
RunningApp.Tap("Tab1AutomationId");
|
||||
RunningApp.Tap("Click Me");
|
||||
RunningApp.Tap("Success");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
|
@ -602,6 +602,14 @@ namespace Xamarin.Forms.Controls
|
|||
#endif
|
||||
}
|
||||
|
||||
protected ContentPage DisplayedPage
|
||||
{
|
||||
get
|
||||
{
|
||||
return (ContentPage)(CurrentItem.CurrentItem as IShellSectionController).PresentedPage;
|
||||
}
|
||||
}
|
||||
|
||||
public ContentPage AddTopTab(string title)
|
||||
{
|
||||
var page = new ContentPage();
|
||||
|
@ -633,8 +641,15 @@ namespace Xamarin.Forms.Controls
|
|||
|
||||
public ContentPage AddBottomTab(string title)
|
||||
{
|
||||
|
||||
ContentPage page = new ContentPage();
|
||||
if (Items.Count == 0)
|
||||
{
|
||||
var item = AddContentPage(page);
|
||||
item.Items[0].Items[0].Title = title ?? page.Title;
|
||||
item.Items[0].Title = title ?? page.Title;
|
||||
return page;
|
||||
}
|
||||
|
||||
Items[0].Items.Add(new ShellSection()
|
||||
{
|
||||
Title = title,
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
<ItemGroup>
|
||||
<Compile Include="$(MSBuildThisFileDirectory)CollectionViewGroupTypeIssue.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue8262.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue9006.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue8207.xaml.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue6362.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Issue7505.cs" />
|
||||
|
@ -1684,4 +1685,4 @@
|
|||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Threading.Tasks;
|
||||
using Xamarin.Forms.Internals;
|
||||
|
||||
|
@ -21,8 +22,19 @@ namespace Xamarin.Forms
|
|||
|
||||
void SendInsetChanged(Thickness inset, double tabThickness);
|
||||
|
||||
void SendPopping(Task poppingCompleted);
|
||||
void SendPoppingToRoot(Task finishedPopping);
|
||||
|
||||
[Obsolete]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
void SendPopped();
|
||||
|
||||
[Obsolete]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
void SendPopping(Page page);
|
||||
|
||||
[Obsolete]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
void SendPopped(Page page);
|
||||
}
|
||||
}
|
|
@ -118,6 +118,45 @@ namespace Xamarin.Forms
|
|||
_lastTabThickness = tabThickness;
|
||||
}
|
||||
|
||||
async void IShellSectionController.SendPopping(Task poppingCompleted)
|
||||
{
|
||||
if (_navStack.Count <= 1)
|
||||
throw new Exception("Nav Stack consistency error");
|
||||
|
||||
var page = _navStack[_navStack.Count - 1];
|
||||
|
||||
_navStack.Remove(page);
|
||||
UpdateDisplayedPage();
|
||||
|
||||
await poppingCompleted;
|
||||
|
||||
RemovePage(page);
|
||||
SendUpdateCurrentState(ShellNavigationSource.Pop);
|
||||
}
|
||||
|
||||
async void IShellSectionController.SendPoppingToRoot(Task finishedPopping)
|
||||
{
|
||||
if (_navStack.Count <= 1)
|
||||
throw new Exception("Nav Stack consistency error");
|
||||
|
||||
var oldStack = _navStack;
|
||||
_navStack = new List<Page> { null };
|
||||
|
||||
for (int i = 1; i < oldStack.Count; i++)
|
||||
oldStack[i].SendDisappearing();
|
||||
|
||||
UpdateDisplayedPage();
|
||||
await finishedPopping;
|
||||
|
||||
for (int i = 1; i < oldStack.Count; i++)
|
||||
RemovePage(oldStack[i]);
|
||||
|
||||
SendUpdateCurrentState(ShellNavigationSource.PopToRoot);
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
|
||||
void IShellSectionController.SendPopped()
|
||||
{
|
||||
if (_navStack.Count <= 1)
|
||||
|
@ -131,6 +170,8 @@ namespace Xamarin.Forms
|
|||
SendUpdateCurrentState(ShellNavigationSource.Pop);
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
void IShellSectionController.SendPopping(Page page)
|
||||
{
|
||||
if (_navStack.Count <= 1)
|
||||
|
@ -140,9 +181,11 @@ namespace Xamarin.Forms
|
|||
SendAppearanceChanged();
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
void IShellSectionController.SendPopped(Page page)
|
||||
{
|
||||
if(_navStack.Contains(page))
|
||||
if (_navStack.Contains(page))
|
||||
_navStack.Remove(page);
|
||||
|
||||
RemovePage(page);
|
||||
|
@ -313,6 +356,7 @@ namespace Xamarin.Forms
|
|||
|
||||
if (previousPage != DisplayedPage)
|
||||
{
|
||||
previousPage?.SendDisappearing();
|
||||
PresentedPageAppearing();
|
||||
SendAppearanceChanged();
|
||||
}
|
||||
|
|
|
@ -63,6 +63,7 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
TaskCompletionSource<bool> _popCompletionTask;
|
||||
IShellSectionRootRenderer _renderer;
|
||||
ShellSection _shellSection;
|
||||
bool _ignorePopCall;
|
||||
|
||||
public ShellSectionRenderer(IShellContext context)
|
||||
{
|
||||
|
@ -265,16 +266,48 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
DisposePage(page);
|
||||
}
|
||||
|
||||
protected virtual async void OnPopToRootRequested(NavigationRequestedEventArgs e)
|
||||
public override UIViewController[] PopToRootViewController(bool animated)
|
||||
{
|
||||
var animated = e.Animated;
|
||||
if (!_ignorePopCall && ViewControllers.Length > 1)
|
||||
{
|
||||
ProcessPopToRoot();
|
||||
}
|
||||
|
||||
return base.PopToRootViewController(animated);
|
||||
}
|
||||
|
||||
async void ProcessPopToRoot()
|
||||
{
|
||||
var task = new TaskCompletionSource<bool>();
|
||||
var pages = _shellSection.Stack.ToList();
|
||||
_completionTasks[_renderer.ViewController] = task;
|
||||
e.Task = task.Task;
|
||||
((IShellSectionController)ShellSection).SendPoppingToRoot(task.Task);
|
||||
await task.Task;
|
||||
|
||||
PopToRootViewController(animated);
|
||||
for (int i = pages.Count - 1; i >= 1; i--)
|
||||
{
|
||||
var page = pages[i];
|
||||
DisposePage(page);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual async void OnPopToRootRequested(NavigationRequestedEventArgs e)
|
||||
{
|
||||
var animated = e.Animated;
|
||||
var task = new TaskCompletionSource<bool>();
|
||||
var pages = _shellSection.Stack.ToList();
|
||||
|
||||
try
|
||||
{
|
||||
_ignorePopCall = true;
|
||||
_completionTasks[_renderer.ViewController] = task;
|
||||
e.Task = task.Task;
|
||||
PopToRootViewController(animated);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_ignorePopCall = false;
|
||||
}
|
||||
|
||||
await e.Task;
|
||||
|
||||
|
@ -328,6 +361,7 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
_ = _context.ApplyNativeImageAsync(ShellSection, ShellSection.IconProperty, icon =>
|
||||
{
|
||||
TabBarItem = new UITabBarItem(ShellSection.Title, icon, null);
|
||||
TabBarItem.AccessibilityIdentifier = ShellSection.AutomationId ?? ShellSection.Title;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -399,11 +433,10 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
var poppedPage = _shellSection.Stack[_shellSection.Stack.Count - 1];
|
||||
|
||||
// this is used to setup appearance changes based on the incoming page
|
||||
((IShellSectionController)_shellSection).SendPopping(poppedPage);
|
||||
((IShellSectionController)_shellSection).SendPopping(popTask);
|
||||
|
||||
await popTask;
|
||||
|
||||
((IShellSectionController)_shellSection).SendPopped(poppedPage);
|
||||
DisposePage(poppedPage);
|
||||
}
|
||||
|
||||
|
@ -491,17 +524,22 @@ namespace Xamarin.Forms.Platform.iOS
|
|||
navigationController.SetNavigationBarHidden(!navBarVisible, true);
|
||||
|
||||
var coordinator = viewController.GetTransitionCoordinator();
|
||||
if (coordinator != null)
|
||||
if (coordinator != null && coordinator.IsInteractive)
|
||||
{
|
||||
// handle swipe to dismiss gesture
|
||||
coordinator.NotifyWhenInteractionEndsUsingBlock((context) =>
|
||||
{
|
||||
if (!context.IsCancelled)
|
||||
{
|
||||
_self._popCompletionTask = new TaskCompletionSource<bool>();
|
||||
_self.SendPoppedOnCompletion(_self._popCompletionTask.Task);
|
||||
}
|
||||
});
|
||||
if (Forms.IsiOS10OrNewer)
|
||||
coordinator.NotifyWhenInteractionChanges(OnInteractionChanged);
|
||||
else
|
||||
coordinator.NotifyWhenInteractionEndsUsingBlock(OnInteractionChanged);
|
||||
}
|
||||
}
|
||||
|
||||
void OnInteractionChanged(IUIViewControllerTransitionCoordinatorContext context)
|
||||
{
|
||||
if (!context.IsCancelled)
|
||||
{
|
||||
_self._popCompletionTask = new TaskCompletionSource<bool>();
|
||||
_self.SendPoppedOnCompletion(_self._popCompletionTask.Task);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче