using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; using Xamarin.Forms.CustomAttributes; using Xamarin.Forms.Internals; #if UITEST using NUnit.Framework; using Xamarin.UITest; #endif namespace Xamarin.Forms.Controls.Issues { [Preserve(AllMembers = true)] [Issue(IssueTracker.Github, 2411, "ListView.ScrollTo not working in TabbedPage", PlatformAffected.Android)] public class Issue2411 : TestTabbedPage { protected override void Init() { Children.Add(new XamarinListViewScrollToBugPage1()); Children.Add(new XamarinListViewScrollToBugPage2()); Children.Add(new XamarinListViewScrollToBugPage3()); } #if UITEST [Test] #if __ANDROID__ [Ignore("Appearing event is tied to virtualization in TabbedPage for Material")] #endif #if __MACOS__ [Ignore("ScrollTo not implemented on MacOS")] #endif [Issue(IssueTracker.Github, 2411, "ScrollToPosition.MakeVisible not called every time TabbedPage", PlatformAffected.Android)] public void Issue2411ScrollToPositionMakeVisible() { RunningApp.WaitForElement(q => q.Marked("99 99 99 99 99 99")); RunningApp.Screenshot("ScrollTo working correctly"); RunningApp.Tap(q => q.Marked("Crash in ScrollToPosition.End")); RunningApp.Screenshot("On Second Tab"); RunningApp.WaitForElement(q => q.Marked("2 0 0 0 0 0 0")); RunningApp.Tap(q => q.Marked("Scroll To in OnAppearing")); RunningApp.Screenshot("On First Tab"); RunningApp.WaitForElement(q => q.Marked("99 99 99 99 99 99")); var listViewBound = RunningApp.Query(q => q.Marked("listView"))[0].Rect; Xamarin.Forms.Core.UITests.Gestures.ScrollForElement(RunningApp, "* marked:'0 0 0 0 0 0'", new Xamarin.Forms.Core.UITests.Drag(listViewBound, Xamarin.Forms.Core.UITests.Drag.Direction.TopToBottom, Xamarin.Forms.Core.UITests.Drag.DragLength.Long)); RunningApp.Screenshot("Scrolled to Top"); RunningApp.Tap(q => q.Marked("Crash in ScrollToPosition.End")); RunningApp.Screenshot("On Second Tab"); RunningApp.WaitForElement(q => q.Marked("2 0 0 0 0 0 0")); RunningApp.Tap(q => q.Marked("Scroll To in OnAppearing")); RunningApp.Screenshot("On First Tab"); RunningApp.WaitForElement(q => q.Marked("99 99 99 99 99 99")); } [Test] [Issue(IssueTracker.Github, 2411, "ScrollToPosition.End crashing in TabbedPage", PlatformAffected.Android)] #if __MACOS__ [Ignore("ScrollTo not implemented on MacOS")] #endif public void Issue2411ScrollToPositionEndCrash() { RunningApp.Tap(q => q.Marked("Crash in ScrollToPosition.End")); RunningApp.Screenshot("On Second Tab"); RunningApp.Tap(q => q.Marked("Scroll To in OnAppearing")); RunningApp.Screenshot("On First Tab"); RunningApp.Tap(q => q.Marked("Crash in ScrollToPosition.End")); RunningApp.Screenshot("On Second Tab Again"); RunningApp.Tap(q => q.Marked("ScrollToPosition.End End - Not animated")); RunningApp.WaitForElement(q => q.Marked("2 99 99 99 99 99 99")); } [Test] [Issue(IssueTracker.Github, 2411, "ScrollToPositon.End crashing in TabbedPage", PlatformAffected.Android)] public void Issue2411ScrollToPositionWrongOnUneven() { RunningApp.Tap(q => q.Marked("Crash in ScrollToPosition.End")); RunningApp.Tap(q => q.Marked("Scroll To in OnAppearing Uneven")); var dontRun = RunningApp.Query(q => q.Marked(XamarinListViewScrollToBugPage3.DontRun)); if (dontRun.Length > 0) Assert.Inconclusive("Ignored on iOS < 9 until Bugzilla 28277 is resolved."); RunningApp.Screenshot("On Third Tab"); RunningApp.WaitForElement(q => q.Marked("99 99 99 99 99 99")); } #endif } [Preserve(AllMembers = true)] internal class ListObj { public string Name { get; set; } } [Preserve(AllMembers = true)] public class CellTemplateScrollTo : ViewCell { public CellTemplateScrollTo() { Label cellLabel = new Label() { HorizontalOptions = LayoutOptions.FillAndExpand, }; cellLabel.SetBinding(Label.TextProperty, new Binding("Name", BindingMode.OneWay)); StackLayout root = new StackLayout() { Children = { cellLabel } }; View = root; } } [Preserve(AllMembers = true)] public class CellTemplateScrollToUneven : CellTemplateScrollTo { public CellTemplateScrollToUneven() { Height = 60 + new Random().Next(10, 100); } } [Preserve(AllMembers = true)] public class XamarinListViewScrollToBugPage1 : ContentPage { ListView _listView; ObservableCollection _collection = new ObservableCollection(); public XamarinListViewScrollToBugPage1() { Title = "Scroll To in OnAppearing"; for (int i = 0; i < 100; i++) { var item = new ListObj { Name = string.Format("{0} {0} {0} {0} {0} {0}", i) }; _collection.Add(item); } _listView = new ListView { ItemsSource = _collection, ItemTemplate = new DataTemplate(typeof(CellTemplateScrollTo)) }; _listView.AutomationId = "listView"; Content = new StackLayout { Children = { _listView } }; } protected override void OnAppearing() { base.OnAppearing(); _listView.ScrollTo(_collection.Last(), ScrollToPosition.MakeVisible, false); } } [Preserve(AllMembers = true)] public class XamarinListViewScrollToBugPage2 : ContentPage { ListView _listView; ObservableCollection _collection = new ObservableCollection(); public XamarinListViewScrollToBugPage2() { Title = "Crash in ScrollToPosition.End"; for (int i = 0; i < 100; i++) { var item = new ListObj { Name = string.Format("2 {0} {0} {0} {0} {0} {0}", i) }; _collection.Add(item); } _listView = new ListView { ItemsSource = _collection, ItemTemplate = new DataTemplate(typeof(CellTemplateScrollTo)) }; var endButton = new Button { Text = "ScrollToPosition.End End - Not animated", Command = new Command(() => { _listView.ScrollTo(_collection.Last(), ScrollToPosition.End, false); }) }; var endButtonAnimated = new Button { Text = "ScrollToPosition.MakeVisible End - Animated", Command = new Command(() => { _listView.ScrollTo(_collection.Last(), ScrollToPosition.MakeVisible, true); }) }; Content = new StackLayout { Children = { endButton, endButtonAnimated, _listView } }; } } public class XamarinListViewScrollToBugPage3 : ContentPage { ListView _listView; ObservableCollection _collection = new ObservableCollection(); int _i = 0; public const string DontRun = "Don't run"; public XamarinListViewScrollToBugPage3() { Title = "Scroll To in OnAppearing Uneven"; bool runTest = true; // This test will fail in iOS < 9 because using ScrollTo with UnevenRows with estimation is currently not working. // It did not previously fail because this test used `TakePerformanceHit` to turn off row estimation. However, as // that was never a public feature, it was never a valid fix for the test. // https://bugzilla.xamarin.com/show_bug.cgi?id=28277 #if !UITEST if (App.IOSVersion < 9) runTest = false; #endif if (!runTest) _collection.Add(new ListObj { Name = DontRun }); else { for (_i = 0; _i < 100; _i++) { var item = new ListObj { Name = string.Format("{0} {0} {0} {0} {0} {0}", _i) }; _collection.Add(item); } } var btnAdd = new Button { Text = "Add item", WidthRequest = 100 }; btnAdd.Clicked += BtnAddOnClicked; var btnBottom = new Button { Text = "Scroll to end", WidthRequest = 100 }; btnBottom.Clicked += BtnBottomOnClicked; var btnPanel = new StackLayout { Orientation = StackOrientation.Horizontal, HorizontalOptions = LayoutOptions.Center, Children = { btnAdd, btnBottom } }; _listView = new ListView { ItemsSource = _collection, BackgroundColor = Color.Transparent, VerticalOptions = LayoutOptions.FillAndExpand, HasUnevenRows = true, ItemTemplate = new DataTemplate(typeof(CellTemplateScrollToUneven)) }; _listView.ItemTapped += (sender, e) => ((ListView)sender).SelectedItem = null; _listView.AutomationId = "listView"; Content = new StackLayout { Children = { btnPanel, _listView } }; } protected override void OnAppearing() { base.OnAppearing(); _listView.ScrollTo(_collection.Last(), ScrollToPosition.MakeVisible, false); } void BtnBottomOnClicked(object sender, EventArgs e) { var item = _collection.Last(); _listView.ScrollTo(item, ScrollToPosition.End, true); } void BtnAddOnClicked(object sender, EventArgs eventArgs) { var str = string.Format("Item {0}", _i++); var item = new ListObj { Name = string.Format("{0} {0} {0} {0} {0} {0}", _i) }; _collection.Add(item); _listView.ScrollTo(item, ScrollToPosition.End, true); } } }