diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue1931.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue1931.cs new file mode 100644 index 000000000..b9d6e0117 --- /dev/null +++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue1931.cs @@ -0,0 +1,109 @@ +using System.Collections.Generic; +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 +{ +#if UITEST + [Category(UITestCategories.ScrollView)] + [Category(UITestCategories.ListView)] +#endif + + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Github, 1931, + "Xamarin Forms on Android: ScrollView on ListView header crashes app when closing page", + PlatformAffected.Android)] + public class Issue1931 : TestNavigationPage + { + const string Go = "Go"; + const string Back = "Back"; + const string Success = "Success"; + Label _result; + Label _instructions2; + + ContentPage RootPage() + { + var page = new ContentPage(); + page.Title = "GH1931 Root"; + + var button = new Button { Text = Go }; + button.Clicked += (sender, args) => PushAsync(ListViewPage()); + + var instructions = new Label { Text = $"Tap the {Go} button" }; + + _result = new Label { Text = Success, IsVisible = false }; + _instructions2 = new Label { Text = "If you can see this, the test has passed", IsVisible = false }; + + var layout = new StackLayout(); + layout.Children.Add(instructions); + layout.Children.Add(button); + layout.Children.Add(_result); + layout.Children.Add(_instructions2); + page.Content = layout; + + return page; + } + + ContentPage ListViewPage() + { + var page = new ContentPage(); + + var layout = new StackLayout(); + + var listView = new ListView(); + + var scrollView = new ScrollView { Content = new BoxView { Color = Color.Green } }; + + listView.Header = scrollView; + + listView.ItemsSource = new List { "One", "Two", "Three" }; + + page.Title = "GH1931 Test"; + + var instructions = new Label { Text = $"Tap the {Back} button" }; + + var button = new Button { Text = Back }; + button.Clicked += (sender, args) => PopAsync(); + + layout.Children.Add(instructions); + layout.Children.Add(button); + layout.Children.Add(listView); + + page.Content = layout; + + page.Appearing += (sender, args) => + { + _instructions2.IsVisible = true; + _result.IsVisible = true; + }; + + return page; + } + + protected override void Init() + { + PushAsync(RootPage()); + } + + +#if UITEST + [Test] + public void ScrollViewInHeaderDisposesProperly() + { + RunningApp.WaitForElement(Go); + RunningApp.Tap(Go); + + RunningApp.WaitForElement(Back); + RunningApp.Tap(Back); + + RunningApp.WaitForElement(Success); + } +#endif + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems index 8147b62dd..4d4c1bc79 100644 --- a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems +++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems @@ -240,6 +240,7 @@ + @@ -907,4 +908,4 @@ MSBuild:UpdateDesignTimeXaml - + \ No newline at end of file diff --git a/Xamarin.Forms.Platform.Android/Renderers/ScrollViewRenderer.cs b/Xamarin.Forms.Platform.Android/Renderers/ScrollViewRenderer.cs index 4770fc542..6984a504f 100644 --- a/Xamarin.Forms.Platform.Android/Renderers/ScrollViewRenderer.cs +++ b/Xamarin.Forms.Platform.Android/Renderers/ScrollViewRenderer.cs @@ -24,6 +24,7 @@ namespace Xamarin.Forms.Platform.Android ScrollView _view; int _previousBottom; bool _isEnabled; + bool _disposed; public ScrollViewRenderer(Context context) : base(context) { @@ -176,18 +177,24 @@ namespace Xamarin.Forms.Platform.Android protected override void Dispose(bool disposing) { - base.Dispose(disposing); + if (_disposed) + { + return; + } - SetElement(null); + _disposed = true; if (disposing) { - Tracker.Dispose(); + SetElement(null); + Tracker?.Dispose(); Tracker = null; RemoveAllViews(); - _container.Dispose(); + _container?.Dispose(); _container = null; } + + base.Dispose(disposing); } protected override void OnAttachedToWindow()