Sticky Header or Sticky Navigation Bar in Xamarin.Forms

About the topic:

Contenido

If you’ve previously wondered how to create a StickyHeader or  StickyNavigationBar in Xamarin.Forms then you’re in the right place.

In this article, I will share with you a CustomCollectionView control to use its Scrolled event, and we will be encapsulating all the logic related to our use case. This time we use the Instagram Profile Page where we have a list of images in a Grid with some tabs to displayed or change the context.

💡 Note: You can also use the ScrollView with its Scrolled event and everything will work the same way.

Understanding the StickyHeader

StickyHeader or StickyNavigation refers to having design elements that are permanently on users’ screens, even when the user scrolling down or up in a view. While this was mainly reserved for the navigation bar at the beginning, but we are seeing elements like floating buttons and other elements that have become popular as sticky elements used in mobile app design.

Creating the StickyHeader

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

This header when we scroll down it stays stuck at the top. And if we scroll to its starting position, it starts scrolling with the other elements.

Custom CollectionView with StickyHeader

In the previous article, we talked a little bit about how to create a collectionView with multiple data contexts that share the same header. If you haven’t seen it I recommend you keep an eye on it so you understand it a little bit.

To achieve this we have defined some default parameters as:

  • StickyHeader, of type View, receives the instance of the view that we will be used as a sticky header and has a default value of null.
  • CustomHeader, of type View, receives the instance of the view that we will be using as a header and has a default value of null.
  • SecondContent, of type View, receives the instance of the view that we will be using as child content and has a default value of null.


With these parameters, we can have the CustomCollactionView as follows:

    public class CustomCollectionView : 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 StickyHeader
        {
            set => _sticyHeader = value;
        }

        [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;
            double minimumHeight = _customHeader.Height - _sticyHeader.Height;

            scrollY = scrollY > minimumHeight ? minimumHeight : 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));
        }
    }

Each time you scroll within our CollectionView, we calculated scrollY, and encourage the transition of the header and child content at the same time. Similarly, we set the transition limits so that our sticky header is always displayed in the view.

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 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 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:CustomCollectionView
            x:Name="collectionView"
            Grid.RowSpan="2"
            CustomHeader="myCustomHeader"
            StickyHeader="myStickyHeader"
            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">
            ...
            <!-- YOUR STICKY HEADER GOES HERE -->
        </StackLayout>

    </Grid>
...

With this, we can get behavior similar to that of the Instagram profile page with our sticky header. Let’s look at an example:

CollectionView inside a ScrollVIew with StickyHeader.
Note: The displayed header does not belong to the CollectionView.

Conclusion

I hope this article is useful for you. Let me know on social media if you really like these kinds of articles, and I will do my best to give you the best of the best.

Help 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
1 Comment
Oldest
Newest
Inline Feedbacks
View all comments
1
0
Would love your thoughts, please comment.x
()
x

Search in the site