Don’t use CollectionView inside ScrollView in Xamarin.Forms

About the topic:

Contenido

In a previous article, I talked about how to use a CollectionView within a ScrollView in Xamarin.Forms, this time I will tell you why you shouldn’t do it, its consequences, and an alternative to the example we raised last time.

In this article, I will share with you a custom CollectionView control that encapsulates all the logic related to our use case, which this time is the Instagram Profile Page where a list of images is displayed in a grid with several tabs to change the context.

Note: This control can be used directly in your projects or simply adapt to your needs if it does not fit what you are looking for.

CollectionView inside a ScrollView

In the previous article, I told you a little about the CollectionView inside a ScrollView, its user experience, and its behavior. If you have not read the article yet, I recommend that you do so here.

On this occasion, I want to talk to you about why not use it in any context and I will give you some alternatives that can help you achieve the result you are looking for.

Why not use the CollectionView inside a ScrollView?

One of the reasons I mentioned in the last article was the User Experience, when using the CollectionView inside a ScrollView the behavior may not be what you are looking for.

Inappropriate behavior

Here’s an example of how a CollectionView behaves within a ScrollView:

CollectionView within a ScrollVIew.

Note: The displayed header does not belong to the CollectionView.

If you look good, until the CollectionView reaches the bottom of the list of items it handles, the ScrollView does not scroll unless you scroll from the header which does not belong to the CollectionView.

Performance is not good with large data collections

If we choose to create a custom control, like the one I show in the previous article, where you disable the Scroll of the CollectionView by defining a fixed height for the control, then we will run into memory problems and our application will crash.

Last time, I forgot to do the place tests, the tests to write articles make me lazy 😅. Thanks to Jorge Diego Crespo for his observation and for his pleasant interest in wanting to help the community. The best community ever!

Well, what happens is that we are not recycling the views on the screen, which is one of the most interesting features of the CollectionView, causing us to have memory issues.

💡 Tip: The CollectionView is efficient with large collections because it reuses view elements and requires the use of views to cache the views references.

This is the main problem why we should not use a CollectionView with a defined height inside a ScrollView.

So, if the solution we presented before is not the one indicated, what can we do?

Alternatives to a CollectionView within a ScrollView

In the previous article, I showed you a particular and very popular case where we might need to change contexts or use views that scroll but share the same header within the same page. This is the Instagram user page. Let’s go see it:

If you look, below the stories, are the TabsViews that allow us to visualize different types of data and contexts.

💡 Note: Previously, Instagram displayed in tabsView the type of view you wanted to see on the page either Grid or List. This behavior in Xamarin.Forms can be achieved with a TemplateSelector as long as the data context is the same.

We are going to see some alternatives that can help us create this type of user interface.

BindableLayout for small data collections

Bindable Layouts enable any Layout to generate content binding to a collection of elements, with the option of setting the appearance of each element with DataTemplate.

🚨 Note: When using this method and using large data collections we could also experience memory issues in our applications because views are not recycled.

Custom CollectionView for large data collections

Unlike the control that I showed in the previous article, what this control does is simulate the behavior of the scroll of the page with a little animation in the different elements that are shown on the page.

To achieve this we have defined some default parameters as:

  • CustomHeader, of type View, receives the instance of the View that we use as a header and has a default value of null.
  • SecondContent, of type View, receives the instance of the View that we use as a second content and has a default value of null.


With these parameters we can have one GoodCollactionView as follows:

    public class GoodollectionView : CollectionView
    {
...
        [TypeConverter(typeof(ReferenceTypeConverter))]
        public View CustomHeader
        {
            set
            {
                _customHeader = value;
                _customHeader.SizeChanged += (o, e) => this.Header = new BoxView() { HeightRequest = _customHeader.Height };                
            }
        }

        [TypeConverter(typeof(ReferenceTypeConverter))]
        public View SecondContent
        {
            set => _secondContent = value;
        }

        private async void GoodCollectionView_Scrolled(object sender, ItemsViewScrolledEventArgs e)
        {
            double scrollY = e.VerticalOffset < 0 ? 0 : e.VerticalOffset;
            scrollY = scrollY > _customHeader.Height ? _customHeader.Height : scrollY;

            // Show or hide the header and scroll the second view
            await Task.WhenAll(_customHeader?.TranslateTo(0, -scrollY, 50), 
                _secondContent?.TranslateTo(0, -scrollY + _customHeader.Height, 50));
        }
    }

Every time we scroll within our CollectionView, we calculate the scrollY and animate the transition of the header and the secondary content at the same time.

Note: There is a limitation. The control automatically creates a Header within the CollectionView, if you create a header it will be overwritten by our code and will add a BoxView to simulate the Margin of the control. If you want to use a Header within the CollectionView, just set a fixed height to your Header and to your row within the Grid where you position the header.

Once we have control, we can use it in our Xamarin Forms projects. Here’s an example in XAML:

...
    <Grid>

        <ctrls:GoodCollectionView
            x:Name="collectionView"
            Grid.RowSpan="2"
            CustomHeader="myCustomHeader"
            ItemSizingStrategy="MeasureFirstItem"
            ItemsLayout="VerticalGrid, 3"
            ItemsSource="{Binding Images}"
            SecondContent="mySecondView">

            <CollectionView.ItemTemplate>
                <DataTemplate>
                        ...
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </ctrls:GoodCollectionView>

        <!-- YOUR VIEWS GOES HERE -->

        <StackLayout x:Name="myCustomHeader" VerticalOptions="Start">
            ...
        </StackLayout>

    </Grid>
...

With this we can obtain a behavior similar to that of the Instagram profile page without losing the recycling of the views to avoid memory issues. Let’s see an example:

CollectionView within a ScrollVIew.

Note: The displayed header does not belong to the CollectionView.

Keep in mind that this control works with the height of our Header, that is, you have to work with defined heights or else use VerticalOptions = “Start” to define the height. If you don’t, the height will be -1.

Conclusion

As you can see I have presented two alternatives to avoid the use of the CollectionView within the ScrollView. The control that has been developed is very adapted to the needs, so it is very likely that you will have to adapt it to your needs if you want to use it.

I hope this article is useful, and nothing let me know on the networks that they really like these kinds of articles and I will do my best to give them the best of the best.

Help us grow our community and unlock the content below to access the sample repo. ⬇⬇⬇

With nothing else to add, see you next time!

What do you think of this content?
 
Luis Matos

Luis Matos

I help professionals and companies to create value solutions. I am a Systems Engineer, blockchain executive, and international mobile application speaker. Founder of the Malla Consulting Agency and several international technology communities.
Subscribe
Notify of
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x

Search in the site