diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla33561.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla33561.cs index ec55d3700..5f1cfe1db 100644 --- a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla33561.cs +++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla33561.cs @@ -1,14 +1,14 @@ using System; - -using Xamarin.Forms.CustomAttributes; -using Xamarin.Forms.Internals; using System.Linq; using System.Threading.Tasks; +using Xamarin.Forms.CustomAttributes; +using Xamarin.Forms.Internals; namespace Xamarin.Forms.Controls { [Preserve(AllMembers = true)] - [Issue(IssueTracker.Bugzilla, 33561, "ListView Pull-to-Refresh ActivityIndicator animation stuck when navigating away and then back again")] + [Issue(IssueTracker.Bugzilla, 33561, + "ListView Pull-to-Refresh ActivityIndicator animation stuck when navigating away and then back again")] public class Bugzilla33561 : TestTabbedPage { public class ListPage : ContentPage @@ -21,7 +21,7 @@ namespace Xamarin.Forms.Controls var template = new DataTemplate(typeof(TextCell)); template.SetBinding(TextCell.TextProperty, "."); - _listView = new ListView() + _listView = new ListView { IsPullToRefreshEnabled = true, ItemsSource = Enumerable.Range(0, 10).Select(no => $"FAIL {no}"), @@ -29,7 +29,7 @@ namespace Xamarin.Forms.Controls IsRefreshing = true }; - _listView.Refreshing += async (object sender, EventArgs e) => + _listView.Refreshing += async (sender, e) => { if (_isRefreshing) return; @@ -50,8 +50,8 @@ namespace Xamarin.Forms.Controls protected override void Init() { Children.Add(new NavigationPage(new ListPage()) { Title = "page 1" }); - Children.Add(new ContentPage() { Title = "page 2" }); - Children.Add(new ContentPage() { Title = "page 3" }); + Children.Add(new ContentPage { Title = "page 2" }); + Children.Add(new ContentPage { Title = "page 3" }); } } } diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue2247.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue2247.cs new file mode 100644 index 000000000..8b9d1d44d --- /dev/null +++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue2247.cs @@ -0,0 +1,43 @@ +using System.Linq; +using Xamarin.Forms.CustomAttributes; +using Xamarin.Forms.Internals; + +namespace Xamarin.Forms.Controls +{ + // This test covers the issue reported in https://github.com/xamarin/Xamarin.Forms/issues/2247 + // for NavigationBehavior.PushAsync. Coverage for NavigationBehavior.PushModalAsync is provided by Bugzilla33561. + + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Github, 2247, + "[iOS] ListView.IsRefreshing not showing activity indicator on iOS", NavigationBehavior.PushAsync)] + public class Issue2247 : TestContentPage + { + ListView _listView; + bool _isRefreshing; + + protected override void Init() + { + var instructions = new Label + { + Text = "The ListView on this page should be displaying the 'refreshing' activity indicator." + + " If it is not, the test has failed" + }; + + var template = new DataTemplate(typeof(TextCell)); + template.SetBinding(TextCell.TextProperty, "."); + + _listView = new ListView + { + IsPullToRefreshEnabled = true, + ItemsSource = Enumerable.Range(0, 10).Select(no => $"Item {no}"), + ItemTemplate = template, + IsRefreshing = true + }; + + Content = new StackLayout + { + Children = { instructions, _listView } + }; + } + } +} \ 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 c6ea2614f..c74e7e480 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 @@ -238,6 +238,7 @@ + diff --git a/Xamarin.Forms.Controls/TestCases.cs b/Xamarin.Forms.Controls/TestCases.cs index c69aaafb4..aeff773eb 100644 --- a/Xamarin.Forms.Controls/TestCases.cs +++ b/Xamarin.Forms.Controls/TestCases.cs @@ -125,6 +125,7 @@ namespace Xamarin.Forms.Controls } readonly List _issues; + TableSection _section; void VerifyNoDuplicates() { @@ -161,10 +162,6 @@ namespace Xamarin.Forms.Controls Action = ActivatePageAndNavigate (attribute, typeInfo.AsType ()) }).ToList(); - var root = new TableRoot (); - var section = new TableSection ("Bug Repro"); - root.Add (section); - VerifyNoDuplicates(); FilterIssues(); @@ -196,10 +193,6 @@ namespace Xamarin.Forms.Controls PageToAction.Clear(); - var root = new TableRoot (); - var section = new TableSection ("Bug Repro"); - root.Add (section); - var issueCells = Enumerable.Empty(); if (!_filterBugzilla) @@ -234,12 +227,19 @@ namespace Xamarin.Forms.Controls issueCells = issueCells.Concat(untrackedIssueCells); } + + if (_section != null) + { + Root.Remove(_section); + } + + _section = new TableSection("Bug Repro"); foreach (var issueCell in issueCells) { - section.Add (issueCell); + _section.Add (issueCell); } - Root = root; + Root.Add(_section); } // Legacy reasons, do not add to this list diff --git a/Xamarin.Forms.Platform.iOS/Platform.cs b/Xamarin.Forms.Platform.iOS/Platform.cs index d8564d2e3..a593f91a0 100644 --- a/Xamarin.Forms.Platform.iOS/Platform.cs +++ b/Xamarin.Forms.Platform.iOS/Platform.cs @@ -163,6 +163,8 @@ namespace Xamarin.Forms.Platform.iOS Task INavigation.PushModalAsync(Page modal, bool animated) { + EndEditing(); + _modals.Add(modal); modal.Platform = this; @@ -476,10 +478,30 @@ namespace Xamarin.Forms.Platform.iOS // One might wonder why these delays are here... well thats a great question. It turns out iOS will claim the // presentation is complete before it really is. It does not however inform you when it is really done (and thus // would be safe to dismiss the VC). Fortunately this is almost never an issue + await _renderer.PresentViewControllerAsync(wrapper, animated); await Task.Delay(5); } + void EndEditing() + { + // If any text entry controls have focus, we need to end their editing session + // so that they are not the first responder; if we don't some things (like the activity indicator + // on pull-to-refresh) will not work correctly. + + // The topmost modal on the stack will have the Window; we can use that to end any current + // editing that's going on + if (_modals.Count > 0) + { + var uiViewController = GetRenderer(_modals[_modals.Count - 1]) as UIViewController; + uiViewController?.View?.Window?.EndEditing(true); + return; + } + + // If there aren't any modals, then the platform renderer will have the Window + _renderer.View?.Window?.EndEditing(true); + } + internal class DefaultRenderer : VisualElementRenderer { public override UIView HitTest(CGPoint point, UIEvent uievent) diff --git a/Xamarin.Forms.Platform.iOS/Renderers/NavigationRenderer.cs b/Xamarin.Forms.Platform.iOS/Renderers/NavigationRenderer.cs index 340829ade..decec294e 100644 --- a/Xamarin.Forms.Platform.iOS/Renderers/NavigationRenderer.cs +++ b/Xamarin.Forms.Platform.iOS/Renderers/NavigationRenderer.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Threading.Tasks; +using ObjCRuntime; using UIKit; using Xamarin.Forms.Internals; using Xamarin.Forms.PlatformConfiguration.iOSSpecific; @@ -527,6 +528,11 @@ namespace Xamarin.Forms.Platform.iOS void OnPushRequested(object sender, NavigationRequestedEventArgs e) { + // If any text entry controls have focus, we need to end their editing session + // so that they are not the first responder; if we don't some things (like the activity indicator + // on pull-to-refresh) will not work correctly. + View?.Window?.EndEditing(true); + e.Task = PushPageAsync(e.Page, e.Animated); }