Анимация раскадровки не синхронизирована с предыдущей анимацией

Vijay Nirmal спросил: 28 марта 2018 в 02:06 в: c#

Я пытаюсь реализовать MiddleClickScrolling в ScrollViewer, и он работает хорошо.

Проблема заключается в перемещении указателя, который перезагружает Storyboard, чтобы обновить скорость но когда мы перемещаем указатель, происходит дрожание. Я добавил gif, но вы можете не заметить этот дрожание в этом gif.

Так как это большой класс, я не могу поместить весь код здесь. Вы можете увидеть мой полный код в GitHub (Примечание: Пожалуйста, выберите ветку SmoothScroll, если вы клонируете его). Легкий способ воспроизвести эту проблему - быстро перемещать указатель вверх и вниз на небольшое расстояние.

Это мой код для анимации раскадровки

_verticalDoubleAnimation = new DoubleAnimation()
{
    EnableDependentAnimation = true,
    Duration = new TimeSpan(0, 0, 1)
};//Different function
var offsetX = _currentPosition.X - _startPosition.X;
var offsetY = _currentPosition.Y - _startPosition.Y;SetCursorType(offsetX, offsetY);if (CanScrollVertical())
{
    if (Math.Abs(offsetY) > _threshold)
    {
        RunInUIThread(() =>
        {
            _verticalDoubleAnimation.From = _scrollViewer.VerticalOffset;
            _verticalDoubleAnimation.To = _scrollViewer.VerticalOffset + (offsetY > 0 ? _scrollViewer.ScrollableHeight : -_scrollViewer.ScrollableHeight);            if ((_scrollViewer.ScrollableHeight / (Math.Abs(offsetY) * _factor)) == double.NaN)
            {
                return;
            }            _verticalDoubleAnimation.Duration = TimeSpan.FromSeconds(_scrollViewer.ScrollableHeight / (Math.Abs(offsetY) * _factor));
            _verticalStoryboard.Begin();
        });
    }
    else
    {
        RunInUIThread(() =>
        {
            _verticalStoryboard.Stop();
            _sliderVertical.Value = _scrollViewer.VerticalOffset;
        });
    }
}

1 ответ

Есть решение
Sean O'Neil ответил: 29 марта 2018 в 10:58

Вместо того, чтобы анимировать его, используйте таймер или цикл while для динамического обновления позиции с помощью метода ScrollViewer.ChangeView (). Убедитесь, что интервал составляет менее 16,6 мс для плавного движения 60 кадров в секунду. Также убедитесь, что для последнего параметра ChangeView установлено значение false, чтобы его встроенная анимация была отключена.

Поэтому при первом коммите измените это:

timer = new Timer(ScrollAsync, null, 50, 50);

На это:

timer = new Timer(ScrollAsync, null, 0, 5);

Таймер не дает точности в пределах 1 мс или даже 10 мс, к моему непониманию. Сверхкомпенсация путем обновления каждые 1-5 мс должна восполнить это, так что это, вероятно, хорошо, и это то, что я использую в своем пользовательском контроле прокрутки. Секундомер очень точный, но это огромная нагрузка на процессор. Другой вариант: это большая дополнительная работа, но если вам нужна точная синхронизация и максимальная производительность при минимальном использовании батареи, вы можете использовать Win2D CanvasAnimatedControl, который можно использовать для запуска кода ровно раз в 60 секунд.

Vijay Nirmal ответил: 28 марта 2018 в 01:24
Я не думаю, что мы можем использовать Composition API напрямую в ScrollViewer, потому что я пытался анимировать ScrollViewer.VerticalOffset напрямую, но он только анимирует полосу прокрутки, но не прокручивает. В любом случае, я попробую. К вашему сведению, я дал ссылку на мой полный код в своем посте.
Vijay Nirmal ответил: 28 марта 2018 в 02:30
Кроме того, что такое _uIElement в вашем коде? Если я использую _scrollViewer, он смещает элемент управления, он не прокручивается.
Vijay Nirmal ответил: 28 марта 2018 в 02:35
Я думаю, что моя проблема связана с функцией ослабления. Есть ли способ установить LinearEase для DoubleAnimation? По умолчанию нет LinearEase
Sean O'Neil ответил: 28 марта 2018 в 02:56
UIElement Это то, на что вы нацеливаетесь с раскадровкой для анимации.
Sean O'Neil ответил: 28 марта 2018 в 03:08
Я взглянул на твой код, но не уверен, что анимация - это то, что тебе нужно. Я сделал что-то подобное, но с джойстиком геймпада и ItemsControl. Я просто обновил значение динамически, используя цикл while. Помните, что кадр видео 60 кадров в секунду составляет всего 16,6 мс. Если вы обновляете значение перевода UIElement со скоростью, превышающей скорость, вам не нужно ничего анимировать, это будет гладко. Как и в режиме среднего щелчка, возьмите расстояние от курсора до центра и добавьте его к значению Y UIElement каждые 5 мс или около того.