-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Fix for CarouselView doesnot scroll corresponding to ItemsUpdatingScrollMode when collection modified #26608
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Hi @jsuarezruiz, We have fixed the issue. On Windows, ItemsUpdatingScrollMode is considered during collection updates. For Android and iOS, we have implemented code changes to ensure consistent behavior across all platforms and test cases for this issue are already included in the 26160 PR |
src/Controls/src/Core/Handlers/Items2/iOS/CarouselViewController2.cs
Outdated
Show resolved
Hide resolved
/azp run |
Azure Pipelines successfully started running 3 pipeline(s). |
/azp run |
Azure Pipelines successfully started running 3 pipeline(s). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are some CarouselView tests failing:
Issue12574Test
at UITest.Appium.HelperExtensions.Wait(Func`1 query, Func`2 satisfactory, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2107
at UITest.Appium.HelperExtensions.WaitForAtLeastOne(Func`1 query, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2124
at UITest.Appium.HelperExtensions.WaitForElement(IApp app, String marked, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency, Nullable`1 postTimeout) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 651
at Microsoft.Maui.TestCases.Tests.Issues.CarouselViewLoopNoFreeze.Issue12574Test() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/CarouselViewUITests.LoopNoFreeze.cs:line 44
at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
Issue10300Test
at UITest.Appium.HelperExtensions.Wait(Func`1 query, Func`2 satisfactory, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2107
at UITest.Appium.HelperExtensions.WaitForAtLeastOne(Func`1 query, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2124
at UITest.Appium.HelperExtensions.WaitForElement(IApp app, String marked, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency, Nullable`1 postTimeout) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 651
at Microsoft.Maui.TestCases.Tests.Issues.CarouselViewRemoveAt.Issue10300Test() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/CarouselViewUITests.RemoveAt.cs:line 25
at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
Hi @jsuarezruiz , The above-mentioned two issues are unrelated to our fix. Additionally, the timeout exception is not reproducible locally. Can we try re-running the tests once more? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you include an UITest to validate all the values for the ItemsUpdatingScrollMode property?
using System.Collections.ObjectModel;
namespace Maui.Controls.Sample.Issues
{
[Issue(IssueTracker.Github, 25991, "CarouselView reverts to displaying 1st item in collection when collection modified", PlatformAffected.UWP)]
public class Issue25991 : ContentPage
{
public class Issue25991Model
{
public string Text { get; set; }
}
ObservableCollection<Issue25991Model> _collection = new ObservableCollection<Issue25991Model>()
{
new Issue25991Model() { Text = "Item 1" },
new Issue25991Model() { Text = "Item 2" }
};
Label InfoLabel { get; set; }
CarouselView TestCarouselView { get; set; }
public Issue25991()
{
StackLayout mainStackLayout = new StackLayout();
mainStackLayout.Margin = new Thickness(5);
Label labelInstructions = new Label()
{
AutomationId = "WaitForStubControl",
Text = "Instructions:\nThe CarouselView contains Item 1 and Item 2. It will initially show the first page, Item 1.\n" +
"Click the 'Scroll to Item 2' button, and the CarouselView will correctly show Item 2.\n" +
"Click 'Add Item', which will add a new Item record to the collection.\n" +
"The CarouselView must stay in the Item 2."
};
mainStackLayout.Add(labelInstructions);
InfoLabel = new Label()
{
AutomationId = "InfoLabel",
};
mainStackLayout.Add(InfoLabel);
TestCarouselView = new CarouselView()
{
ItemsUpdatingScrollMode = ItemsUpdatingScrollMode.KeepScrollOffset,
ItemsSource = _collection,
Loop = false
};
TestCarouselView.ItemTemplate = new DataTemplate(() =>
{
StackLayout stackLayout = new StackLayout();
Label nameLabel = new Label();
nameLabel.SetBinding(Label.TextProperty, "Text");
nameLabel.FontSize = 25;
nameLabel.TextColor = Colors.Red;
stackLayout.Children.Add(nameLabel);
return stackLayout;
});
TestCarouselView.CurrentItemChanged += OnTestCarouselViewCurrentItemChanged;
mainStackLayout.Add(TestCarouselView);
Button scrollToPerson2Button = new Button()
{
AutomationId = "ScrollToPerson2Button",
Text = "Scroll to Item 2"
};
scrollToPerson2Button.Clicked += OnScrollToPerson2ButtonClicked;
mainStackLayout.Add(scrollToPerson2Button);
Button addItemButton = new Button()
{
AutomationId = "AddItemButton",
Text = "Add Item",
};
addItemButton.Clicked += OnAddButtonClicked;
mainStackLayout.Add(addItemButton);
HorizontalStackLayout buttonsStackLayout = new HorizontalStackLayout();
Button keepItemsInViewButton = new Button()
{
AutomationId = "KeepItemsInViewButton",
Text = "keepItemsInView",
};
keepItemsInViewButton.Clicked += OnKeepItemsInViewButtonClicked;
buttonsStackLayout.Add(keepItemsInViewButton);
Button keepScrollOffsetButton = new Button()
{
AutomationId = "KeepScrollOffsetButton",
Text = "KeepScrollOffset",
};
keepScrollOffsetButton.Clicked += OnKeepScrollOffsetButtonClicked;
buttonsStackLayout.Add(keepScrollOffsetButton);
Button keepLastItemInViewButton = new Button()
{
AutomationId = "KeepLastItemInViewButton",
Text = "KeepLastItemInView",
};
keepLastItemInViewButton.Clicked += OnKeepLastItemInViewButtonClicked;
buttonsStackLayout.Add(keepLastItemInViewButton);
mainStackLayout.Add(buttonsStackLayout);
Content = mainStackLayout;
}
void OnTestCarouselViewCurrentItemChanged(object sender, CurrentItemChangedEventArgs e)
{
InfoLabel.Text = TestCarouselView.Position.ToString();
}
void OnScrollToPerson2ButtonClicked(object sender, EventArgs e)
{
TestCarouselView.ScrollTo(1);
}
void OnAddButtonClicked(object sender, EventArgs e)
{
_collection.Add(new Issue25991Model()
{
Text = "Item " + (_collection.Count + 1),
});
}
void OnKeepItemsInViewButtonClicked(object sender, EventArgs e)
{
TestCarouselView.ItemsUpdatingScrollMode = ItemsUpdatingScrollMode.KeepItemsInView;
}
void OnKeepScrollOffsetButtonClicked(object sender, EventArgs e)
{
TestCarouselView.ItemsUpdatingScrollMode = ItemsUpdatingScrollMode.KeepScrollOffset;
}
void OnKeepLastItemInViewButtonClicked(object sender, EventArgs e)
{
TestCarouselView.ItemsUpdatingScrollMode = ItemsUpdatingScrollMode.KeepLastItemInView;
}
}
}
Hi @jsuarezruiz ,We have added the UITest cases to validate all the values for the |
/azp run |
Azure Pipelines successfully started running 3 pipeline(s). |
/rebase |
f6a1d23
to
5594050
Compare
/rebase |
48a51ec
to
a3d49a5
Compare
src/Controls/src/Core/Handlers/Items/Android/MauiCarouselRecyclerView.cs
Show resolved
Hide resolved
@@ -1,4 +1,5 @@ | |||
#if TEST_FAILS_ON_CATALYST && TEST_FAILS_ON_WINDOWS && TEST_FAILS_ON_ANDROID //The Position property now functions correctly on Android and Windows, issue: https://github.com/dotnet/maui/issues/15443. Note that on Catalyst, swipe and drag options are not supported in Appium. | |||
#if TEST_FAILS_ON_CATALYST && TEST_FAILS_ON_WINDOWS && TEST_FAILS_ON_ANDROID && TEST_FAILS_ON_IOS //The Position property now functions correctly on Android and Windows, issue: https://github.com/dotnet/maui/issues/15443. Note that on Catalyst, swipe and drag options are not supported in Appium. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now, on Catalyst, the Appium drag actions should be supported. However, probably you will get the same result than on iOS. But, to avoid future confusion, could update the comment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have modified the comments; kindly review the changes and let me know if you have any concerns.
/azp run |
Azure Pipelines successfully started running 3 pipeline(s). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/azp run |
Azure Pipelines successfully started running 3 pipeline(s). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, It's ok for the Flight branch
…ollMode when collection modified (dotnet#26608) * Added sample * Added test * Added UITest to validate Windows CarouselView scrolling behavior * Updated test * Updated test * More changes * Commit for 25991 * Commit for testcase changes * Update CarouselViewController2.cs * commit for unwanted changes * commit for unwanted changes * commit for testcase removal * commit for refactor * commit for method name change * Added sample * Added test * Added UITest to validate Windows CarouselView scrolling behavior * Updated test * Updated test * More changes * Fix the test * Update Issue25991.cs with minor fixes and additions * Fix Issue25991 test assertions and string format * Commit for testcase failure * commit for testcase changes * commit for testcase changes * Create ItemShouldbeScrolledbasedOnGroupHeader.png * Delete ItemShouldbeScrolledbasedOnGroupHeader.png * Add check for empty ItemsSource in CarouselViewController2. * Fix item addition logic in Issue25991 test * Update issue comments in Issue8964.cs --------- Co-authored-by: Javier Suárez <javiersuarezruiz@hotmail.com>
…ollMode when collection modified (dotnet#26608) * Added sample * Added test * Added UITest to validate Windows CarouselView scrolling behavior * Updated test * Updated test * More changes * Commit for 25991 * Commit for testcase changes * Update CarouselViewController2.cs * commit for unwanted changes * commit for unwanted changes * commit for testcase removal * commit for refactor * commit for method name change * Added sample * Added test * Added UITest to validate Windows CarouselView scrolling behavior * Updated test * Updated test * More changes * Fix the test * Update Issue25991.cs with minor fixes and additions * Fix Issue25991 test assertions and string format * Commit for testcase failure * commit for testcase changes * commit for testcase changes * Create ItemShouldbeScrolledbasedOnGroupHeader.png * Delete ItemShouldbeScrolledbasedOnGroupHeader.png * Add check for empty ItemsSource in CarouselViewController2. * Fix item addition logic in Issue25991 test * Update issue comments in Issue8964.cs --------- Co-authored-by: Javier Suárez <javiersuarezruiz@hotmail.com>
…ollMode when collection modified (#26608) * Added sample * Added test * Added UITest to validate Windows CarouselView scrolling behavior * Updated test * Updated test * More changes * Commit for 25991 * Commit for testcase changes * Update CarouselViewController2.cs * commit for unwanted changes * commit for unwanted changes * commit for testcase removal * commit for refactor * commit for method name change * Added sample * Added test * Added UITest to validate Windows CarouselView scrolling behavior * Updated test * Updated test * More changes * Fix the test * Update Issue25991.cs with minor fixes and additions * Fix Issue25991 test assertions and string format * Commit for testcase failure * commit for testcase changes * commit for testcase changes * Create ItemShouldbeScrolledbasedOnGroupHeader.png * Delete ItemShouldbeScrolledbasedOnGroupHeader.png * Add check for empty ItemsSource in CarouselViewController2. * Fix item addition logic in Issue25991 test * Update issue comments in Issue8964.cs --------- Co-authored-by: Javier Suárez <javiersuarezruiz@hotmail.com>
…ollMode when collection modified (#26608) * Added sample * Added test * Added UITest to validate Windows CarouselView scrolling behavior * Updated test * Updated test * More changes * Commit for 25991 * Commit for testcase changes * Update CarouselViewController2.cs * commit for unwanted changes * commit for unwanted changes * commit for testcase removal * commit for refactor * commit for method name change * Added sample * Added test * Added UITest to validate Windows CarouselView scrolling behavior * Updated test * Updated test * More changes * Fix the test * Update Issue25991.cs with minor fixes and additions * Fix Issue25991 test assertions and string format * Commit for testcase failure * commit for testcase changes * commit for testcase changes * Create ItemShouldbeScrolledbasedOnGroupHeader.png * Delete ItemShouldbeScrolledbasedOnGroupHeader.png * Add check for empty ItemsSource in CarouselViewController2. * Fix item addition logic in Issue25991 test * Update issue comments in Issue8964.cs --------- Co-authored-by: Javier Suárez <javiersuarezruiz@hotmail.com>
…ollMode when collection modified (#26608) * Added sample * Added test * Added UITest to validate Windows CarouselView scrolling behavior * Updated test * Updated test * More changes * Commit for 25991 * Commit for testcase changes * Update CarouselViewController2.cs * commit for unwanted changes * commit for unwanted changes * commit for testcase removal * commit for refactor * commit for method name change * Added sample * Added test * Added UITest to validate Windows CarouselView scrolling behavior * Updated test * Updated test * More changes * Fix the test * Update Issue25991.cs with minor fixes and additions * Fix Issue25991 test assertions and string format * Commit for testcase failure * commit for testcase changes * commit for testcase changes * Create ItemShouldbeScrolledbasedOnGroupHeader.png * Delete ItemShouldbeScrolledbasedOnGroupHeader.png * Add check for empty ItemsSource in CarouselViewController2. * Fix item addition logic in Issue25991 test * Update issue comments in Issue8964.cs --------- Co-authored-by: Javier Suárez <javiersuarezruiz@hotmail.com>
Issue Details
Behavior in windows: When modifying the collection, the CarouselView scrolls to display the first item. This is the expected behavior when considering the ItemsUpdatingScrollMode.
Android and iOS: While updating the collection, ItemsUpdatingScrollMode is not respected, causing the current position to deviate from the expected behavior for keeping items in view.
Root Cause
Android: In the MauiCarouselRecyclerView, the ItemsUpdatingScrollMode is not applied during the ItemsCollectionChanged event. As a result, the CarouselView maintains the position of the previously scrolled item.
iOS and Mac: In the CarouselViewController, the collection update ignores the ItemsUpdatingScrollMode, and the current position remains unchanged, irrespective of the scroll mode settings.
Fix Details
Android: Updated the MauiCarouselRecyclerView to adjust the carousel position based on the ItemsUpdatingScrollMode during collection updates.
iOS and Mac: Incorporated the ItemsUpdatingScrollMode into the collection update logic to ensure the position is updated appropriately according to the specified scroll mode.
Issues Fixed
Fixes #25991
Output Screenshot
Screen.Recording.2024-12-12.at.8.33.19.PM.mov
Screen.Recording.2024-12-12.at.8.30.44.PM.mov