# 页面过渡

`PageTransitions` are used to render a transition between two views, for example in a [Carousel](https://docs.avaloniaui.net/docs/controls/carousel) or [TransitioningContentControl](https://docs.avaloniaui.net/docs/controls/TransitioningContentControl)

{% hint style="warning" %}
The duration must be set before the transition is used and must be greater than 0. If not, you will get an error.
{% endhint %}

## Build-In PageTransitions

### CrossFade

The `CrossFade` fades out the current view and fades in the new view by animating the opacity.

{% tabs %}
{% tab title="XAML" %}

```markup
<CrossFade Duration="0:00:00.500" />
```

{% endtab %}

{% tab title="C#" %}

```csharp
var transition = new CrossFade(TimeSpan.FromMilliseconds(500));
```

{% endtab %}
{% endtabs %}

#### Source code

[CrossFade.cs](https://github.com/AvaloniaUI/Avalonia/blob/master/src/Avalonia.Visuals/Animation/CrossFade.cs)

#### Reference

[CrossFade](http://reference.avaloniaui.net/api/Avalonia.Animation/CrossFade/)

### PageSlide

The `PageSlide` slides the content either horizontally or vertically. You can specify the slide axis via the `Orientation`-property. The default value is `Horizontal`.

{% tabs %}
{% tab title="XAML" %}

```markup
<PageSlide Duration="0:00:00.500" Orientation="Vertical" />
```

{% endtab %}

{% tab title="C#" %}

```csharp
var transition = new PageSlide(TimeSpan.FromMilliseconds(500), PageSlide.SlideAxis.Vertical);
```

{% endtab %}
{% endtabs %}

#### Source code

[PageSlide.cs](https://github.com/AvaloniaUI/Avalonia/blob/master/src/Avalonia.Visuals/Animation/PageSlide.cs)

#### Reference

[PageSlide](http://reference.avaloniaui.net/api/Avalonia.Animation/PageSlide/)

### CompositePageTransition

The `CompositePageTransition` is used create a combined transition of several different transitions. The below sample creates a transition which slides the views diagonal (horizontally and vertically at the same time) and also fades the views out and in.

{% tabs %}
{% tab title="XAML" %}

```markup
<CompositePageTransition>
    <CrossFade Duration="0:00:00.500" />
    <PageSlide Duration="0:00:00.500" Orientation="Horizontal" />
    <PageSlide Duration="0:00:00.500" Orientation="Vertical" />
</CompositePageTransition>
```

{% endtab %}

{% tab title="C#" %}

```csharp
var compositeTransition = new CompositePageTransition();
compositeTransition.PageTransitions.Add(new PageSlide(TimeSpan.FromMilliseconds(500), PageSlide.SlideAxis.Vertical));
compositeTransition.PageTransitions.Add(new PageSlide(TimeSpan.FromMilliseconds(500), PageSlide.SlideAxis.Horizontal));
compositeTransition.PageTransitions.Add(new CrossFade(TimeSpan.FromMilliseconds(500)));
```

{% endtab %}
{% endtabs %}

#### Source code

[CompositePageTransition.cs](https://github.com/AvaloniaUI/Avalonia/blob/master/src/Avalonia.Visuals/Animation/CompositePageTransition.cs)

#### Reference

[CompositePageTransition](http://reference.avaloniaui.net/api/Avalonia.Animation/CompositePageTransition/)

## Custom PageTransitions

You can also create your own `PageTransition` by implementing the `IPageTransition`-interface.

The Interface has one member which you need to implement:

```csharp
public Task Start(Visual? from, Visual? to, bool forward, CancellationToken cancellationToken)
{
    // Setup the transition here.
}
```

### Example

Below is a sample which will shrink the old view and grow the new view in vertically direction.

```csharp
public class CustomTransition : IPageTransition
{
    /// <summary>
    /// Initializes a new instance of the <see cref="CustomTransition"/> class.
    /// </summary>
    public CustomTransition()
    {
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="CustomTransition"/> class.
    /// </summary>
    /// <param name="duration">The duration of the animation.</param>
    public CustomTransition(TimeSpan duration)
    {
        Duration = duration;
    }

    /// <summary>
    /// Gets the duration of the animation.
    /// </summary>
    public TimeSpan Duration { get; set; }

    public async Task Start(Visual from, Visual to, bool forward, CancellationToken cancellationToken)
    {
        if (cancellationToken.IsCancellationRequested)
        {
            return;
        }

        var tasks = new List<Task>();
        var parent = GetVisualParent(from, to);
        var scaleYProperty = ScaleTransform.ScaleYProperty;

        if (from != null)
        {
            var animation = new Animation
            {
                FillMode = FillMode.Forward,
                Children =
                {
                    new KeyFrame
                    {
                        Setters = { new Setter { Property = scaleYProperty, Value = 1d } },
                        Cue = new Cue(0d)
                    },
                    new KeyFrame
                    {
                        Setters =
                        {
                            new Setter
                            {
                                Property = scaleYProperty,
                                Value = 0d
                            }
                        },
                        Cue = new Cue(1d)
                    }
                },
                Duration = Duration
            };
            tasks.Add(animation.RunAsync(from, null, cancellationToken));
        }

        if (to != null)
        {
            to.IsVisible = true;
            var animation = new Animation
            {
                FillMode = FillMode.Forward,
                Children =
                {
                    new KeyFrame
                    {
                        Setters =
                        {
                            new Setter
                            {
                                Property = scaleYProperty,
                                Value = 0d
                            }
                        },
                        Cue = new Cue(0d)
                    },
                    new KeyFrame
                    {
                        Setters = { new Setter { Property = scaleYProperty, Value = 1d } },
                        Cue = new Cue(1d)
                    }
                },
                Duration = Duration
            };
            tasks.Add(animation.RunAsync(to, null, cancellationToken));
        }

        await Task.WhenAll(tasks);

        if (from != null && !cancellationToken.IsCancellationRequested)
        {
            from.IsVisible = false;
        }
    }

    /// <summary>
    /// Gets the common visual parent of the two control.
    /// </summary>
    /// <param name="from">The from control.</param>
    /// <param name="to">The to control.</param>
    /// <returns>The common parent.</returns>
    /// <exception cref="ArgumentException">
    /// The two controls do not share a common parent.
    /// </exception>
    /// <remarks>
    /// Any one of the parameters may be null, but not both.
    /// </remarks>
    private static IVisual GetVisualParent(IVisual? from, IVisual? to)
    {
        var p1 = (from ?? to)!.VisualParent;
        var p2 = (to ?? from)!.VisualParent;

        if (p1 != null && p2 != null && p1 != p2)
        {
            throw new ArgumentException("Controls for PageSlide must have same parent.");
        }

        return p1 ?? throw new InvalidOperationException("Cannot determine visual parent.");
    }
}
```

![Custom Transition Example](/files/FS6j3108kQz1szfu7lHV)

#### Source code

[IPageTransition.cs](https://github.com/AvaloniaUI/Avalonia/blob/master/src/Avalonia.Visuals/Animation/IPageTransition.cs)

#### Reference

[IPageTransition](http://reference.avaloniaui.net/api/Avalonia.Animation/IPageTransition/)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://avaloniachina.gitbook.io/avalonia/docs/animations/pagetransitions.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
