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

CollectionView - Recycle DataTemplates when using template selector #12011

Merged
merged 24 commits into from May 15, 2023

Conversation

Redth
Copy link
Member

@Redth Redth commented Dec 10, 2022

Description of Change

For Android and iOS we were using a single value for the 'view/cell' item type in the platform adapter/source. If you were using a data template selector, and returned different data templates, whenever a recycled view/cell's data template didn't match the data template it needed to display for the new/recycled context, the whole view tree of that template would be recreated.

This PR ensures we have a unique view/cell type for every different DataTemplate.Type that might be returned by the template selector so that when a view/cell is recycled it should always be reused for the same DataTemplate it was created for, and so the view hierarchy won't be recreated.

Issues Fixed

Previously we were returning a single view type id for all 'items' in collectionview, which meant if you were using a template selector, and had a variety of returned different DataTemplates, each would share the same recycled item.  When a recycled item is reused for a different template, it causes the view for that template to be recreated to be correct for the template selected.

This change returns a unique item id per DataTemplate.Type, so that recycled items should always have the correct DataTemplate.Type and not need to be recreated with a different view hierarchy.
Like on Android, we were using a single cell reuse identifier for iOS "items" regardless of if they had different DataTemplates.  If you were using a data template selector, and returned different data templates, whenever a recycled cell's data template didn't match the data template it needed to display for the new/recycled context, the whole view tree of that template would be recreated.

This change ensures we have a unique cell reuse id for every different DataTemplate.Type that might be returned by the template selector so that when a cell is recycled it should always be reused for the same Data Template it was created for, and so the view hierarchy won't be recreated.

This does require the DetermineCellReuseId to know the indexpath we're getting it for, so a new method was introduced, internal for NET7, protected for NET8+, and in NET8+ the old method is obsoleted.
@Redth Redth added the area/collectionview 📃 CollectionView, CarouselView, IndicatorView label Dec 10, 2022
Copy link
Contributor

@hartez hartez left a comment

Choose a reason for hiding this comment

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

Looks fine in theory, minor naming nit.

Redth and others added 5 commits February 14, 2023 11:22
@Redth Redth marked this pull request as ready for review February 14, 2023 17:00
@Vroomer
Copy link

Vroomer commented Feb 15, 2023

@Redth Hello, can you confirm whether this PR fixes #12988 as well?

@rmarinho
Copy link
Member

/rebase

1 similar comment
@mattleibow
Copy link
Member

/rebase

PureWeen and others added 3 commits May 10, 2023 10:44
The `CarouselViewAdapter` loops by basically returning a very large value for item count of its adapter/source which means the recyclerview is going to ask for view types with a position value that does not actually exist.

Previously this was ok because we returned only a single item view type ever, however now that we want to return a different type for template selector scenarios where there are potentially multiple template types, we need to override also the `GetItemViewType` and pass in the calculated position in the list properly (as we do in `OnBindViewHolder` here already) since the base `ItemsViewAdapter` class now calls `ItemsSource.GetItem(position)` in its `GetItemViewType()` call.
@PureWeen PureWeen merged commit c459b0d into main May 15, 2023
29 checks passed
@PureWeen PureWeen deleted the cv-recycle-templateselector-templates branch May 15, 2023 19:54
expensivecow pushed a commit to expensivecow/maui that referenced this pull request May 22, 2023
…otnet#12011)

* [Android] Use different view types per item template

Previously we were returning a single view type id for all 'items' in collectionview, which meant if you were using a template selector, and had a variety of returned different DataTemplates, each would share the same recycled item.  When a recycled item is reused for a different template, it causes the view for that template to be recreated to be correct for the template selected.

This change returns a unique item id per DataTemplate.Type, so that recycled items should always have the correct DataTemplate.Type and not need to be recreated with a different view hierarchy.

* [iOS] Distinct Cell reuse id's for different DataTemplates

Like on Android, we were using a single cell reuse identifier for iOS "items" regardless of if they had different DataTemplates.  If you were using a data template selector, and returned different data templates, whenever a recycled cell's data template didn't match the data template it needed to display for the new/recycled context, the whole view tree of that template would be recreated.

This change ensures we have a unique cell reuse id for every different DataTemplate.Type that might be returned by the template selector so that when a cell is recycled it should always be reused for the same Data Template it was created for, and so the view hierarchy won't be recreated.

This does require the DetermineCellReuseId to know the indexpath we're getting it for, so a new method was introduced, internal for NET7, protected for NET8+, and in NET8+ the old method is obsoleted.

* Switch up some xaml controls in the sample

* Expose Id internally to use for android view types

* Cache datatemplates for unique item view types

* Api changes (overrides)

* Improve sample

* Remove api txt change that shouldn't have been added

* Update src/Controls/src/Core/Handlers/Items/Android/Adapters/ItemsViewAdapter.cs

Co-authored-by: E.Z. Hart <hartez@users.noreply.github.com>

* Update src/Controls/src/Core/Handlers/Items/Android/Adapters/ItemsViewAdapter.cs

Co-authored-by: Rui Marinho <me@ruimarinho.net>

* Update src/Controls/src/Core/Handlers/Items/Android/Adapters/ItemsViewAdapter.cs

Co-authored-by: Rui Marinho <me@ruimarinho.net>

* Use DataTemplate Id for cellReuseId

* Calculate correct position for carousel adapter

The `CarouselViewAdapter` loops by basically returning a very large value for item count of its adapter/source which means the recyclerview is going to ask for view types with a position value that does not actually exist.

Previously this was ok because we returned only a single item view type ever, however now that we want to return a different type for template selector scenarios where there are potentially multiple template types, we need to override also the `GetItemViewType` and pass in the calculated position in the list properly (as we do in `OnBindViewHolder` here already) since the base `ItemsViewAdapter` class now calls `ItemsSource.GetItem(position)` in its `GetItemViewType()` call.

---------

Co-authored-by: Rui Marinho <me@ruimarinho.net>
Co-authored-by: E.Z. Hart <hartez@users.noreply.github.com>
Co-authored-by: Shane Neuville <shneuvil@microsoft.com>
expensivecow pushed a commit to expensivecow/maui that referenced this pull request May 22, 2023
expensivecow pushed a commit to expensivecow/maui that referenced this pull request May 22, 2023
…otnet#12011)

* [Android] Use different view types per item template

Previously we were returning a single view type id for all 'items' in collectionview, which meant if you were using a template selector, and had a variety of returned different DataTemplates, each would share the same recycled item.  When a recycled item is reused for a different template, it causes the view for that template to be recreated to be correct for the template selected.

This change returns a unique item id per DataTemplate.Type, so that recycled items should always have the correct DataTemplate.Type and not need to be recreated with a different view hierarchy.

* [iOS] Distinct Cell reuse id's for different DataTemplates

Like on Android, we were using a single cell reuse identifier for iOS "items" regardless of if they had different DataTemplates.  If you were using a data template selector, and returned different data templates, whenever a recycled cell's data template didn't match the data template it needed to display for the new/recycled context, the whole view tree of that template would be recreated.

This change ensures we have a unique cell reuse id for every different DataTemplate.Type that might be returned by the template selector so that when a cell is recycled it should always be reused for the same Data Template it was created for, and so the view hierarchy won't be recreated.

This does require the DetermineCellReuseId to know the indexpath we're getting it for, so a new method was introduced, internal for NET7, protected for NET8+, and in NET8+ the old method is obsoleted.

* Switch up some xaml controls in the sample

* Expose Id internally to use for android view types

* Cache datatemplates for unique item view types

* Api changes (overrides)

* Improve sample

* Remove api txt change that shouldn't have been added

* Update src/Controls/src/Core/Handlers/Items/Android/Adapters/ItemsViewAdapter.cs

Co-authored-by: E.Z. Hart <hartez@users.noreply.github.com>

* Update src/Controls/src/Core/Handlers/Items/Android/Adapters/ItemsViewAdapter.cs

Co-authored-by: Rui Marinho <me@ruimarinho.net>

* Update src/Controls/src/Core/Handlers/Items/Android/Adapters/ItemsViewAdapter.cs

Co-authored-by: Rui Marinho <me@ruimarinho.net>

* Use DataTemplate Id for cellReuseId

* Calculate correct position for carousel adapter

The `CarouselViewAdapter` loops by basically returning a very large value for item count of its adapter/source which means the recyclerview is going to ask for view types with a position value that does not actually exist.

Previously this was ok because we returned only a single item view type ever, however now that we want to return a different type for template selector scenarios where there are potentially multiple template types, we need to override also the `GetItemViewType` and pass in the calculated position in the list properly (as we do in `OnBindViewHolder` here already) since the base `ItemsViewAdapter` class now calls `ItemsSource.GetItem(position)` in its `GetItemViewType()` call.

---------

Co-authored-by: Rui Marinho <me@ruimarinho.net>
Co-authored-by: E.Z. Hart <hartez@users.noreply.github.com>
Co-authored-by: Shane Neuville <shneuvil@microsoft.com>
rmarinho added a commit that referenced this pull request May 30, 2023
…12011)

* [Android] Use different view types per item template

Previously we were returning a single view type id for all 'items' in collectionview, which meant if you were using a template selector, and had a variety of returned different DataTemplates, each would share the same recycled item.  When a recycled item is reused for a different template, it causes the view for that template to be recreated to be correct for the template selected.

This change returns a unique item id per DataTemplate.Type, so that recycled items should always have the correct DataTemplate.Type and not need to be recreated with a different view hierarchy.

* [iOS] Distinct Cell reuse id's for different DataTemplates

Like on Android, we were using a single cell reuse identifier for iOS "items" regardless of if they had different DataTemplates.  If you were using a data template selector, and returned different data templates, whenever a recycled cell's data template didn't match the data template it needed to display for the new/recycled context, the whole view tree of that template would be recreated.

This change ensures we have a unique cell reuse id for every different DataTemplate.Type that might be returned by the template selector so that when a cell is recycled it should always be reused for the same Data Template it was created for, and so the view hierarchy won't be recreated.

This does require the DetermineCellReuseId to know the indexpath we're getting it for, so a new method was introduced, internal for NET7, protected for NET8+, and in NET8+ the old method is obsoleted.

* Switch up some xaml controls in the sample

* Expose Id internally to use for android view types

* Cache datatemplates for unique item view types

* Api changes (overrides)

* Improve sample

* Remove api txt change that shouldn't have been added

* Update src/Controls/src/Core/Handlers/Items/Android/Adapters/ItemsViewAdapter.cs

Co-authored-by: E.Z. Hart <hartez@users.noreply.github.com>

* Update src/Controls/src/Core/Handlers/Items/Android/Adapters/ItemsViewAdapter.cs

Co-authored-by: Rui Marinho <me@ruimarinho.net>

* Update src/Controls/src/Core/Handlers/Items/Android/Adapters/ItemsViewAdapter.cs

Co-authored-by: Rui Marinho <me@ruimarinho.net>

* Use DataTemplate Id for cellReuseId

* Calculate correct position for carousel adapter

The `CarouselViewAdapter` loops by basically returning a very large value for item count of its adapter/source which means the recyclerview is going to ask for view types with a position value that does not actually exist.

Previously this was ok because we returned only a single item view type ever, however now that we want to return a different type for template selector scenarios where there are potentially multiple template types, we need to override also the `GetItemViewType` and pass in the calculated position in the list properly (as we do in `OnBindViewHolder` here already) since the base `ItemsViewAdapter` class now calls `ItemsSource.GetItem(position)` in its `GetItemViewType()` call.

---------

Co-authored-by: Rui Marinho <me@ruimarinho.net>
Co-authored-by: E.Z. Hart <hartez@users.noreply.github.com>
Co-authored-by: Shane Neuville <shneuvil@microsoft.com>
@github-actions github-actions bot locked and limited conversation to collaborators Dec 13, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area/collectionview 📃 CollectionView, CarouselView, IndicatorView
Projects
None yet
Development

Successfully merging this pull request may close these issues.

CollectionView virtualization does not work when using a DataTemplateSelector
6 participants