Анимация свойств Double в WinRT

102

Класс DoubleAnimation, который мы использовали в предыдущей статье, позволяет применить анимацию к любому свойству типа double, поддерживаемому свойством зависимости, например Width и/или Height:

<Page
    x:Class="WinRTTestApp.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:WinRTTestApp">

    <Page.Resources>
        <Storyboard x:Key="storyboard"
                    AutoReverse="True"
                    RepeatBehavior="Forever">
            <DoubleAnimation Storyboard.TargetName="ellipse"
                             Storyboard.TargetProperty="Height"
                             EnableDependentAnimation="True"
                             From="500" To="100" Duration="0:0:1" />
            
            <DoubleAnimation Storyboard.TargetName="ellipse"
                             Storyboard.TargetProperty="Width"
                             EnableDependentAnimation="True"
                             From="100" To="500" Duration="0:0:1" />            
        </Storyboard>
    </Page.Resources>

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <Ellipse Name="ellipse">
            <Ellipse.Fill>
                <LinearGradientBrush>
                    <GradientStop Offset="0" Color="LightBlue" />
                    <GradientStop Offset="1" Color="Lime" />
                </LinearGradientBrush>
            </Ellipse.Fill>
        </Ellipse>
    </Grid>

</Page>

Две анимации выполняются параллельно. Первая изменяет свойство Width элемента Ellipse от 100 до 600, а вторая - свойство Height элемента Ellipse от 600 до 100. Два размера лишь на миг встречаются в средней точке, образуя круг. Настройки AutoReverse и RepeatBehavior могут задаваться либо для Storyboard (как сделано у меня), либо для отдельных анимаций.

Анимация запускается при загрузке страницы и работает «бесконечно»:

public MainPage()
{
    this.InitializeComponent();

    Loaded += (sender, args) =>
    {
        (this.Resources["storyboard"] as Storyboard).Begin();
    };
}

Так как кисть LinearGradientBrush, которой заполняется Ellipse, использует градиент по умолчанию - от левого верхнего угла к правому нижнему, градиент в действительности слегка сдвигается во время анимации.

Анимация ширины и высоты элемента Ellipse

Width и Height - не единственные свойства Ellipse, к которым может применяться анимация. Свойство StrokeThickness, определяемое классом Shape, также относится к типу double и поддерживается свойством зависимости. Следующий фрагмент выводит эллипс, контур которого обозначается серией точек, а анимация изменяет толщину пунктирной линии:

<Page ...>

    <Page.Resources>
        <Storyboard x:Key="storyboard">
            <DoubleAnimation Storyboard.TargetName="ellipse"
                             Storyboard.TargetProperty="StrokeThickness"
                             EnableDependentAnimation="True"
                             From="1" To="80" Duration="0:0:3"
                             RepeatBehavior="Forever"
                             AutoReverse="True" />
        </Storyboard>
    </Page.Resources>

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <Ellipse Name="ellipse"
                 Stroke="LimeGreen"
                 StrokeDashCap="Round"
                 StrokeDashArray="0 2" />
    </Grid>

</Page>

Анимация запускается в событии Loaded тем же кодом, что и в предыдущей программе.

Значение «0 2» свойства StrokeDashArray означает, что пунктирная линия состоит из отрезка, имеющего длину 0 единиц, за которым следует пробел величиной в 2 единицы (где единицей является значение StrokeThickness). Отрезок имеет закругленные концы благодаря свойству StrokeDashCap, причем закругление увеличивает длину отрезка, так что отрезок фактически превращается в точку с диаметром, равным StrokeThickness. Центры точек разделяются интервалом, равным двойной величине StrokeThickness, так что контуры точек разделяются интервалом StrokeThickness.

В этой анимации количество точек уменьшается, а затем возрастает с увеличением и уменьшением значения StrokeThickness в ходе анимации. Точки словно исчезают и появляются в правой части эллипса:

Анимация толщины линий

Нет ли у Ellipse других свойств типа double? Как насчет свойства StrokeDashOffset, которое указывает, с какой позиции начинаются отрезки и интервалы в пунктирной линии? Следующая разметка XAML использует объект Path с кривыми Безье для рисования знака бесконечности пунктирной линией. Анимация применяется к свойству StrokeDashOffset, чтобы точки «перемещались» по фигуре:

<Page ...>

    <Page.Resources>
        <Storyboard x:Key="storyboard">
            <DoubleAnimation Storyboard.TargetName="path"
                             Storyboard.TargetProperty="StrokeDashOffset"
                             EnableDependentAnimation="True"
                             From="0" To="1.5" Duration="0:0:1"
                             RepeatBehavior="Forever" />
        </Storyboard>
    </Page.Resources>

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <Viewbox>
            <Path Name="path"
                  Margin="12"
                  Stroke="LimeGreen"
                  StrokeThickness="24"
                  StrokeDashArray="0 1.5"
                  StrokeDashCap="Round"
                  Data="M 100   0
                        C  45   0,   0  45, 0 100
                        S  45 200, 100 200
                        S 200 150, 250 100
                        S 345   0, 400   0
                        S 500  45, 500 100
                        S 455 200, 400 200
                        S 300 150, 250 100
                        S 155   0, 100   0" />
        </Viewbox>
    </Grid>

</Page>

К сожалению, я не могу изобразить точки, ползающие по «восьмерке», на странице сайта, чтобы передать эффект анимации:

Анимация свойства StrokeDashOffset

Определение Path в этой программе использует хорошо известную аппроксимацию Безье для четверти круга. Для круга с центром в точке (0,9) дуга правой нижней четверти круга начинается в точке (100,0) и заканчивается в точке (0,100). Она очень хорошо аппроксимируется кривой Безье, которая также начинается в точке (100,0) и заканчивается в точке (0,100), с двумя контрольными точками (100,55) и (55,100). Из четырех дуг «Безье 55» можно составить целый круг.

Таким образом, дуга четверти круга, которая начинает знак бесконечности в левом верхнем углу, начинается в точке (100,0) и заканчивается в точке (0,100), но центр находится в точке (100,100) вместо (0,0), поэтому первая контрольная точка смещена на 55 единиц влево от (100,0), а вторая на 55 единиц вверх от (0,100) - получаем (45,0) и (0, 45).

Следующая кривая Безье продолжает фигуру в левом нижнем углу, начиная с точки (0, 100) (конца предыдущей кривой) и заканчивая в точке (100, 200) с контрольными точками (0,155) и (45,200). Но оставшаяся часть разметки продолжается не фигурами с маркером «C» (обозначающим кубическую кривую Безье - Cubic), а фигурами с маркером «S» (обозначающим плавную кривую Безье - Smooth). Как известно, две кривые Безье соединяются плавно, если их общая точка и две смежные контрольные точки коллинеарны (то есть находятся на одной прямой).

Присутствие фигуры S в синтаксисе разметки Path приводит к тому, что первая контрольная точка вычисляется автоматически так, чтобы она была коллинеарна с начальной точкой и предыдущей контрольной точкой и находилась от начальной точки на одинаковом расстоянии с предыдущей коллинеарной точкой. Таким образом, для первой кривой Безье с точками (0, 45) и (0,100) первая контрольная точка первой фигуры S имеет координаты (0,155).

При рисовании пунктирной линии, конец которой соединяется с началом, очень высока вероятность того, что отрезок в начальной точке будет неполным. Значение StrokeThickness, равное 24, было вычислено экспериментально, и оно не обязано быть целым числом. Например, в версии этой программы для Windows Phone я остановился на значении StrokeThickness 23,98.

Изучая остальные классы библиотеки Shapes в поиске свойств типа double, подходящих для анимации, вы также найдете свойства X1, Y1, X2 и Y2 класса Line. Позднее я покажу, как организовать анимацию свойств типа Point, встречающихся во многих классах, производных от PathSegment.

Современные веб-приложения уже давно запускаются и просматриваются не только с десктопных компьютеров, а также с различных мобильных устройств. Доля рынка мобильной рекламы в интернете растет с каждым годом, поэтому для мониторинга мобильной рекламы на ваших сайтах, понадобится гибкий сервис, наподобие admobispy.com, предлагающий многофункциональную систему отчетов по подробной информации о объявлениях в различных сетях.

Пройди тесты
Лучший чат для C# программистов