Skip to content
This repository has been archived by the owner on May 1, 2024. It is now read-only.

[Android] Fix bug. Children pages in NavigationPage were got appearing events even if they were not latest in navigation stack #758

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -0,0 +1,185 @@
using System;
using System.Linq;
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;
#if UITEST
using NUnit.Framework;
#endif


namespace Xamarin.Forms.Controls.Issues
{
[Preserve(AllMembers = true)]
[Issue(IssueTracker.Bugzilla, 52458, "Children pages in NavigationPage were got `appearing events` even if they were not latest in navigation stack", NavigationBehavior.PushModalAsync)]
public class Bugzilla52458 : TestPage
{
NavigationPage _navPage;
ContentPage _page2, _page3;
Label _checkIsAppearingLabel;

IPageController PageController => this;

protected override void Init()
{
NavigationPage navPage;
ContentPage appearingPage, page2, page3;

var appearingLabel = new Label
{
AutomationId = "checkIsAppearingLabel",
Text = false.ToString()
};

appearingPage = new ContentPage
{
Content = new StackLayout
{
Children =
{
new Button
{
BackgroundColor = Color.Red,
Text = "NavigateToPage2",
Command = new Command(NavigateToPage2)
}
}
}
};
page2 = new ContentPage
{
Content = new StackLayout
{
Children =
{
new StackLayout()
{
Orientation = StackOrientation.Horizontal,
Children =
{
new Label
{
Text = "First page is appeared: "
},
appearingLabel
}
},
new Button
{
Text = "SetPage3",
Command = new Command(SetPage3)
}
}
}
};
page3 = new ContentPage
{
Content = new StackLayout
{
Children =
{
new Button
{
Text = "RevertToNavigationPage",
Command = new Command(SetNavigationPage)
}
}
}
};

appearingPage.Appearing += OnAppearingFirstPage;
appearingPage.Disappearing += OnDisappearingFirstPage;

navPage = new NavigationPage(appearingPage);

_navPage = navPage;
_checkIsAppearingLabel = appearingLabel;
_page2 = page2;
_page3 = page3;

SetPage(navPage);
}

void OnAppearingFirstPage(object sender, EventArgs e)
{
Device.StartTimer(TimeSpan.FromMilliseconds(50), () =>
{
var currentPage = _navPage.CurrentPage;

_checkIsAppearingLabel.Text = true.ToString();

if (currentPage != sender)
{
//throw new Exception("Page cannot get appearing event if it is not last in NavigationStack");
}

return false;
});
}

void OnDisappearingFirstPage(object sender, EventArgs e)
{
_checkIsAppearingLabel.Text = false.ToString();
}

void SetNavigationPage()
{
SetPage(_navPage);
}

void NavigateToPage2()
{
if (_navPage.CurrentPage != _page2)
_navPage.PushAsync(_page2);
}

void SetPage3()
{
SetPage(_page3);
}

void SetPage(Page page)
{
if (PageController.InternalChildren.Count > 0)
PageController.InternalChildren.Remove(PageController.InternalChildren.First());
PageController.InternalChildren.Add(page);
}

protected override bool OnBackButtonPressed()
{
var currentPage = (Page)PageController.InternalChildren.FirstOrDefault();
var currentPageResult = currentPage?.SendBackButtonPressed();

if (currentPageResult != null && currentPageResult.Value)
{
return true;
}

return base.OnBackButtonPressed();
}

#if UITEST

[Test]
public void NavigationAppearingTest()
{
var app = RunningApp;
app.WaitForElement(x => x.Text("NavigateToPage2"));
app.Tap(x => x.Text("NavigateToPage2"));
app.WaitForElement(x => x.Text("SetPage3"));
app.Tap(x => x.Text("SetPage3"));
app.WaitForElement(x => x.Text("RevertToNavigationPage"));
app.Tap(x => x.Text("RevertToNavigationPage"));
app.WaitForElement(x => x.Marked("checkIsAppearingLabel"));

var checkIsAppearingLabel = app.Query(x => x.Marked("checkIsAppearingLabel")).First();

Assert.IsFalse(string.Equals(checkIsAppearingLabel.Text, true.ToString()), "Page cannot get appearing event if it is not last in NavigationStack");

app.Back();
}

#endif


}
}
Expand Up @@ -251,6 +251,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla39829.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla39458.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla39853.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla52458.cs" />
<Compile Include="$(MSBuildThisFileDirectory)PlatformSpecifics_iOSTranslucentNavBarX.xaml.cs">
<DependentUpon>PlatformSpecifics_iOSTranslucentNavBarX.xaml</DependentUpon>
<SubType>Code</SubType>
Expand Down
46 changes: 41 additions & 5 deletions Xamarin.Forms.Platform.Android/AppCompat/NavigationPageRenderer.cs
Expand Up @@ -267,11 +267,7 @@ protected override void OnElementChanged(ElementChangedEventArgs<NavigationPage>
navController.InsertPageBeforeRequested += OnInsertPageBeforeRequested;
navController.RemovePageRequested += OnRemovePageRequested;

// If there is already stuff on the stack we need to push it
foreach (Page page in navController.Pages)
{
PushViewAsync(page, false);
}
InsertPages(navController.Pages);
}
}

Expand Down Expand Up @@ -589,6 +585,46 @@ void SetupToolbar()
_toolbar = bar;
}

void InsertPages(IEnumerable<Page> pages)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a fan to add another way to insert pages to the fragment stack. Can't we fix the problem just on SwitchContentAsync ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. I will try to do it soon

{
_fragmentStack.Clear();

if (pages == null)
return;

var pagesCount = pages.Count();

for (int i = 0; i < pagesCount; i++)
{
var page = pages.ElementAt(i);
Fragment fragment = GetFragment(page, false, false);
_fragmentStack.Add(fragment);

if (i == pagesCount - 1)
{
((Platform)Element.Platform).NavAnimationInProgress = true;
FragmentTransaction transaction = FragmentManager.BeginTransaction();

Current = page;

transaction.DisallowAddToBackStack();
transaction.Add(Id, fragment);
transaction.Show(fragment);
transaction.CommitAllowingStateLoss();

Device.StartTimer(TimeSpan.FromMilliseconds(1), () =>
{
fragment.UserVisibleHint = true;
UpdateToolbar();
return false;
});

Context.HideKeyboard(this);
((Platform)Element.Platform).NavAnimationInProgress = false;
}
}
}

Task<bool> SwitchContentAsync(Page page, bool animated, bool removed = false, bool popToRoot = false)
{
var tcs = new TaskCompletionSource<bool>();
Expand Down