Awesome Scroll Effects in Xamarin.Forms
Tags: xamarinforms, design, mobile
Published: 2021-01-12 18:26:22

Everyone likes a good parallax scroll effect, right? While that's a good start, you can do so much more once you master the very basic techniques. In this post and video I look at behaviors, converters, and data triggers to add other animation effects and transitions to your UI. 

{% youtube K7SqT2_PuuU %}

The basis for this example is a reproduction of the Reverb app which I made a long time ago in my Xappy playground app. Navigate to Content\Scenarios\ProductDetails for the completed code.

{% github davidortinau/xappy no-readme %}

## Getting Scroll Values

Since the scrolling of content is the basis for all the effects in this experience, we need to start with getting values we can bind to. As those values change, we can follow along and trigger other things to happen in the UI.

The easiest way to get values such as the scroll X/Y, relative scroll X/Y, and percentage scroll X/Y is using a behavior from the awesome XAML animation library [Xamanimation](https://github.com/jsuarezruiz/Xamanimation). Xamanimation is a library that leverages all the built-in APIs of Xamarin.Forms to make complex animations with ease.

Let's start by adding this behavior to our Scrollview:

{% gist https://gist.github.com/davidortinau/6e8bb7288f5b0072c57abe7263bbfe44 file=snippet1.xaml %}

## Parallax Scrolling

To parallax scroll means that the foreground content moves at a different pace than the background (or middle ground) content. Let's start by understanding the layers of this layout. 

I'm using a `Grid` which effectively is a z-stack. The first item in the layout is in the back, then the next stacks on top of it, obscuring it. To then lay things out you'd use columns and rows of different sizes, define any elements to span columns and rows, and the vertical and horizontal options on your children elements. These are the basic points you have to control the layout and achieve any complexity you require. 

This is a look at the structure of this layout:

* Grid
  * BoxView
  * CarouselView
  * ScrollView
    * StackLayout - this is where all of our content resides 
  * FlexLayout - navigation bar with no background
  * FlexLayout - navigation bar with white background

As the `ScrollView` scrolls content, it will appear over the top of the `CarouselView`. The `BoxView` just mirrors the `CarouselView` to leave behind a white background. 

Now, in order to move the box and carousel with the content scrolling, we will bind to the scroll behavior's `RelativeScrollY` and translate the Y position of those views.

{% gist https://gist.github.com/davidortinau/6e8bb7288f5b0072c57abe7263bbfe44 file=snippet2.xaml %}

If I **only** used the `RelativeScrollY` or `ScrollY` values, the views would translate linear with the content, keeping pace. Instead, I want them to scroll a little slower, thus creating the parallax effect. To do this, I wrote the [ScrollValueConverter](https://github.com/davidortinau/Xappy/blob/main/Xappy/Xappy/Converters/ScrollValueConverter.cs), a value converter. To tweak the animation effect I pass in several arguments, semi-colon delimited.

{% gist https://gist.github.com/davidortinau/6e8bb7288f5b0072c57abe7263bbfe44 file=snippet8.cs %}

The main value of importance here is the "factor" that I use to multiple against the calculated percentage of scroll. The `-5` seems like it does nicely.

## Animating Other Values with Behaviors

I also want the carousel to fade out as the user scrolls, so for this scenario we can use a Xamarin.Forms behavior, provided again by Xamanimation. This allows you to animate any value based on another value you bind to.

{% gist https://gist.github.com/davidortinau/6e8bb7288f5b0072c57abe7263bbfe44 file=snippet3.xaml %}

This time I'm using the `ScrollY` value to change the `VisualElement.Opacity` to achieve a linear effect. The behavior starts at the Y value 0 and continues until 180 moving the opacity from 1 to 0. Pretty straight forward!

## Triggering Animations with Data Triggers

As the user scrolls and the carousel fades out, the navigation bar transitions from transparent background to solid, AND shifts the icons from white to dark. This can be accomplished in several ways, but I chose to do it by duplicating the navigation bar. As the user reaches a certain scroll point, a fade in/out animation is triggered.

{% gist https://gist.github.com/davidortinau/6e8bb7288f5b0072c57abe7263bbfe44 file=snippet6.xaml %}

This takes advantage of data triggers in Xamarin.Forms. The value of `ScrollY` is evaluated against criteria I've set to determine a boolean result. When true the `EnterActions` are called, and when false the `ExitActions`.

I wrote another value converter, [ComparisonConverter](https://github.com/davidortinau/Xappy/blob/main/Xappy/Xappy/Converters/ComparisonConverter.cs), to take a Y position and compare it to my parameter. The parameters are a position value and a comparison rule; in this case, greater than. As the value crosses that boundary, the animations are called.

Xamanimation brings animation extensions from C# to XAML. In this case, I've defined the animations to be triggered in my page resources:

{% gist https://gist.github.com/davidortinau/6e8bb7288f5b0072c57abe7263bbfe44 file=snippet4.xaml %}

## Final Polish

As the content scrolls out of view and back into view it scales away and fades. This happens linearly to the scroll position and at a certain Y position. Since we did this already with the behavior above, this same technique may be applied to each frame of content within the scroll view.

{% gist https://gist.github.com/davidortinau/6e8bb7288f5b0072c57abe7263bbfe44 file=snippet7.xaml %}

When the first frame hits a scroll Y of 320 it will scale to 75% and fade out completely by the time it reaches a scroll Y of 400. Simple and beautiful!

Please share any cool user experiences you create using these techniques in your experiments and applications. Enjoy!


### Resources:
* [Xamanimation](https://github.com/jsuarezruiz/Xamanimation)
* [Docs: Behaviors](https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/behaviors/)
* [Docs: Data triggers](https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/triggers#data-triggers)
* [Docs: Value converters](https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/data-binding/converters)

{% github davidortinau/xappy no-readme %}