Scrolling animations

This example shows how you can use a ScrollView together with ScrollingAnimation to create advanced visual effects to accompany scrolling. In this example, we have an article with a nice header that animates when you scroll through the article.

Design

The basic layout is like this:

<App Theme="Basic" Background="#eeeeeeff">
    <iOS.StatusBarConfig ux:Name="statusBarConfig" Style="Dark"/>
    <Panel>
		<MultiLayoutPanel ux:Name="headerPanel" HitTestMode="None" Alignment="Top" Height="260">
            ... Header content ...
        </MultiLayoutPanel>
        <ScrollView>
            ... Main content ...
        </ScrollView>
    </Panel>
</App>

The main part of our app is created with a Panel which layers the headerPanel on top of a ScrollView.

Notice that we set HitTestMode to "None" for headerPanel which makes it ignore all input. This has the effect of sending the input to the next element that is under the pointer. This way, we can scroll the ScrollView even if the headerPanel is above it visually.

ScrollingAnimation

A very central part of this example is the ScrollingAnimation trigger. It can be used to do animations based on a scrollviews scroll position.

One example is that the header gets smaller as you scroll down. Because the header and the body is on top of each other, they don't affect each other layout-wise.

We can move the backgroundPicture with a Move animator:

<ScrollingAnimation From="0" To="260">
    <Move Target="backgroundPicture" RelativeTo="Size" Y="-0.7" Easing="QuadraticOut"/>
    ... some other animators ...
</ScrollingAnimation>

All the Change blocks will be smoothly animated between scroll position 0 and 260. Note that RelativeTo="Size" Y="-0.7" means that the target element is moved 70% of its size in the negative Y-direction. The RelativeTo property gives us finer control of how to animate with relative numbers.

Throughout this example we use the RelativeTo property set to both "Size" and "ParentSize". If one wants to specify an arbitrary node as the relative node, one can use the RelativeNode property.

Animating the profile picture

There is an interesting type of animation happening to the face picture. Notice that at scroll position 0, the picture is on top of the background picture, but as we start scrolling, it actually moves behind it. To achieve this effect, we use a MultiLayoutPanel. The MultiLayoutPanel allows us to actually move the element to a different spot in the visual tree using a Placeholder node.

<MultiLayoutPanel ux:Name="headerPanel" HitTestMode="None" Alignment="Top" Height="260">
    <Placeholder ux:Name="overBackgroundLayout">
        <Image ux:Name="facePicture"  File="Assets/avatar.png" Alignment="BottomCenter"
               Width="150" Height="150" Offset="0,75"/>
    </Placeholder>

    ... background image ...

    <Placeholder ux:Name="underBackgroundLayout" Target="facePicture"/>
</MultiLayoutPanel>

Then we change which placeholder we want our picture to exist in:

<ScrollingAnimation From="125" To="0">
    <Set headerPanel.LayoutElement="overBackgroundLayout"/>
</ScrollingAnimation>
<ScrollingAnimation From="125" To="170">
    <Set headerPanel.LayoutElement="underBackgroundLayout"/>
</ScrollingAnimation>

Since the Set animator permanently changes its targets value, we have to set it back to its original state when we scroll back, hence the two animators.

The status bar text color change

On iOS devices, the background image is displayed under the statusbar (not visible in the gif). The top half of the image has quite bright colors, so we set the statusbar style to be dark. When we start scrolling, and the darker parts of our image go beneath the statusbar, we want to change the style to light. This can also be done with the ScrollingAnimation trigger:

<Fuse.iOS.StatusBarConfig ux:Name="statusBarConfig" Style="Dark"/>

Then, we simply use a Change on it during a ScrollingAnimation:

<ScrollingAnimation From="50" To="250">
    <Change statusBarConfig.Style="Light" />
</ScrollingAnimation>

Since this is a boolean change, the actual switch from dark to light style will happen when the animator progress is at 50%. In this case that would be at 150.

  • Note that this only applies to iOS, and has no effect on Android devices.