Прокрутка импульса на мобильных устройствах - PullRequest
2 голосов
/ 23 марта 2011

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

Я хочу, чтобы он был достаточно универсальным, чтобы он мог переноситься на любую платформу, но в настоящее время я работаю в C # на .net Compact Framework.

То, что я сейчас делаю, это:

  • Создать объект секундомера (в ctor панели)
  • при наведении мыши запустите секундомер и сохраните текущую точку мыши _lastMouse
  • при перемещении мыши остановите секундомер и сохраните velocity = (_lastMouse - curMouse) / Stopwatch.TotalSeconds, затем сбросьте секундомер и запустите его снова
    • В большинстве случаев Stopwatch.TotalSeconds находится между 0,02 и 0,03
  • при наведении мыши, я передаю значение velocity в функцию плавной прокрутки, и эта функция продолжает прокручивать панель до тех пор, пока не будет достигнут конец или пока растущее трение не заставит скорость == 0

Моя проблема на последнем этапе. Значения velocity обычно находятся в диапазоне 2000-3000 пикселей. Скорость в пикселях в секунду, так что этого следовало ожидать. Я беру секундомер (который должен все еще работать), останавливаю его и нахожу время, прошедшее с момента последнего движения мышью, умножаю velocity на Stopwatch.TotalSeconds, получаю это расстояние, затем сбрасываю и запускаю секундомер, затем возвращаюсь назад и начинаю все снова.

Ожидаемый результат состоит в том, что истекшее время между обновлениями, умноженное на скорость, должно дать мне количество пикселей (в соответствии с последним движением мыши), которое я должен прокрутить. Мой фактический результат заключается в том, что иногда панель летит, а иногда она движется медвежьим! постепенное замедление в порядке, это просто начальная скорость, которая выключена

Есть ли изъян в логике? Должен ли я делать что-то еще?

Спасибо за любую помощь!

1 Ответ

1 голос
/ 26 марта 2011

Мне кажется, что здесь есть три возможных источника неточности. Во-первых, как "А.Р." сказал, что у вас будут проблемы, если детализация вашего таймера не достаточно хороша. Вы проверили IsHighResolution и Frequency, чтобы был уверен все в порядке?

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

В-третьих, физическое движение пальца (или стилуса, мыши или чего-то еще, что вы делаете, фактически вводит; я собираюсь угадать палец), возможно, не так хорошо себя ведет. В конце жеста он может измениться от горизонтального к вертикальному.

Все эти проблемы были бы существенно смягчены путем использования более длинного периода выборки и возможно (попробуйте оба варианта), игнорируя самую последнюю выборку или две. Итак, держите небольшой круговой буфер недавних сэмплов, и когда вы наведете курсор мыши, посмотрите назад (скажем) на 100 мс или около того и используйте его, чтобы определить свою скорость. Или, если вы не хотите хранить такую ​​большую историю, используйте простой БИХ-фильтр: каждый раз, когда вы получаете образец, делайте что-то вроде

filtered_dt = filtered_dt + SMALL*(latest_dt-filtered_dt);
filtered_dx = filtered_dx + SMALL*(latest_dx-filtered_dx);
filtered_dy = filtered_dy + SMALL*(latest_dy-filtered_dy);

где МАЛЫЙ должен быть где-то около 0,2 или около того; затем используйте filtered_dx/filtered_dt и filtered_dy/filtered_dt в качестве оценки скорости. (Я думаю, что это лучше, чем вычислять скорость каждый раз и фильтровать ее, потому что, например, последняя все равно взорвется, если вы когда-нибудь получите невероятно малый dt. Если сомневаетесь, попробуйте оба способа.)

Если вы используете подход IIR, вы все равно можете заставить его игнорировать самый последний образец, если он окажется ненадежным; если вы помните последние dt, dx и dy, вы можете сделать это, отменив последнее обновление: используйте (filtered_dt-SMALL*latest_dt)/(1-SMALL) и т. д.

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

...