Создание специальной функции плавности

38

Унаследовав новый класс от EasingFunctionBase и переопределив методы EaseInCore() и CreateInstanceCore(), можно создать собственный специальный эффект плавности. Это очень специализированная техника, потому что большинство разработчиков получают нужный результат, конфигурируя стандартные функции плавности (либо используя анимацию ключевого сплайна). Тем не менее, создание собственной функции плавности оказывается неожиданно простым. Почти вся логика, которую нужно при этом написать, выполняется в методе EaseInCore(). Он получает значение нормализованного времени — по сути, значение от 0 до 1, представляющее ход анимации. Когда анимация начинается впервые, нормализованное время равно 0. Затем оно растет, пока не достигнет значения 1 в конце анимации:

protected override double EaseInCore(double normalizedTime)
{ ... }

В течение анимации среда WPF вызывает EaseInCore каждый раз, когда обновляет анимированное значение. Точная частота зависит от частоты кадров, однако можно рассчитывать на примерно 60 вызовов EaselnCore() в секунду.

Для выполнения функции плавности метод EaseInCore() принимает нормализованное время и определенным образом его корректирует. Скорректированное значение, возвращаемое EaseInCore(), затем используется для подстройки хода анимации.

Например, если EaseInCore() возвращает 0, анимация возвращается к своей начальной точке. Если EaseInCore() возвращает 1, анимация перепрыгивает в конечную точку. Тем не менее, метод EaseInCore() не ограничивается этим диапазоном. Например, он может вернуть 1.5, заставив анимацию перегнать себя на дополнительные 50% (этот эффект уже демонстрировался в функции плавности типа ElasticEase).

Ниже приведена версия EaseInCore(), которая вообще ничего не делает. Она возвращает нормализованное значение, предоставляя анимации выполняться обычным образом, как если бы не было вообще никакой функции плавности:

protected override double EaseInCore(double normalizedTime)
{
   return normalizedTime;
}

А вот версия EaseInCore(), которая дублирует функцию CubicEase, возводя в куб нормализованное время. Поскольку нормализованное время выражается дробным значением, возведение в куб порождает меньшую величину. Поэтому данный метод дает эффект начального замедления анимации и ускорения его по мере того, как нормализованное время (и его значение в кубе) приближается к 1:

protected override double EaseInCore(double normalizedTime)
{
    return Math.Pow(normalizedTime, 3);
}

Плавность, которая реализуется в методе EaseInCode() — это то, что получается при использовании значения EaseIn для EasingMode. Интересно, что это все, что потребуется, поскольку среда WPF достаточно интеллектуальна, чтобы самостоятельно вычислить дополняющее поведение для режимов EaseOut и EaseInOut.

Наконец, ниже показана функция плавности, которая делает нечто более интересное — смещает нормализованное значение на случайную величину, создавая эффект случайной дрожи. Амплитуда дрожания может изменяться (в пределах заданного диапазона) с помощью свойства зависимости Jitter, которое принимает значения от 0 до 2000:

public class RandomJitterEase : EasingFunctionBase
    {
        // Генератор случайных чисел
        private Random rand = new Random();

        protected override double EaseInCore(double normalizedTime)
        {
            if (normalizedTime == 1) return 1;
            return Math.Abs(normalizedTime - (double)rand.Next(0,10)/(2010 - Jitter));
        }

        public int Jitter
        {
            get { return (int)GetValue(JitterProperty); }
            set { SetValue(JitterProperty, value); }
        }

        public static readonly DependencyProperty JitterProperty =
            DependencyProperty.Register("Jitter", typeof(int), typeof(RandomJitterEase),
            new UIPropertyMetadata(1000), new ValidateValueCallback(ValidateJitter));

        private static bool ValidateJitter(object value)
        {
            int jitterValue = (int)value;
            return ((jitterValue <= 2000) && (jitterValue >= 0));
        }
            
        protected override Freezable CreateInstanceCore()
        {
            return new RandomJitterEase();
        }
    }

Для просмотра значений плавности, которые вычисляются в процессе анимации, добавьте в EaseInCore() вызов метода WriteLine() класса System.Diagnostinc.Debug. Это выведет указанное значение в окно Output (Вывод) во время отладки в Visual Studio.

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