Skip to content
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

[iOS] Fix setting the CurrentItem on CarouselView load #22279

Open
wants to merge 19 commits into
base: main
Choose a base branch
from

Conversation

rmarinho
Copy link
Member

@rmarinho rmarinho commented May 7, 2024

Description of Change

Since the mappers run when the handler is started and in different order than forms, seems the initial position based on CurrentItem wasn't being set correctly since the mapper for the Position property runs first and overrides it.

We also fix an issue when rotating was not keeping the correct position, since the scroll event was triggered and we want to avoid updating the position till the orientation finishes. This changed the Scrolled event to be fired when the scroll animation finishes.

Added a way to know better when we the CollectionViewController is attached or detached from the view hierarchy. So now we can proper call the TearDown and Setup.

Fixes some warnings

Issues Fixed

Fixes #18879

Copilot summary

This pull request includes changes to the CarouselViewHandler.iOS.cs and CarouselViewController.cs files in the src/Controls/src/Core/Handlers/Items/ directory. The changes primarily involve refactoring the code, adding new methods, and improving the existing logic.

Here are the most significant changes:

Changes in CarouselViewHandler.iOS.cs:

  • Imported Foundation and UIKit namespaces.
  • Modified the ScrollToRequested method to include a new NSIndexPath instance and added a new scrollToItemAction method.
  • Updated the MapPosition method to handle situations where the initial position hasn't been set.
  • Added a new AnimationDuration property in the MapLoop method.

Changes in CarouselViewController.cs:

  • Imported the Microsoft.Maui.Devices namespace.
  • Refactored the CarouselViewController class to include new fields and methods, and modified the constructor.
  • Updated the GetCell method to include new conditions for DefaultCell and TemplatedCell. [1] [2]
  • Modified the ViewDidLayoutSubviews method to use _isCenteringItem instead of _updatingScrollOffset.
  • Refactored the UpdateItemsSource method to use InitialPositionSet instead of _initialPositionSet.
  • Updated the AttachingToWindow and DetachingFromWindow methods, and added new methods InitialPositionSet, TearDown, and Setup.
  • Modified the CarouselViewScrolled method to include new conditions.
  • Refactored the CollectionViewUpdating and CollectionViewUpdated methods to include new conditions.
  • Updated the UpdateLoop and UpdateFromCurrentItem methods to include new conditions. [1] [2]
  • Modified the UpdateFromPosition method to include new conditions and logic.
  • Updated the UpdateInitialPosition and UpdateVisualStates methods to include new conditions and logic. [1] [2]
  • Refactored the CarouselViewLoopManager class to include new conditions. [1] [2] [3]

@rmarinho rmarinho requested a review from a team as a code owner May 7, 2024 18:46
@Eilon Eilon added the area-controls-collectionview CollectionView, CarouselView, IndicatorView label May 7, 2024
@rmarinho rmarinho requested a review from PureWeen May 8, 2024 22:50
jsuarezruiz
jsuarezruiz previously approved these changes May 9, 2024
@@ -23,9 +23,9 @@ protected override void FixtureSetup()
[Category(UITestCategories.CarouselView)]
public async Task CarouselViewSetPosition()
Copy link
Contributor

Choose a reason for hiding this comment

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

This one is failing on iOS
image

@@ -17,20 +18,34 @@ public class CarouselViewController : ItemsViewController<CarouselView>
protected readonly CarouselView Carousel;

CarouselViewLoopManager _carouselViewLoopManager;
bool _initialPositionSet;
bool _updatingScrollOffset;
Copy link
Member Author

Choose a reason for hiding this comment

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

I just renamed this one to be more clear

@@ -44,10 +59,14 @@ public override UICollectionViewCell GetCell(UICollectionView collectionView, NS
var correctedIndexPath = NSIndexPath.FromRowSection(cellAndCorrectedIndex.correctedIndex, 0);

if (cell is DefaultCell defaultCell)
{
Copy link
Member Author

Choose a reason for hiding this comment

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

Fixing warnings and added {

@rmarinho rmarinho requested a review from PureWeen May 23, 2024 16:44
@@ -249,6 +262,15 @@ void InvalidateMeasureIfContentSizeChanged()
_previousContentSize = contentSize.Value;
}

internal virtual void AttachingToWindow()
Copy link
Member

Choose a reason for hiding this comment

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

can we make this private protected instead?

internal override void DettachingFromWindow()
{
base.DettachingFromWindow();
TearDown();
Copy link
Member

Choose a reason for hiding this comment

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

I don't think we can just outright call TearDown here

Or we need to move some of the cod that's in the ctor into AttachingToWindow

for example this is unsubscrived from

carousel.Scrolled -= CarouselViewScrolled;

Inside of TearDown, but subscribed to in the ctor.

Just because something is detaching from the window, doesn't mean it won't get re-attached.

For example, when a modal is pushed on top of the current screen. The VC below that modal will get unattached.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah , you right, got eager that actually never gets called, let me move the subscribe to the correct place to.

}
}

internal override void DettachingFromWindow()
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
internal override void DettachingFromWindow()
internal override void DetachingFromWindow()

@@ -139,13 +139,15 @@ public CarouselItem(int index, string image = null)
Index = index;

if (string.IsNullOrEmpty(image))
Image = "https://picsum.photos/700/300/";
Image = "oasis.jpg";
Copy link
Member Author

Choose a reason for hiding this comment

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

Just fix so we don't use a web image

@@ -82,27 +82,31 @@
CurrentItem="{Binding Selected}">
<CarouselView.ItemTemplate>
<DataTemplate>
<Frame
<Border
Copy link
Member Author

Choose a reason for hiding this comment

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

We like Border

using CoreGraphics;
using UIKit;

namespace Microsoft.Maui.Controls.Handlers.Items;

internal class MauiCollectionView : UICollectionView
internal class MauiCollectionView : UICollectionView, IUIViewLifeCycleEvents
Copy link
Member Author

Choose a reason for hiding this comment

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

This allows the Controller to know how it can subscribe and cleanup better.

this.GetDesiredSizeFromHandler(widthConstraint, heightConstraint);

protected virtual double AnimationDuration => 0.5;
Copy link
Member Author

Choose a reason for hiding this comment

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

Should this be private for now? open on net9 ?

@rmarinho
Copy link
Member Author

Seems is breaking this test FlyoutHeaderScroll

Scrolled Header: position 44 is no enough to cover height (-250). Epsilon: 0.3

https://dev.azure.com/xamarin/public/_build/results?buildId=116396&view=ms.vss-test-web.build-test-results-tab&runId=2821703&resultId=100285&paneView=debug

@@ -17,48 +17,146 @@ public CarouselViewUITests(TestDevice device)
protected override void FixtureSetup()
{
base.FixtureSetup();
App.NavigateToGallery(CarouselViewGallery);
//App.NavigateToGallery(CarouselViewGallery);
Copy link
Contributor

Choose a reason for hiding this comment

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

This was maybe commented testing and has it escaped?

base.LoadView();
var collectionView = new MauiCollectionView(CGRect.Empty, ItemsViewLayout);
CollectionView = collectionView;
(collectionView as IUIViewLifeCycleEvents).MovedToWindow += CollectionViewMovedToWindow;
Copy link
Contributor

Choose a reason for hiding this comment

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

Unsubscribe when doing dispose

@@ -14,4 +16,18 @@ public override void ScrollRectToVisible(CGRect rect, bool animated)
if (!KeyboardAutoManagerScroll.IsKeyboardAutoScrollHandling)
base.ScrollRectToVisible(rect, animated);
}

[UnconditionalSuppressMessage("Memory", "MEM0002", Justification = IUIViewLifeCycleEvents.UnconditionalSuppressMessage)]
Copy link
Contributor

Choose a reason for hiding this comment

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

Also the CarouselView is included in the HandlerDoesNotLeak. Looks fine pasing the test.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-controls-collectionview CollectionView, CarouselView, IndicatorView
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Problem initializing the CurrentItem for the Carousel
4 participants