Базовые анимации

50

Ранее уже было упомянуто основное правило анимации WPF: каждая анимация работает на основе отдельного свойства зависимости. Однако имеется и другое ограничение. Для осуществления анимации свойства (другими словами, для изменения его значения с течением времени) понадобится класс анимации, поддерживающий его тип данных. Например, свойство Button.Width использует тип данных double. Для его анимации применяется класс DoubleAnimation. Однако Button.Padding использует структуру Thickness, поэтому ему потребуется класс ThicknessAnimation.

Это требование не так строго, как первое правило WPF-анимации, ограничивающее анимацию свойствами зависимости. Причина в том, что для свойства зависимости, которое не имеет соответствующего класса анимации, можно создать собственный класс анимации для его типа данных. Тем не менее, в пространстве имен System.Windows.Animation доступны классы для большинства используемых типов данных.

Многие типы данных не имеют соответствующих классов анимации, поскольку это непрактично. Примером могут служить перечисления. Например, размещением элемента в панели компоновки можно управлять с помощью свойства HorizontalAlignment, которое принимает значения из перечисления HorizontalAlignment. Однако перечисление HorizontalAlignment предлагает только четыре значения (Left, Right, Center и Stretch), что существенно ограничивает его применение в анимации. Хотя есть возможность переключаться с одной ориентации на другую, плавно перенести элемент от одного типа выравнивания к другому не удастся. По этой причине класс анимации для типа данных HorizontalAlignment не предусмотрен. Его можно создать самостоятельно, однако ограничение этими четырьмя значениями перечисления все равно остается.

Анимация ссылочных типов обычно не выполняется, однако делается для их подсвойств. Например, все элементы управления имеют свойство Background, что позволяет устанавливать объект Brush, используемый для рисования фона. Применять анимацию для переключения от одной кисти к другой не слишком эффективно, но можно использовать анимацию для изменения свойств кисти, например, варьировать свойство Color объекта SolidColorBrush (применяя для этого класс ColorAnimation) или же свойство Offset объекта GradientStop в составе LinearGradient (с помощью класса DoubleAnimation). Это расширяет возможности анимации WPF, позволяя анимировать специальные аспекты внешнего вида элементов.

Классы анимации

На основе упомянутых типов анимации — DoubleAnimation и ColorAnimation — можно предположить, что все классы анимации называются в стиле ИмяТипаAnimation. Это близко к истине, но не совсем так.

На самом деле существуют два вида анимации — та, которая изменяет свойства последовательно от начального до конечного значения (этот процесс называется линейной интерполяцией), и та, что произвольно изменяет свойство от одного значения к другому.

Примерами из первой категории могут служить DoubleAnimation и ColorAnimation; они используют интерполяцию для гладкого изменения значения. Однако интерполяция не имеет смысла при изменении определенных типов данных, таких как строки и объекты ссылочных типов. Вместо применения интерполяции эти типы данных изменяются скачкообразно в определенный момент времени, для чего применяется техника, называемая анимацией ключевого кадра (key frame animation). Все классы анимации ключевого кадра носят имена в форме ИмяТипаAnimationUsingKeyFrames — например, StringAnimationUsingKeyFrames и ObjectAnimationUsingKeyFrames.

Некоторые типы данных имеют класс анимации ключевого кадра, но не имеют класса анимации методом интерполяции. Например, можно выполнять анимацию строки с использованием ключевых кадров, но не методом интерполяции. Однако каждый тип данных поддерживает анимацию ключевого кадра или же поддержка анимации вообще отсутствует. Другими словами, каждый тип данных, имеющий соответствующий ему класс анимации методом интерполяции (вроде DoubleAnimation и ColorAnimation), также имеет соответствующий тип анимации ключевого кадра (такой как DoubleAnimationUsingKeyFrames и ColorAnimationUsingKeyFrames).

По правде говоря, есть еще один тип анимации. Третий тип называется анимацией на основе пути (path-based animation), и этот тип более специализирован, чем анимация методом интерполяции или анимация ключевого кадра. Анимация на основе пути модифицирует значение в соответствии с фигурой, описанной в объекте PathGeometry, и в первую очередь применяется для перемещения элемента по некоторому пути. Классы для анимации на основе пути имеют имена в стиле ИмяТипаAnimationUsingPath, например, DoubleAnimationUsingPath или PointAnimationUsingPath.

Хотя в настоящее время в WPF используются три подхода к анимации (линейная интерполяция, ключевые кадры и пути), ничто не мешает создавать классы анимации, которые модифицируют значения на основе совершенно другого подхода. Единственное требование — класс анимации должен модифицировать значения с течением времени. В конечном итоге, вот что можно обнаружить в пространстве имен System.Windows.Media.Animation:

Все эти классы анимации унаследованы от абстрактного класса ИмяТипаAnimationBase, реализующего несколько основополагающих аспектов. Он предоставляет основу для создания собственных классов анимации. Если тип данных поддерживает более одного типа анимации, то все его классы анимации наследуются от абстрактного базового класса. Например, DoubleAnimation и DoubleAnimationUsingKeyFrames — оба являются наследниками DoubleAnimationBase.

Этими 42 классами содержимое пространства имен System.Windows.Media.Animation не исчерпывается. Каждая анимация ключевого кадра также работает с собственным классом ключевого кадра и классом коллекции ключевых кадров. Так что в сумме пространство имен System.Windows.Media.Animation содержит более 100 классов.

Заглянув в пространство имен System.Windows.Media.Animation, вы будете несколько шокированы. Оно включает в себя различные классы анимации для самых разнообразных типов данных. В результате все это выглядит несколько неупорядоченным. Было бы неплохо иметь какой-то способ комбинации всех средств анимации в несколько классов ядра. И почему бы ни построить класс Animation<T>, который смог бы работать с любым типом данных?

Однако, к сожалению, такая модель в настоящий момент невозможна по ряду причин. Главная из них состоит в том, что различные классы анимации могут выполнять свою работу несколько по-разному, а это требует разного кода. Например, способ перехода между полутонами одного цвета в классе ColorAnimation отличается от способа модификации отдельного числового значения в классе DoubleAnimation. Другими словами, хотя классы анимации и предоставляют одинаковый общедоступный интерфейс, их внутренняя реализация может сильно отличаться. Интерфейсы этих классов стандартизованы через наследование, поскольку все классы анимации унаследованы от одних и тех же базовых классов (начиная с Animatable).

Однако это еще не все. Естественно, многие классы анимации разделяют некоторый объем кода, а по некоторым вообще "плачут" обобщения, как, например, о сотне классов, используемых для представления ключевых кадров и коллекций ключевых кадров. В идеальном мире классы анимации отличались бы типом анимации, которую они выполняют, так что была бы возможность иметь дело c классами вроде NumerieAnimation<T>, KeyFrameAnimation<T> или LinearInterpolationAnimation<T>. Можно предположить, что более глубокая причина того, что классы анимации не организованы подобным образом, связана с отсутствием прямой поддержки обобщений в XAML.

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