#005 Анимация текста в WPF / контейнер StackPanel
Сейчас мы поговорим о том, как при помощи WPF можно анимировать текст. Для начала, создайте новый проект типа WinFX Windows Application и назовите его "TextAnim". Первое, что мы сделаем - это немного увеличим размер окна и разместим форму по центру. Задайте следующие свойства для формы:
Height="480" Width="640" WindowStartupLocation ="CenterScreen"
Теперь давайте вспомним наше первое WPF приложение - мы тогда говорили о том, что существует масса различных контейнеров. До этого момента мы пользовались контейнером GRID (мы к нему еще вернемся в одной из следующих статей), но сегодня нам будет удобнее воспользоваться другим контейнером, который называется StackPanel. StackPanel размещает все элементы в столбик - один над другим - создается своеобразная "невидимая таблица" с одним столбцом и любым количеством строк (количество строк = количеству элементов внутри StackPanel). Высота строк регулируется автоматически, в зависимости от высоты элемента. В одной строке размещается только один элемент. Для этого приложения я хочу разместить на форме 4 текстовых блока, каждый друг над другом. Конечно, я мог бы сделать это и в Grid, но тогда мне бы пришлось вручную форматировать их местоположение при помощи свойств Margin, Alignment. Это намного проще сделать при помощи StackPanel:
<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TextAnim" Height="480" Width="640"
WindowStartupLocation ="CenterScreen"
>
<StackPanel >
<TextBlock >Мой первый текстовый блок</TextBlock>
<TextBlock >Мой второй текстовый блок</TextBlock>
<TextBlock >Мой третий текстовый блок</TextBlock>
<TextBlock >Мой четвертый текстовый блок</TextBlock>
</StackPanel>
</Window>
</TextBlock>
</StackPanel>
</Window>[/code]
Запустите проект и убедитесь, что текстовые элементы размещены так, как мы и хотели.
Обратите внимание - я применил необычный способ задания основного свойства для текстового блока. В данном случае это свойство TEXT. Я написал его значение между конструкторами элемента <TextBlock>. Такая форма записи равносильна следующей: <TextBlock Text="Мой текстовый блок"/> Так же можно поступать и с некоторыми другими элементами, например, со знакомым вам элементом <Button>.
Давайте немного изменим внешний вид наших надписей. Добавьте эти свойства к каждому текстовому блоку: FontFamily ="SegoeUI" FontSize ="38". Обратите внимание, что изменив размер наших надписей, при использовании StackPanel нам не нужно заботиться о том, чтобы вручную форматировать их расположение (как в случае с Grid) - StackPanel делает это за нас, засчет "виртуальных строк". Также давайте добавим к каждому текстовому блоку свойство Foreground, но теперь с любыми, но разными значениями, например вот так:
[code]<StackPanel >
<TextBlock FontFamily ="SegoeUI" FontSize ="38"
Foreground ="Green">Мой первый текстовый блок</TextBlock>
<TextBlock FontFamily ="SegoeUI" FontSize ="38"
Foreground="Red" >Мой второй текстовый блок</TextBlock>
<TextBlock FontFamily ="SegoeUI" FontSize ="38"
Foreground ="Blue" >Мой третий текстовый блок</TextBlock>
<TextBlock FontFamily ="SegoeUI" FontSize ="38"
Foreground ="Gold" >Мой четвертый текстовый блок</TextBlock>
</StackPanel>[/code]
Запустите программу и посмотрите, что получилось. Теперь давайте займемся анимацией наших текстовых блоков. Если вы помните нашу статью № 003, посвященную богатой графике и введению в анимацию - то вы знаете, что за интерактив элемента отвечает его свойство Triggers. Давайте зададим имена для каждого TextBlock-а. Для первого Name="MyWipedText", для второго Name="MyFadingText", для третьего Name="MyChangingColorText" и для четвертого Name="MyRotatingText". Как и в случае, когда мы анимировали прямоугольник в третьей статье, анимация будет начинаться при загрузке элемента, поэтому добавьте соответствующий код для каждого текстового блока, вот так:
[code]<TextBlock FontFamily ="SegoeUI" FontSize ="38"
Foreground ="Green"
Name="MyWipedText">Мой первый текстовый блок
<TextBlock.Triggers>
<EventTrigger RoutedEvent="TextBlock.Loaded">
<BeginStoryboard>
<Storyboard>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</TextBlock.Triggers>
</TextBlock>[/code]
Первый текстовый блок будет уничтожаться справа налево и восстанавливаться, поэтому внутри блока <Storyboard></Storyboard> для первого блока внесите такой код:
[code]<DoubleAnimation
Storyboard.TargetName="MyWipedText"
Storyboard.TargetProperty="(TextBlock.Width)"
To="0.0" Duration="0:0:10"
AutoReverse="True" RepeatBehavior="Forever" />[/code]
Думаю вы без труда разберетесь с этим кодом (для более подробной информации смотрите статью 003). Однако если вы сейчас попробуете запустить проект, вы получите сообщение об ошибке. Почему? Дело в том, что в данном случае мы подвергаем анимации свойство Width нашего текстового блока. Свойство To указывает, что ширина должна уменьшиться до 0, а свойство AutoReverse что ширина должна будет восстановиться до исходного значения. Но у нас нет исходного значения! С этим и связана ошибка. Поэтому, чтобы ее решить, давайте просто добавим Width="480" в описание текстового блока. Запустите программу и посмотрите на результат:
Да, анимация работает, но так и хочется крикнуть: "Эй, я не заказывал выравнивание по центру!" Давайте добавим в описание нашего первого блока еще и такое свойство HorizontalAlignment ="Left". Запускаем и смотрим:
Мы достигли желаемого эффекта! На всякий случай, полный код первого блока:
[code]<TextBlock FontFamily ="SegoeUI" FontSize ="38"
Foreground ="Green"
Name="MyWipedText" Width="480"
HorizontalAlignment ="Left">Мой первый текстовый блок
<TextBlock.Triggers>
<EventTrigger RoutedEvent="TextBlock.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="MyWipedText"
Storyboard.TargetProperty="(TextBlock.Width)"
To="0.0" Duration="0:0:10"
AutoReverse="True" RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</TextBlock.Triggers>
</TextBlock>[/code]
Давайте перейдем ко второй надписи - здесь мы хотим, чтобы надпись плавно исчезала и вновь появлялась. Для этого будем анимировать свойство прозрачности Opacity - оно принимает значения от 0 до 1. Например если вы хотите задать прозрачность 50%, то значением свойства Opacity будет 0.5 - добавьте этот код внутри блока <Storyboard></Storyboard> для нашего второго элемента:
[code]<DoubleAnimation
Storyboard.TargetName="MyFadingText"
Storyboard.TargetProperty="(TextBlock.Opacity)"
From="1.0" To="0.0" Duration="0:0:5"
AutoReverse="True" RepeatBehavior="Forever" />[/code]
Общий смысл аналогичен, поэтому комментировать не буду. Запустите проект и убедитесь, что вторая надпись ведет себя так, как мы и хотели.
Переходим к третьему текстовому блоку. Здесь бутет немного интересней. Я хочу, чтобы третья надпись меняла свой цвет. Для этого объектом анимации будет не сам TextBlock, а его заливочная кисть! Сейчас заливочная кисть не определена, поэтому давайте внесем кое-какие коррективы. Удалите свойство Foreground из описания третьего текстового блока:
После этого внесите этот код в тело надписи (помните, нечто подобное мы делали в статье 003?) :
Пусть вас не смущает что имя для кисти типа SolidColorBrush мы задали при помощи несколько необычного оператора x:Name. Теперь мы готовы к внесению кода анимации. Как обычно, внутри уже подготовленного блока <Storyboard></Storyboard> вносим такой код:
[code]<ColorAnimation
Storyboard.TargetName="MySolidColorBrush"
Storyboard.TargetProperty="Color"
From="DarkOrange" To="SteelBlue" Duration="0:0:5"
AutoReverse="True" RepeatBehavior="Forever" />[/code]
Обратите внимание, что теперь мы использовали новый тип анимации ColorAnimation - он подходит для анимирования кистей заливки и других подобных задач. Также посмотрите, что мы использовали свойство From - оно явно задало начальное значение для анимации. Запустите проект и посмотрите как красиво меняется цвет у нашей третьей надписи. На всякий случай полный код третьего элемента:
[code]<TextBlock FontFamily ="SegoeUI" FontSize ="38"
Name="MyChangingColorText">
Мой третий текстовый блок
<TextBlock.Foreground>
<SolidColorBrush x:Name="MySolidColorBrush" Color="Blue" />
</TextBlock.Foreground>
<TextBlock.Triggers>
<EventTrigger RoutedEvent="TextBlock.Loaded">
<BeginStoryboard>
<Storyboard>
<ColorAnimation
Storyboard.TargetName="MySolidColorBrush"
Storyboard.TargetProperty="Color"
From="DarkOrange" To="SteelBlue" Duration="0:0:5"
AutoReverse="True" RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</TextBlock.Triggers>
</TextBlock>[/code]
У нас остался четвертый элемент - мы заставим его вращаться! В WPF за различные изменения положения, формы и других подобных характеристик объекта отвечает свойство RenderTransform. Чтобы заставить надпись вертеться, анимации мы подвергнем характеристику Angle (угол) свойства RenderTransform. Добавьте такой код в тело четвертой надписи:
Внимательно изучите комментарии на картинке выше. Теперь мы готовы для создания анимации. Думаю вы уже догадались, что код анимации мы внесем между блоков <Storyboard></Storyboard> нашей четвертой надписи. Вот этот код:
[code]<DoubleAnimation
Storyboard.TargetName="MyRotateTransform"
Storyboard.TargetProperty="(RotateTransform.Angle)"
From="0.0" To="360" Duration="0:0:10"
RepeatBehavior="Forever" />[/code]
Тут все очень просто - мы меняем угол с 0 градусов (From) до 360 градусов (To) , чем и заставляем надпись вращаться вокруг своей оси. Запустите проект и посмотрите, что получилось:
Мы научились на примере текстовых надписей типа TextBlock создавать анимации различного типа. Обратите внимание на то, как просто создать сложные эффекты в Windows Presentation Foundation. Система позволяет одновременно воспроизводиться сразу любому количеству элементов и анимаций, при этом ваше окно полностью откликается на любые события. Представьте, сколько усилий потребовало бы от программиста, чтобы создать нечто подобное в обычном .NET 2.0 !
В завершение статьи, традиционно привожу полный листинг программы:
[code]<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TextAnim" Height="480" Width="640"
WindowStartupLocation ="CenterScreen"
>
<StackPanel >
<TextBlock FontFamily ="SegoeUI" FontSize ="38"
Foreground ="Green"
Name="MyWipedText" Width="480"
HorizontalAlignment ="Left">Мой первый текстовый блок
<TextBlock.Triggers>
<EventTrigger RoutedEvent="TextBlock.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="MyWipedText"
Storyboard.TargetProperty="(TextBlock.Width)"
To="0.0" Duration="0:0:10"
AutoReverse="True" RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</TextBlock.Triggers>
</TextBlock>
<TextBlock FontFamily ="SegoeUI" FontSize ="38"
Foreground="Red"
Name="MyFadingText">
Мой второй текстовый блок
<TextBlock.Triggers>
<EventTrigger RoutedEvent="TextBlock.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="MyFadingText"
Storyboard.TargetProperty="(TextBlock.Opacity)"
From="1.0" To="0.0" Duration="0:0:5"
AutoReverse="True" RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</TextBlock.Triggers>
</TextBlock>
<TextBlock FontFamily ="SegoeUI" FontSize ="38"
Name="MyChangingColorText">
Мой третий текстовый блок
<TextBlock.Foreground>
<SolidColorBrush x:Name="MySolidColorBrush" Color="Blue" />
</TextBlock.Foreground>
<TextBlock.Triggers>
<EventTrigger RoutedEvent="TextBlock.Loaded">
<BeginStoryboard>
<Storyboard>
<ColorAnimation
Storyboard.TargetName="MySolidColorBrush"
Storyboard.TargetProperty="Color"
From="DarkOrange" To="SteelBlue" Duration="0:0:5"
AutoReverse="True" RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</TextBlock.Triggers>
</TextBlock>
<TextBlock FontFamily ="SegoeUI" FontSize ="38"
Foreground ="Gold"
Name="MyRotatingText">
Мой четвертый текстовый блок
<TextBlock.RenderTransform>
<RotateTransform x:Name="MyRotateTransform"
Angle="0" CenterX="230" CenterY="25"/>
</TextBlock.RenderTransform>
<TextBlock.Triggers>
<EventTrigger RoutedEvent="TextBlock.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="MyRotateTransform"
Storyboard.TargetProperty="(RotateTransform.Angle)"
From="0.0" To="360" Duration="0:0:10"
RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</TextBlock.Triggers>
</TextBlock>
</StackPanel
</Window>[/code]
Июль, 2006
По теме
- Создаем контекстно-зависимое WPF-приложение
- #024 – Знакомство с WPF/E
- #023 – Введение в WPF, reloaded…
- #022 Введение в Microsoft Interactive Designer RC1
- #021 Применение 3D в WPF - Часть 2
- #020 Применение 3D в WPF - Часть 1
- #019 Введение в возможности 3D на WPF
- #018 Размещение контрола NET 2.0 на форме WPF
- #017 Первое Web-приложение / Подробнее о Grid / Элемент Frame
- #016 EXE, XBAP, XAML? - Все равно!