Мы нашли те, которые мы используем в примере, где-то в сети, мы надеемся, что это не нарушит работу любого дизайнера:
Если у вас нет ничего лучше, получите эти изображения и используйте их.
Когда вы представляете падающий лист, представленный в цифровом контексте, вы можете заметить три вещи:
- лист падает
- лист вращается вокруг своей оси под некоторым углом
- лист делает кривое движение
Эти три свойства могут привести к тому, что лист упадет под действием ветра и сорвется с дерева. Одна вещь, которую мы пока не реализуем, — это преобразование кривизны, поскольку мы планируем создать отдельный учебник по нему, как расширение к этому.
Таким образом, нам нужно было бы создать перевод и ротацию, добавив немного логики здесь и там.
В смысле Android, как мы упоминали ранее, листья будут объектами ImageView. Они будут созданы случайным образом и добавлены в корневой макет непосредственно перед началом анимации. Так что нам понадобится таймер, который бы сбивал анимацию с одного листа. Допустим, мы хотим новый лист каждые 5 секунд. Поэтому нам понадобится таймер, который отправит пустое сообщение, обработанное объектом-обработчиком. Когда сообщение обработано (получено), мы получаем случайный лист из набора листьев (Drawables), создаем объект ImageView и помещаем чертеж в качестве его содержимого, а также добавляем изображение в корневой макет действия. Затем мы вызываем метод, который в нашем случае называется startAnimation, который принимает один объект ImageView в качестве параметра, который будет анимирован. Мы делаем это таким образом, чтобы оставить место в методе startAnimation, где будет создаваться, инициализироваться и запускаться ViewAnimator, а также его прослушиватель.
Пойдем снова, шаг за шагом. Давайте сначала создадим объект Handler:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { super .handleMessage(msg); int viewId = new Random().nextInt(LEAVES.length); Drawable d = getResources().getDrawable(LEAVES[viewId]); LayoutInflater inflate = LayoutInflater.from(FallAnimationActivity. this ); ImageView leafImageView = (ImageView) inflate.inflate(R.layout.ani_image_view, null ); leafImageView.setImageDrawable(d); mRootLayout.addView(leafImageView); LayoutParams animationLayout = (LayoutParams) leafImageView.getLayoutParams(); animationLayout.setMargins( 0 , ( int )(- 150 *mScale), 0 , 0 ); animationLayout.width = ( int ) ( 60 *mScale); animationLayout.height = ( int ) ( 60 *mScale); startAnimation(imageView); } }; |
Объект leafImageView надувается из XML, поэтому нам не нужно создавать его программно, mScale — это глобальное поле, содержащее плотность экрана (используется в нескольких других местах кода, поэтому объявлено глобально). После того, как мы добавим leafImageView в корневой макет, мы программно установим его верхнее поле равным 150dp в минус, только чтобы расположить его над видимой областью экрана. Мы создаем TimerTask следующим образом:
1
2
3
4
5
6
|
private class AnimTimerTask extends TimerTask { @Override public void run() { mHandler.sendEmptyMessage( 0x001 ); } } |
и TimerTask выполняется следующим образом, в нашем случае в методе onCreate Activity:
1
|
new Timer().schedule( new AnimTimerTask(), 0 , 5000 ); |
Это означает, что создавайте новый просмотр изображений каждые 5 секунд, добавляйте его в корневой макет и запускайте на нем анимацию.
Теперь вернемся к логике анимации. Как мы уже упоминали ранее, нам нужно перевести в нижнюю и боковую (x / y) и анимацию незначительного поворота. Оба стержня (x и y) являются центром оси, поэтому центр изображения листа.
Задержка перед запуском анимации снова рассчитывается случайным образом как значение от 0 до 6000 (миллисекунды). Аниматор будет с плавающей от 0 до 1.
Сейчас мы установили анимацию на 10 секунд (10000 мс). Это может быть немного быстрее, поэтому вы можете увеличить это значение по своему желанию.
В AnimatorUpdateListener происходит следующее: конечная позиция «x» конечного изображения будет рассчитываться как случайное значение от 0 (слева от экрана) и ширины дисплея (справа от экрана). Любая точка между ними будет конечной позицией ‘x’. Окончательной позицией «у» изображения листа будет высота экрана / дно плюс 150 точек на дюйм, чтобы изображение не останавливалось в видимой области. Мне нравится, чтобы он падал до некоторой точки высоты дисплея + 10dp, которая бы выглядела так, как будто лист упал на землю. На этот раз мы заставляем лист исчезнуть в пустоте экрана.
Итак, теперь у нас есть изображение, которое идет сверху вниз, где конечная позиция х случайна. Но нам не хватает еще 2 вещей (вращение + кривая анимации), из которых мы решили реализовать только еще одну, вращение. Давайте представим, что ветер не такой сильный, поэтому нам нужен дрожащий эффект для листа. Для этого достаточно угла от 50 до 100. Одно общее правило для реализации этого было бы этой практикой:
1
|
Min + ( int )(Math.random() * ((Max - Min) + 1 )) |
В нашем случае это будет:
1
|
50 + ( int )(Math.random() * 101 ) |
onAnimationUpdate вызывается до тех пор, пока не будет сделан каждый последний кадр. Вращение и перевод установлены здесь. Наконец мы начинаем аниматор. Вот весь метод:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
public void startAnimation( final ImageView leafImageView) { leafImageView.setPivotX(leafImageView.getWidth()/ 2 ); leafImageView.setPivotY(leafImageView.getHeight()/ 2 ); long delay = new Random().nextInt( 6000 ); final ValueAnimator animator = ValueAnimator.ofFloat( 0 , 1 ); animator.setDuration( 10000 ); animator.setInterpolator( new AccelerateInterpolator()); animator.setStartDelay(delay); animator.addUpdateListener( new ValueAnimator.AnimatorUpdateListener() { int movex = new Random().nextInt(mDisplaySize.right); int angle = 50 + ( int )(Math.random() * 101 ); @Override public void onAnimationUpdate(ValueAnimator animation) { float value = ((Float) (animation.getAnimatedValue())).floatValue(); leafImageView.setRotation(angle*value); leafImageView.setTranslationX((movex- 40 )*value); leafImageView.setTranslationY((mDisplaySize.bottom + ( 150 *mScale))*value); } }); animator.start(); } |
Когда мы запускаем это приложение, мы должны увидеть что-то вроде этого:
Мы используем эту анимацию для нашего последнего проекта, который находится в процессе полировки.
Кроме того, загрузите исходные коды и посмотрите, что мы что-то упустили или сделали ошибку, объясняя код.
Ссылка: Android: листоподобная анимация с использованием аниматоров свойств от нашего партнера по JCG Александра Балаловского в блоге 2Dwarfs .