#java #android #анимация #animate
Здесь на русском StackOverflow я получил очень хороший совет и смог добавить анимацию фишек в буквенную игру для Android. Когда пользователь выбирает в меню "Вернуть буквы" и буква "A" должна прилететь в позицию внизу экрана, показанную красной стрелкой: Нынешний алгоритм работает так: Текущие координаты фишки: mRect.top и mRect.left Конечные координаты фишки: mTarget.x и mTarget.y Пока на нем есть движущиеся фишки, экран мобильного приложения рисуется заново (для этого снова и снова вызывается postInvalidate(30)). Когда нужно анимированно переместить фишку, я вызываю следующий метод, который делит предстоящий путь на 8 одинаковых шагов: public void startAnimatedMove(float x, float y) { mTarget.x = x; mTarget.y = y; steps = 8; mStepX = (mTarget.x - mRect.left) / steps; mStepY = (mTarget.y - mRect.top) / steps; } Каждый раз, по истечении 30 миллисекунд, вызывается метод, сдвигающий фишку в нужном направлении (причем последний шаг у меня особый - он помещает фишку точно на mTarget.x и mTarget.y - чтобы избежать ошибки округления): private void nextStep() { if (--steps == 0) moveTo(mTarget.x, mTarget.y); else moveTo(mRect.left + mStepX, mRect.top + mStepY); } Этот алгоритм работает хорошо (и дает возможность анимировать фишки прямо из главного thread-а приложения), но так как шаги mStepX и mStepY одинаковые, фишка движется неестественно. Вопрос: Как бы сделать шаги неодинаковыми? Они дожны быть большими в середине пути - и маленькими в начале и конце (см. зеленый график наверху справа). Тогда фишка будет медленно начинать и заканчивать движение - так называемый "easying in out". То есть нужна функция (с использованием x*x или Math.sin()?) для каждой оси, которая получала бы как input номер текушего шага, а выдавала как output дистанцию в пикселях вдоль оси икс или игрек: private void nextStep() { if (--steps == 0) moveTo(mTarget.x, mTarget.y); else moveTo(mRect.left + calcStepX(steps), mRect.top + calcStepY(steps)); } Обновление: Нашел интересный сайт про Easing Equations by Robert Penner, но пока не разобрался, как применить их к своему программному коду - особенно как рассчитать шаги, чтобы их сумма попала в точку назначения...
Ответы
Ответ 1
как расчитать шаги, чтобы их сумма попала в точку назначения Все формулы на упомянутом сайте опираются на 4 параметра: t, b, c, d: t – текущее время (или номер кадра), b – начальное значение, c – (конечное значение - начальное значение), d – общая длительность анимации. Чтобы за 8 кадров некий параметр, напр., Y, изменился от 162 до 288, вы в понравившуюся формулу, напр., в экспонениальный out return c * ( -Math.pow( 2, -10 * t/d ) + 1 ) + b; подставляете b,c вашей анимации, d=7, а t=просчитываемый кадр (0..7) и получаете на выходе значение вашего параметра для этого кадра.Ответ 2
Все гораздо проще. В android'е есть класс ValueAnimator Пользоваться примерно так: ValueAnimator va = ValueAnimator.ofInt(0, height); va.setDuration(300); va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { public void onAnimationUpdate(ValueAnimator animation) { Integer value = (Integer) animation.getAnimatedValue(); v.getLayoutParams().height = value.intValue(); v.requestLayout(); } }); Дефолтный интерполятор вычисляет значения именно так как вы хотите, т.е. начало и конец медленно, в середине быстрее. Вы естественно можете создать свой интерполятор. А если в интерполятор передать null, то будет линейно, как в вашем примере. ЗЫ Если надо анимировать два или больше независимых (т.е. когда dx через dy не посчитать) параметров можно воспользоваться AnimatorSet
Комментариев нет:
Отправить комментарий