Android studio — Анимация Android


Содержание

Пишем игру для Android. Часть 4 — Спрайтовая анимация

На прошлых уроках мы говорили о работе с графикой. Мы вывели на экран изображение робота и заставили его двигаться. Однако пока наша поделка выглядит довольно тускло. Чтобы вдохнуть в наш объект жизнь, необходимо добавить анимацию, заставить поднимать ноги и дрыгать ручками в процессе перемещения по экрану.

Давайте на какое-то время отвлечемся от игры и поговорим об анимации вообще. Представим, что нам требуется нарисовать человечка, который шагает слева направо по экрану. Как это можно реализовать? Обычно новичкам эта задача кажется непомерно трудной. На самом деле здесь нет ничего сложного. Идея взята из кинематографа. У нас должен быть набор изображений, представляющий собой «фотографии» нашего человечка в разные, достаточно близкие, моменты времени. Быстро меняя кадры, мы увидим, что наша картинка начала двигаться. Ситуацию с походкой упрощает тот факт, что она носит периодический характер. Грубо говоря, чтобы получить красивую и достоверную анимацию нам достаточно иметь кадры с момента, когда человечек опирается, скажем, на левую ногу, до момента, когда он сделав два шага вновь на нее обопрется.

Давайте рассмотрим пример, состоящий из нескольких кадров. Не будем заморачиваться на графике и возьмем готовый рисунок из некогда популярной компьютерной игры Monkey Island.

В компьютерной графике и gamedev-е широко используется понятиеспрайт(sprite). В современной трактовке оно означает графический объект, который может перемешаться по экрану и при этом изменять свой вид. Со спрайтом связан рисунок, содержащий раскадровку и, в зависимости от ситуации, спрайт имеет вид того или иного кадра. Ниже приведет пример рисунка с последовательностью кадров, который будет использоваться нами для создания спрайта.

Это изображение имеет ширину в 150 точек, и содержит 5 кадров, то есть ширина каждого кадра составляет 30 пикселей.

Чтобы создать анимацию мы можем загрузить каждый кадр, как отдельную картинку и затем через равные интервалы времени выводить их последовательно на экран. Можно сделать по-другому: загрузить одну картинку, содержащую все кадры, а затем налету разбивать ее на кадры и выводить требуемый в данный момент кадр. На самом деле это довольно просто. Мы знаем, что наша картинка содержит 5 кадров шириной 30 пикселей. Определим прямоугольник, имеющий ширину кадра (30 точек) и высоту всего изображения. На приведенном ниже рисунке синими прямоугольниками отмечены первые два кадра.

Давайте продолжим разработку нашей игры. Создадим проект. За основу возьмем разработанный на предыдущих уроках пример Droid_03. Добавим в папку res/drawable-mdpi проекта файлwalk_elaine.png Создадим новый класс для нашего персонажа. Поскольку в Monkey Island персонаж зовут Elaine, назовем класс ElaineAnimated.

Здесь bitmap — png рисунок, содержащий все кадры; sourceRect — прямоугольная область, которая «очерчивает» в рисунке границы текущего кадра; frameTicker — переменная, содержащая время, которое прошло с момента последной смены кадра анимации. Указанная в комментарии переменная fps обозначает не fps игры, а fps спрайта, то есть сколько раз изменяется кадр спрайта за секунду. Для плавной анимации это значение должно иметь величину порядка 25-30, однако для наших учебных целей подойдет и более скромное число 5. Мы не можем поставить здесь большее значение, поскольку у нас всего 5 кадров в рисунке. framePeriod — период между сменой кадра в миллисекундах. Для нашего случая, когда мы хотим менять 5 кадров в секунду эта величина равна 200 мс.

Подразумевается, что кадры имеют одинаковую ширину, поэтому spriteWidth вычисляется, как общая ширина рисунков поделенная на число кадров. В конструктор передается параметр fps, который обозначает число кадров спрайта в секунду.

Добавим в конструктор класса MainGamePanel строку, создающую объект для нашего нового анимированного персонажа

Добавим в класс метод update, который будет изменять текущий кадр в зависимости от текущего времени. Мы специально не привязываемся к частоте обновления игрового цикла, чтобы не нарушать процессор лишней работой. Например, допустим, что наша программа запущена на очень продвинутом телефоне, который обеспечивает проход итерации игрового цикла за 20 мс, допустим также, что менять картинку спрайта нужно раз в 200 мс, таким образом, мы должны обновлять спрайт каждый десятый шаг игрового цикла.

Этот метод получает в качестве параметра текущее время и если это время превышает сумму времени последнего обновления (frameTicker) и длительности показа кадра (framePeriod), то необходимо перейти к показу следующего кадра. Для этого увеличиваем на единицу значение переменная currentFrame, а затем на основании ее значения вычисляем заново границы кадра (sourceRect.left и sourceRect.right).

Внесем изменение в метод update класса MainGamePanel

Теперь у нашего спрайта меняются кадры, но мы не видим этого. Добавим в класс ElaineAnimated метод draw, который будет выводить на экран текущий кадр

Команда canvas.drawBitmap рисует прямоугольную область sourceRect из рисунка bitmap в прямоугольной области destRect.

Изменим также метод onDraw, добавив туда вызов метода перерисовки спрайта

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

Анимация

Cell-анимация

Cell animation представляет собой технику анимации, при которой ряд изображений или кадров последовательно сменяют друг друга за короткий промежуток времени. Подобная техника довольно распространена при создании мультфильмов. Например, имеется следующий набор изображений:

При достаточно быстрой смене кадров получится динамический эффект зайца, забрасывающего мяч в баскетбольную корзину. Теперь рассмотрим, как сделать подобную анимацию в приложении Android.

Во-первых, нам надо добавить все эти изображения в проект в папку res/drawable. И в эту же папку добавим новый xml-файл. Назовем его rabit_animation.xml и поместим в него следующее содержимое:

Анимация определяется с помощью корневого элемента animation-list , который содержит набор ключевых кадров в виде элементов item.

Свойство andro в определении корневого элемента указывает, что анимация будут продолжатся циклически. А при значении true анимация срабатывала только один раз.

Каждый элемент аннимации устанавливает ссылку на ресурс изображения с помощью свойства android:drawable , а также с помощью свойства android:duration устанавливает время в миллисекундах, которое будет отображаться изображение.

В разметке интерфейса для отображения анимации используется элемент ImageView:

Для установки ресурса анимации применяется свойство android:src , и также для растягивания по ширине контейнера с сохранением аспектного онтошения между шириной и высотой используется свойство andro

Больше для запуска анимации ничего не надо. И при запуске приложения анимация будет автоматически запускаться.

Также можно установить анимацию в коде java:

Анимация на Android

Создадим полноэкранное приложение, как показано в уроке:
Создание полноэкранного приложения в Android Studio

Наше приложение будет работать по следующему принципу:
На каждом шаге прорисовки (onDraw(Canvas)) получаем переменную curTime, которая будет хранить текущее время. В зависимости от ее значения, объекты, которые мы рисуем, меняют свои положение и свойства. Под конец метода прорисовки вызываем invalidate(), который заставляет MyView вызвать функцию прорисовки заново.

MyView:

Приложение выглядит следующим образом:

Обратите внимание, что размер и положение графических объектов зависят только от ширины (mWidth) и высоты (mHeight) экрана. Таким образом наше приложение будет корректно отображаться на всех Android устройствах.


Векторная анимация Andro > Задать вопрос

Привет. Подскажите годную статью какую-нибудь, касающуюся векторной анимации (желательно с примерами). Полистал форумы, почитал, но пока не особо догнал. Делал приложение, нужно было сделать 2 цикличные анимации, но с возможностью изменения скорости этой самой анимации. Нарезал растровых картинок, одна картинка — один кадр, соответственно. Реализовал таким образом, что совсем неудобно, да и плохо для приложения и последующей работы с этой анимацией

Сейчас сделан один векторный рисунок, состоящий из нескольких секций. Эти самые секции должны заливаться по очереди в разные цвета. Вот собственно и вся анимация. Ну и вопрос: как я могу сделать эту анимацию, определить для какого фрейма какую секцию залить и как я могу управлять скоростью анимации? В принципе, я понимаю, что это все можно сделать в xml, но из кода я должен ускорять или замедлять эту анимацию. Какие способы реализации есть, ребят? Спасибо.

zigins >Заметки Android

Пример создания бесконечной, случайной анимации с помощью TimeAnimator

Введение

Цель: используя TimeAnimator, создать анимацию конечного числа объектов, которые, уходя за экран, переиспользовались бы снова (повышение производительности). Расположение объектов случайное. С помощью анимаций перемещения, вращения, изменения масштаба и прозрачности, создать эффект глубины.

Другими словами, мы хотим создать анимацию, которая была бы бесконечной, но не циклической. Объекты должны переиспользоваться, но при каждой инициализации их расположение должно задаваться случайным образом.

Почему ТimeAnimator? Для анимаций, у которых известно начальное и конечное состояние, удобно использовать ValueAnimator. Это также справедливо, когда наша анимация бесконечно циклически повторяется. Но если у нас бесконечная анимация, которая в той или иной степени рандомная (или чем-либо детерминируема), то ValueAnimator нам не подойдет. В этом случае прекрасно подходит TimeAnimator, который предоставляет слушатель, куда на каждом шаге анимации передается общее время анимации и время, которое прошло с последнего шага анимации (все в миллисекундах).

Итак, перед началом наглядные примеры ValueAnimator и TimeAnimator, которые дает Патрик в своей статье:

Начнем

Анимацию будем делать в кастомном View, который первым делом и создаем:

В качестве объектов для анимирования возьмем такие:

Создадим их 32 штуки, будем вращать, изменять прозрачность и размер. Объекты будут появляться у нижнего края экрана и уходить за верхний, после чего переиспользоваться. Начальное положение по оси Х, размер будем задавать случайно. Для создания эффекта глубины скорость перемещения и прозрачность объектов будет зависить от их размера.

Внутри нашего кастомного View создаем класс который полностью описывает объект анимации на каждом шаге:

Так как экраны android-устройств могут иметь различные размеры, то зададим базовый размер наших объектов для анимации, базовую скорость, а заодно и прототип объекта, которой должен иметь тип Drawable:

При создадии или переиспользовании обекта для анимации мы должны его инициализировать. Добавляем эту фунцию в нашу кастомную View.. Но для этого нам понадобятся некоторые константы и класс для рандомизации:

Наконец, сама функция инициализации объекта для анимации:

Цукерберг рекомендует:  Бесконечная галерея Сайт кгыуддукюсщь

Итак, где нам лучше инициализировать все объекты для анимации. Очевидно, что это лучше сделать в функции onSizeChanged(…) нашего View. Таким образом объеткы будут инициализированы при создании View и при каждом изменении ее размера:

Теперь в функциях onAttachedToWindow() и onDetachedFromWindow() мы должны инициализировать, запустить и завершить работу TimeAnimator, соответственно. Приступим:

В функции updateState(float deltaMs), которая вызывается на каждом шаге анимации, происходит две вещи. Во-первых, мы перемещаем анимированный объект на требуемое расстояние, ориентируясь на время, прошедшее с момента предыдущего шага анимации. И таким образом, анимация будет подстраиваться под производительность системы. И, во-вторых, мы проверяем не ушел ли наш объект за пределы представления. Если ушел, то мы не уничтожаем его и создаем новый (это было бы не рационально), но переиспользуем, задавая новые значения, которые определяют его положение. Таким образом, достигается бесконечность и рандомность и не страдает производительность.

Производительность можно повысить учтывая версии систем и, например, на более ранних версиях уменшать количество анимируемых объектов.

Но, теперь нам нужно отобразить анимируемые объекты на нашем View, задавая необходимую прозрачность и размер. Кроме того, мы говорили, что объекты должны вращаться вокруг своей оси. Реализуем это все в функции рисования элементов View onDraw(…):

Кроме того добавим функции Pause() и Resume(), для остановки анимации и ее восстановления, если такое будет необходимо:

Все, наш кастомный view почти готов, осталось добавить конструкторы. Вот полный листинг нашего View:

Наконец, используемый в примере layout:

Бонус

  • Чтобы не было скучно, давайте добавим проигрывание музыки при запуске приложения. Для этого надо создать в ресурсах папку raw и поместить туда аудио-файл. В Activity прописать (как видно выше)
  • Давайте добавим больше независимости кастомному View от Activity. Сделаем так, чтобы View сам следил за жизненным циклом Activity или Fragment в котором используется и реагировал бы на события onPause() и onResume(). Для этого воспользуемся возможностями Android Architecture Components:

Теперь наша Activity наследуется от LifecycleActivity. И в прописании функций onPause() и onResume() отпадает необходимость:

При этом наша кастомная View реализует интерфейс LifecycleObserver. И перед функциями pause() и resume() появляются следующие аннотации:


Android studio — Анимация Android

В этой статье рассмотрим как сделать анимацию элементов интерфейса в android. Под элементами интерфейса в данном случае имеются в виду все наследники класса View (полный список наследников можно посмотреть в документации класса View). Анимация это простой способ сделать приложение более живеньким :)

1. Начнем с создания тестового полигона. Сделаем простое приложение с кнопкой и картинкой посередине экрана. Код приводить не буду, он простой, если что, смотрите в исходниках (они в конце статьи).

2. В директории /res/anim создадим файл anim.xml и напишем туда

Это описание анимации, которое мы будем применять к нашей картинке. Подробнее что тут происходит рассмотрим ниже, а пока просто скопируем это в файл.

3. Чтобы загрузить анимацию из xml файла используется статический метод класса AnimationUtils
loadAnimation(Context context, int id), где context — текущий контекст, а id — идентификатор ресурса с анимацией. Метод возвращает экземпляр класса Animation.
Animation — абстрактный класса для представления анимации в приложении.
Чтобы применить ее, полученный экземпляр класса Animation передается методу
startAnimation(Animation animation) класса View (и всех его наследников).

4. Напишем в файл AnimationTestActivity.java:

1) Читаем файл с идентификатором R.anim.anim (что соответствует файлу /res/anim/anim.xml) и получаем экземпляр класса Animation.
2) По нажатию на кнопку применяем анимацию для изображения.

5. Можно запустить наше приложение. По нажатию на кнопку, картинка исчезнет, а потом медленно начнет прорисовываться обратно.

6. Теперь рассмотрим подробно как же создается анимация в xml файле.
Существует 4 вида анимации:

  • alpha (прозрачность, видимость)
  • scale (масштабирование)
  • rotate (поворот)
  • translate (перемещение)

Для создания анимации мы должны описать начальное и конечное состояние объекта, а система сама решит как перейти из одного состояния в другое. В нашем примере

мы описываем анимацию alpha, то есть изменяем видимость объекта. Задаем начальное состояние fromAlpha=»0.0″ (полностью невидимое) и конечное toAlpha=»1.0″ (полностью видимое). Указываем продолжительность анимации duration=»1000″ (в миллисекундах). А все остальное, то есть как нужно изменять видимость объекта чтобы за секунду сделать его из невидимого в видимое, система делает сама. Рассчитывается это с помощью интерполяции — в вычислительной математике способ нахождения промежуточных значений величины по имеющемуся дискретному набору значений. Для каждой анимации можно задать интерполятор
-AccelerateDecelerateInterpolator (@android:anim/accelerate_decelerate_int erpolator) — скорость изменения в начале и конце низкая, а в середине ускоряется

-AccelerateInterpolator (@android:anim/accelerate_interpolator) — скорость изменения в начале низкая, а затем ускоряется

-AnticipateInterpolator (@android:anim/anticipate_interpolator) — изменения начинаются в обратную сторону, а затем резко двигаются вперед

-AnticipateOvershootInterpolator (@android:anim/anticipate_overshoot_inte rpolator) — изменения начинаются в обратную сторону, затем резко двигаются вперед и пролетают выше конечного значения, а затем возвращаются до конечного значения

-BounceInterpolator (@android:anim/bounce_interpolator) — скорость изменения увеличивается в конце

-CycleInterpolator (@android:anim/cycle_interpolator) — повторение анимации указанное число раз. Скорость изменения следует синусоиде

-DecelerateInterpolator (@android:anim/decelerate_interpolator) — скорость изменения уменьшается в конце

-LinearInterpolator (@android:anim/linear_interpolator) — скорость изменения постоянна

-OvershootInterpolator (@android:anim/overshoot_interpolator) — изменения резко двигаются вперед и пролетают выше конечного значения, а затем возвращаются до конечного значения

Задается интерполятор с помощью атрибута android:interpolator. Например
andro >e_interpolator». По умолчанию используется LinearInterpolator.

7. Описание начальных и конечных состояний
1) alpha (прозрачность, видимость)
— android:fromAlpha — начальное значение прозрачности. 0.0 — полностью прозрачное (невидимое), 1.0 — полностью непрозрачное (видимое)
— android:toAlpha — конечное значение прозрачности

2) scale (масштабирование)
— android:fromXScale — начальное значение масштаба по оси X (где текущий размер соответствует значению 1.0)
— android:toXScale — конечное значение масштаба по оси X
— android:fromYScale — начальное значение масштаба по оси Y (где текущий размер соответствует значению 1.0)
— android:toYScale — конечное значение масштаба по оси Y
— android:pivotX — х координата точки, которая останется неизменна после масштабирования
— android:pivotY — y координата точки, которая останется неизменна после масштабирования

Возможные значение pivotX и pivotY:
в пикселях относительно левого (или верхнего для координаты Y) края элемента (например «5»)
в процентах относительно левого (верхнего) края (например «5%»)
в процентах относительно левого (верхнего) края родительского элемента (например «5%p»)

Например, если pivotX=0, pivotY=0 (что соответствует верхнему левому углу элемента), то масштабирование будет изменять размер элемента вниз и вправо. Если pivotX=50%, pivotY=50%, то точка находится по центру элемента и размер изменяется во все сторону, при этом центр будет оставаться а в одной точке.

3) rotate (поворот)
— android:fromDegrees — Начальное значение угла поворота (в градусах, возможно отрицательное значение)
— android:toDegrees — конечное значение угла поворота
— android:pivotX — x координаты центра поворота.
— android:pivotY — y координата центра поворота.
Возможные значения pivotX и pivotY как у анимации scale

4) translate (перемещение)
— android:fromXDelta — x координата начальной точки перемещения. Возможные значения:
в пикселях относительно изначальной позиции (например «5»)
в процентах относительно ширины элемента (например «5%»)
в процентах относительно ширины родительского элемента (например «5%p»)
— android:toXDelta — x координата конечной точки перемещения
— android:fromYDelta — y координата начальной точки перемещения
— android:toYDelta — y координата конечной точки перемещения

8. Дополнительные параметры
Также есть атрибуты общие для всех четырех типов анимации, наиболее полезные из них:
— android:duration — длительность анимации (в миллисекундах)
— android:interpolator — определяет интерполятор для анимации
— android:repeatCount — кол-во дополнительных повторений анимации. Именно дополнительных, то есть один раз анимация выполнится по любому. Значением по умолчанию является «0» — это значит анимация выполнится только один раз. Значение «1» значит, что анимация выполнится два раза (один раз основной и один раз дополнительный). Значение «-1» или «infinite» — бесконечный повтор.
— android:repeatMode — определяет поведение анимации, когда она дошла до конца, а параметр repeatCount не равен 0. Есть два значения «restart» — анимация начинается заново и «reverse» — анимация пойдет в обратном порядке.
— android:startOffset — задержка перед началом анимации (в миллисекундах)

9. Объединение нескольких анимаций
К элементу можно применить одновременно несколько типов анимаций. Например если мы напишем:

Картинка за 1 секунду изменит прозрачность (с полностью прозрачной до непрозрачной) и при этом повернется на 360 градусов.

Анимациям можно выставлять разную длительность, например поставим duration=5000 у анимации rotate. Теперь картинка будет поворачиваться гораздо медленнее, а прозрачность меняется все-также за секунду.

С помощью startOffset, можно сделать анимации последовательными. Добавим к rotate атрибут startOffset=»1000″ (то есть сделаем задержку равную длительности первой анимации). Теперь картинка вначале за 1 секунду станет видимой, а затем только повернется на 360 градусов.

Несколько анимаций можно объединять в наборы тегом . Один такой тег будет в файле всегда и является корневым. Для набора можно задавать следующие атрибуты:
duration (длительность), repeatMode (режим повторения) — эти атрибуты будут применяться для каждой анимации в наборе
interpolator — определяет интерполятор анимации и shareInterpolator — будет ли этот интерполятор применятся для каждой анимации в наборе (возможные значения «true» и «false»)
startOffset (задержка) — задержка для всего набора анимаций.
К сожалению, к набору нельзя применить атрибут repeatCount, то есть повторить несколько раз набор анимаций не получится.
Наборы могут быть любой вложенности.

10. Создание анимации без xml
Анимацию можно создать и без использования xml, непосредственно в коде программы. Для этого используются классы наследники Animation:
1) AlphaAnimation для создания анимации alpha. Конструктор класса имеет вид
AlphaAnimation(float fromAlpha, float toAlpha) где fromAlpha и toAlpha соответственно начальное и конечное значение прозрачности (от 0.0 до 1.0)

2) RotateAnimation для создания анимации rotate. Имеет три конструктора:
RotateAnimation (float fromDegrees, float toDegrees)
где fromDegrees и toDegrees — начальный и конечный угол поворота. Центр поворота находится в точке (0,0)
RotateAnimation (float fromDegrees, float toDegrees, float pivotX, float pivotY)
pivotX и pivotY — координаты центра поворота в пикселях относительно левой и верхней границы элемента.
RotateAnimation (float fromDegrees, float toDegrees, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue)
pivotXType и pivotYType формат в котором указывается значение. Задается константой Animation.ABSOLUTE (абсолютное значение относительно левой или верхней границы в пикселях), Animation.RELATIVE_TO_SELF (значение в процентах относительно размеров элемента, причем значение 1.0 соответствует 100%) или Animation.RELATIVE_TO_PARENT (значение в процентах относительно размеров родительского элемента, причем значение 1.0 соответствует 100%).
pivotXValue и pivotYValue — значение для координаты центра поворота (с учетом формата)


3) ScaleAnimation для создания анимации scale. Также имеет три конструктора
ScaleAnimation(float fromX, float toX, float fromY, float toY)
ScaleAnimation(float fromX, float toX, float fromY, float toY, float pivotX, float pivotY)
ScaleAnimation(float fromX, float toX, float fromY, float toY, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue)

Параметры fromX, toX, fromY, toY — аналогичны атрибутам для создания анимации в xml. Параметры pivotX, pivotY, pivotXType, pivotXValue, pivotYType, pivotYValue — аналогичны параметра для анимации rotate.

4) TranslateAnimation для создания анимации translate. Имеет два конструктора
TranslateAnimation(float fromXDelta, float toXDelta, float fromYDelta, float toYDelta)
TranslateAnimation(int fromXType, float fromXValue, int toXType, float toXValue, int fromYType, float fromYValue, int toYType, float toYValue)
Значения параметров должны быть понятны

5) и последний класс AnimationSet для объединения анимаций. Его конструктор
AnimationSet(boolean shareInterpolator)
shareInterpolator — определяет должны ли анимации входящие в набор использовать общий (заданный для набора) интерполятор или каждая анимация определяет свой. Значение «true» в первом случае и «false» во втором.

У каждого класса есть методы для определения дополнительные параметров анимации, например:
setDuration(long durationMillis) — установление длительности
setInterpolator(Context context, int resID) — установление интерполятора
setRepeatCount(int repeatCount) — установление кол-ва повторов
setRepeatMode(int repeatMode) — установление режима повтора
setStartOffset(long startOffset) — установление задержки начала анимации
Все методы можно посмотреть на странице документации

Цукерберг рекомендует:  Таблица с ценами на CSS3

11. Создадим в коде анимацию, которая по нажатию на кнопку будет поворачивать картинку на случайный угол (от 0 до 360) и увеличивать до случайного размера (не более чем в два раза). Я для этого добавила еще одну кнопку randomButton

1) Создаем объект Random, для генерации случайных чисел. Про Random подробнее можно прочитать в документации, сейчас нас интересуют методы int nextInt(int n) — генерирующий целое число в диапозоне от 0 до n. И метод float nextFloat() — генерирующий вещественное число от 0 до 1.
2) Создаем анимацию вращения. Начальный угол = 0, конечный угол = случайному числу от 0 до 360. Animation.RELATIVE_TO_SELF означает, что точку центра поворота мы будем указывать в процентах относительно ширины элемента. Не забываем, что значение 1.0 соотвествует 100%, а значит 0.5f — это 50%. Значит точка центра поврота будет посередине картинки.
3) Задаем длительность анимации 1000 миллисекунд (это 1 секунда)
4) Определяем режим повторения как Animation.REVERSE, то есть при повторении анимация пойдем в обратном порядке.
5) Задаем кол-во дополнительных повторений = 1. Значит всего анимация повторится два раза, один раз в прямом порядке и один в обратном.
6) Метод long computeDurationHint() расчитывает сколько суммарно будет продолжаться анимация. Есть метод getDuration(), но он просто возвращает значение длительности, которое мы задали методом setDuration(). В нашем случае мы задали значение длительности 1000 и метод getDuration() вернет 1000 и не учтет, что анимация будет повторяться два раза, а значит в действительности будет продолжаться 2000 миллисекунд. Метод computeDurationHint() рассчитает длительность с учетом повторов и задержек.
7) Расчитываем новый размер картинки. Значение 1.0 это текущий масштаб картинки, значит значение 2.0 — увеличение картинки в два раза. Мы генерируем число от 0.0 до 1.0 и приплюсовываем 1, значит получаем число от 1.0 до 2.0
8) Создаем анимацию масштабирования от текущего размера картинки до случайно сгенерированного число от 1.0 до 2.0
9) Задаем задержку равную суммарной длительности анимации вращения. Чтобы вторая анимация начиналась сразу после окончания первой
10) Создаем набор анимаций.
11) Добавляем две созданные анимации в набор
12) Применяем набор анимаций к картинке

12. Еще один интересный метод класса Animation
setAnimationListener (Animation.AnimationListener listener) — устанавливает слушателя изменений состояний анимации. Интерфейс Animation.AnimationListener определяет следующие методы:
onAnimationStart (Animation animation) — вызывается при старте анимации
onAnimationRestart (Animation animation) — вызывается при повторе анимации
onAnimationEnd (Animation animation) — вызывается по окончании анимации

Ничего полезного мы при изменении состояния анимации не делаем, просто пишем это в лог.

На этом все. Основное я рассказала, остальное лучше изучать экспериментами :)

Animator — инструмент для создания анимаций на Andro />

Что такое Animator?

Статья была впервые опубликована здесь.

Немного истории. С момента запуска платформы Android существовал фреймворк View Animation. Предназначался он, как следует из названия, для анимаций. Но производительность устройств в конце нулевых была настолько низкой, что о красивых анимациях никто особо не думал, поэтому фреймворк не был удобным и гибким. Он имел только четыре типа анимации (TranslateAnimation, AlphaAnimation, ScaleAnimation, RotateAnimation), класс, позволяющий их комбинировать (AnimationSet), а также способность работать только с классами, унаследованными от View.

В Android 3.0 появился куда более гибкий фреймворк Property Animation. Он умеет изменять любое доступное свойство, а также может работать с любыми классами. Его основным инструментом является Animator.

Animator — это тип классов, предназначенных для изменения значений выбранного объекта относительно времени. Грубо говоря, это инструмент для управления потоком заданной длительности, который изменяет определённое свойство от начального значения к конечному. Таким плавно меняющимся свойством в анимации может быть, например, прозрачность.

Классы, унаследованные от Animator

ValueAnimator (наследуется от Animator)

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

Посмотрите на изменение alpha с его помощью:

ObjectAnimator, наследуется от ValueAnimator

Это класс, призванный упростить работу с ValueAnimator. С ним вам не нужно вручную изменять какое-либо значение по событию изменения — вы просто даёте Animator’у объект и указываете поле, которое вы хотите изменить, например scaleX. С помощью Java Refliction ищется setter для этого поля (в данном случае — setScaleX. Далее Animator самостоятельно будет менять значение этого поля.

С помощью ObjectAnimator изменение alpha будет выглядеть так:

У класса View есть несколько свойств специально предназначенных для анимирования с помощью Animator:

  • прозрачность (View. ALPHA )
  • масштаб (View.SCALE_X, View.SCALE_Y)
  • вращение (View. ROTATION , View.ROTATION_X, View.ROTATION_Y)
  • положение (View.X, View.Y, View.Z)
  • положение отображаемой части (View.TRANSLATION_X, View.TRANSLATION_Y, View.TRANSLATION_Z)

AnimatorSet (наследуется от Animator)

Это класс, позволяющий комбинировать анимации различными способами: запускать одновременно или последовательно, добавлять задержки и т.д.

Это отдельный класс. Он не наследуется от Animator, но обладает той же логикой, что и ObjectAnimator для View, и предназначен для лёгкого анимирования какой-либо View без лишних заморочек.

Вот так с его помощью можно изменить alpha:

Как мы начали использовать Animator

Около года назад передо мной встала задача сделать анимацию при клике на элемент. Вот такую:

Не то чтобы я не делал анимаций прежде, но на аутсорсе они редко нужны. Поэтому я загуглил Animation Android. Первые пять ссылок довольно подробно описывали, как делаются анимации, и я приступил. Вот первый результат:

Урок 6. Установка пользовательских анимаций в Material Design

Содержание этого урока


См. также

Благодаря анимациям в Material Design пользователи получают отклик на выполняемые действия. Кроме того, анимации обеспечивают зрительную связь при взаимодействии с приложением. Тема Material Design содержит ряд анимаций по умолчанию для кнопок и переходов, а в Android 5.0 (уровень API 21) и более поздних версиях можно настраивать эти анимации и создавать новые:

  • реакция на касание;
  • круговое появление;
  • переходы;
  • перемещение по кривой;
  • изменение состояний представления.

Настройка реакции на касание

Реакция на касание в Material Design обеспечивает моментальное визуальное подтверждение взаимодействия пользователя с элементами интерфейса в точке касания. В стандартной анимации для реакции на нажатие кнопок используется новый класс RippleDrawable , обеспечивающий переход между разными состояниями с созданием эффекта ряби.

В большинстве случаев эту возможность следует применять в XML-файле представления, указав фон представления следующим образом:

  • ?android:attr/selectableItemBackground для ограниченной области ряби;
  • ?android:attr/selectableItemBackgroundBorderless для ряби, распространяемой за границы представления. При отрисовке она будет ограничиваться ближайшим родительским элементом представления со значением фона, отличным от null.

Примечание. selectableItemBackgroundBorderless — это новый атрибут, представленный в уровне API 21.

Также можно определить RippleDrawable в качестве XML-ресурса с помощью элемента ripple .

Можно назначить цвет для объектов RippleDrawable . Чтобы изменить стандартный цвет отклика на касание, воспользуйтесь атрибутом темы android:colorControlHighlight .

Дополнительные сведения представлены в справке по API для класса RippleDrawable .

Применение эффекта появления

Анимация эффекта появления обеспечивает зрительную связь с действиями пользователя, когда отображается или скрывается группа элементов интерфейса. С помощью метода ViewAnimationUtils.createCircularReveal() можно анимировать ограничивающий круг, чтобы отобразить или скрыть с экрана представление.

Как отобразить ранее скрытое представление с помощью этого эффекта:

Как скрыть ранее отображавшееся представление с помощью этого эффекта:

Настройка переходов

Переходы в приложениях Material Design обеспечивают зрительные связи между различными состояниями путем движения элементов и преобразований между общими элементами. Можно выбрать настраиваемые анимации для начальных и конечных переходов, а также для переходов общих элементов между операциями.

  • Начальный переход определяет порядок появления на экране представлений в операции. Например, в начальном переходе explode представления появляются на экране извне и перемещаются к центру экрана.
  • Конечный переход определяет порядок исчезновения с экрана представлений в операции. Например, в конечном переходе explodeпредставления исчезают с экрана в направлении из центра к краям.
  • Переход общих элементов определяет порядок перехода между операциями представлений, используемых в обеих операциях. Например, если в двух операциях используется одно и то же изображение, но в разных позициях и с разными размерами, в случае применения перехода общего элемента changeImageTransform выполняется плавное перемещение и масштабирование изображения между этими операциями.

В Android 5.0 (уровень API 21) поддерживаются следующие начальные и конечные переходы:

  • explode — перемещение представлений в центр экрана или из центра;
  • slide — перемещение представлений к одному из краев экрана или от него;
  • fade — отображение или скрытие представления на экране путем изменения его прозрачности.

Любой переход, являющийся наследованием класса Visibility , поддерживается как начальный или конечный переход. Дополнительные сведения представлены в справке по API для класса Transition .

В Android 5.0 (уровень API 21) также поддерживаются следующие переходы общих элементов:

  • changeBounds — анимация изменений границ макетов целевых представлений;
  • changeClipBounds — анимация изменений границ обрезки целевых представлений;
  • changeTransform — анимация изменений параметров масштабирования и поворота целевых представлений;
  • changeImageTransform — анимация изменений размеров и параметров масштабирования целевых изображений.

Если активировать переходы в приложении, то между начальной и конечной операциями активируется стандартный переход методом плавной замены.

Рисунок 2. Переход с одним общим элементом.

Определение настраиваемых переходов

Сначала необходимо активировать переходы содержимого окна с помощью атрибута android:windowContentTransitions при определении стиля, наследуемого из темы Material Design. В определении стиля можно указать начальный и конечный переходы, а также переходы общих элементов:

Transitions API: делаем анимацию для Andro >

При всей важности и распространенности анимации в мобильной разработке программисты отмечают, что в Android-приложениях её создание всегда было непростой задачей.

В то время как iOS давно предоставляет удобные инструменты для анимирования интерфейсов, в Android решения, позволяющие оптимизировать труд разработчиков, появились относительно недавно. Однако с ними жизнь специалистов определенно заиграла новыми красками.

Инструменты, о которых мы расскажем сегодня, — это удобное решение для самых разных анимаций: вместо отдельных экранов программист анимирует так называемые сцены, а переходы между ними генерируются автоматически при помощи Transition API — и это лишь верхушка айсберга возможностей. И если вы еще не используете эту технологию на своих проектах — самое время попробовать!


Transitions API: как это работает?

Уже в Android 4.0 существовал ранний вариант решения проблемы с анимацией — флаг animateLayoutChange для ViewGroup. Однако этот инструмент был недостаточно гибким и не мог обеспечить разработчику полный контроль над переходами (Transitions). В Android 4.4 KitKat и выше были реализованы Transitions API. Поскольку Transitions API также есть в саппорт-библиотеке, теперь с их помощью можно упростить работу с анимацией практически на любом девайсе под Android.

Именно в KitKat Transition API появляется такое понятие как сцена — Scene, и Transition — переход между сценами. Для определения корневого layout вводится понятие Scene root, внутри которого и происходит изменение сцен. При этом сама сцена по сути является враппером над ViewGroup, описывающим своё состояние и состояние объектов View в нем.

Сам Transition — механизм, который позволяет считывать параметры View, изменяющиеся от сцены к сцене, и генерировать анимации для создания плавных переходов между ними.

Transition Framework предоставляeт следующие возможности для создания анимаций:

  • Group-level animations: возможность анимировать целые иерархии объектов View. Разработчик указывает ViewGroup, которую нужно санимировать, и анимации автоматически применяются к каждому её элементу;
  • Transition-based animation: анимации, основанные на переходах;
  • Built-in animations: простые встроенные анимации, которые генерируются автоматически, такие как растворение, затемнение, изменение размера, движение и т.д.;
  • Resource file support: поддержка файлов ресурсов, в которых может быть записано, что и как анимировать. Таким образом, необязательно прописывать все анимации в коде;
  • Lifecycle callbacks: предоставляет все необходимые методы контроля за воспроизведением анимации;
Цукерберг рекомендует:  Unity - Желающие сотворить клиент в UNITY

При всех своих достоинствах данный метод создания анимаций имеет и некоторые ограничения:

  • Может давать сбои, если применяется к наиболее сложным SurfaceView и TextureView, работающим не в UI потоке, что ведет к рассинхронизации анимации.
  • Плохо работают AdapterView, такими как ListView, когда в них необходимо анимировать отдельные элементы.
  • Периодически возникают проблемы с синхронизацией при попытке изменить размер TextView: шрифт может отобразиться в следующей сцене до того, как закончилось изменение остальных объектов.

Однако эти ограничения вряд ли можно назвать существенными: в практике ситуации, когда нужно применить анимацию, к примеру, к SurfaceView, встречаются крайне редко.

Рассмотрим примеры работы с Transition Frameworks

Создание сцены из ресурса:

Создание сцены из кода:

Сами Transitions также создаются на базе ресурса:

Или кода:

Есть возможность создавать целые сеты анимаций, например, одновременное движение, изменение размера и затемнение

В ресурсе:

В коде:

Еще одна возможность — применить анимацию не ко всей сцене, а к отдельному объекту View

Transition manager создается одной строчкой кода. Он существует для того, чтобы прописать все сцены и переходы в одном месте. Это позволяет существенно сократить объем работ и упростить дальнейший контроль над анимацией:

Как запускать сцены? Очень просто!

С кастомными Transitions:

C Transitions по умолчанию:

Или без Transitions:

Использовать переходы можно и отдельно, не создавая сцены

При помощи логичного и интуитивно понятного интерфейса TransitionListener вы можете контролировать каждый шаг любой анимации:

Помимо встроенных вы можете создавать и собственные анимации. Например, так можно изменить цвет фона View:

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

Почему это важно?

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

Расскажите нам о своем опыте создания анимации для Android: используете ли вы Transitions API? Какие есть плюсы и минусы у этого и других методов, с которыми вы работали?

Android studio — Анимация Android

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

Что вы узнаете


  • Как использовать Android Design Support Library.
  • Как применять material design к вашему приложению.
  • Следующие ключевые компоненты и принципы:
  • Темы и цвета для создания тактильных поверхностей и print-like design
  • Лучшие способы использования слоёв для упрощения понимания навигации в приложении
  • Анимация и ответ на касание для выражения meaningful motion.

Что вам потребуется

  • Android Studio версии 1.5+ и JDK 7+
  • Опыт разработки Android приложений
  • Устройство для теста на базе Android 4.1+*
  • Кабель USB micro to USB.

* Могут быть использованы устройства Android 2.3.3 (Gingerbread, API Level 10) или выше, однако, часть эффектов material design (например, круговая анимация) может не воспроизводиться на Android 4.4 (KitKat) и ранее.

Скачайте приложение-пример

Вы можете скачать весь код примера на ваш компьютер.

. или клонировать GitHub репозиторий из командной строки.

Репозиторий android-design-library содержит несколько проектов-примеров. Это руководство использует только два из них:

  • android-design-library/1-Base — начальный код, который вы будете модифицировать в процессе выполнения руководства.
  • android-design-library/app — завершённый пример выполняемого вами задания для проверки ошибок в случае возникновения трудностей.

Запустите приложение-пример

Во-первых давайте рассмотрим как выглядит завершённый вариант приложения. Следующие инструкции опишут как его открыть в Android Studio.

  1. Импортируйте android-design-library пакет.
  2. Для этого выберите корневую директорию android-design-library (Quickstart >Import Project. > android-design-library ). Дальнейшую работу мы будем вести в модуле Base-1.
  3. Кликните на кнопку Gradle sync.
  4. Включите режим отладки по USB на вашем Android устройстве.
  5. Подключите ваше Android устройство и кликните кнопку Run. Вы увидите домашний экран приложения через несколько секунд.

Часто задаваемые вопросы

Используемые принципы Material Design:

Давайте рассмотрим два ключевых нововведения: темы и цвета!

Благодаря темам можно выбирать подходящие к нашему приложению цвета. Разработчики могут выбирать между светлыми и тёмными темами (см. рис. 1 и 2).

Настройка цветов производится через атрибуты темы, которые автоматически используются всеми компонентами приложения, например colorPrimaryDark для Status Bar и colorPrimary для App Bar (см. рис. 3).

  1. Добавим светлую тему в наше приложение и настроим часть цветов в res/values/styles.xml

Приложение должно выглядеть следующим образом:

Используемые принципы Material Design:


  • Тактильные поверхности
  • Выделенные элементы
  • Meaningful Motion

В этом примере мы создадим общую структуру приложения, которую впоследствии заполним компонентами material design.

Добавим toolbar

Теперь вы готовы писать поверх стартового проекта (Base-1).

  1. Добавим toolbar и tabs в activity_main.xml and MainActivity.java
  2. Удалим TextView в activity_main.xml

Добавим tabs в toolbar

  1. В activity_main.xml удалим RelativeLayout и заменим на CoordinatorLayout.
  2. В activity_main.xml добавим Tablayout внутри AppBarLayout.
  3. В MainActivity.java создадим класс tabs и инициализируем меню

Приложение должно выглядеть следующим образом:

Добавим Fragment и ViewPager

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

  1. Создадим 3 фрагмента. ListContentFragment.java , TileContentFragment.java и CardContentFragment.java .
  2. В MainActivity.java создадим объект ViewPager и Adapter для прокручивания контента.
  3. В activity_main.xml добавим элемент ViewPager вне AppBarLayout .
  4. Создадим файлы, описывающие внешний вид каждого из фрагментов: item_list.xml , item_tile.xml и item_card.xml внутри res/layout/ . Обратите внимание на индивидуальные атрибуты, чтобы понять какие варианты настройки доступны.

Приложение должно выглядеть следующим образом:

Используемые принципы Material Design:

  • Тактильные поверхности
  • Карточки

RecyclerView – это контейнер для отображения больших массивов данных, который может пролистываться очень эффективно (с большой скоростью), удерживая в памяти ограниченное количество элементов списка. Наш набор данных для этого руководство состоит из пустых карточек, похожих на листки бумаги и служащих как короткая репрезентация информации. Для получения большего количества информации необходимо зайти»внутрь» карточки, кликнув на неё и вызвав открытие Detail View.

Давайте добавим RecyclerView в приложение:

  1. Добавим зависимости в build.gradle для использования CardView и RecyclerView.
  1. В каждом из созданных фрагментов создайте экземпляр RecyclerView.Adapter для настройки RecyclerView .
  1. В каждом фрагменте сконфигурируйте ViewHolder для адаптера. Замените R.layout.item_tile на view, который вы создадите для каждого фрагмента.
  1. Для каждого фрагмента обновите onCreateView(), чтобы использовать ContentAdapter .

    Специально для TileContentFragment уделим внимание настройке отступов и укажем в RecyclerView использование GridLayout — это сделает внешний вид более приятным на вид.


Если вы не справляетесь — взгляните на примеры TileContentFragment.java , ListContentFragment.java , и CardContentFragment.java . На этом шаге приложение должно выглядеть следующим образом:

    Чтобы завершить эффект, давайте стилизуем каждый view через модифицирование item_list.xml , item_tile.xml , чтобы добавить изображение.

Мы так же сделаем то же самое для item_card.xml , оборачивая наш RelativeLayout в CardView, чтобы получить тени и скруглённые углы, характерные для «карточек». (На Lollipop и более новых ОС, тени будут отображаться через нативное для Android свойство elevation . На старых устройствах support library симулирует эффект используя drawables).

Мы должны получить следующую картинку:

Используемые принципы Material Design:

  • Тактильные поверхности
  • Bold Elements

Добавим NavigationDrawer

Навигационная панель выдвигается слева. Это общий паттерн, характерный для приложений Google и соответствующий спецификации MD для листов.

  1. Создадим файл menu_navigation.xml , который будет определять элементы навигации в папке res/menu .
  1. Создадим файл navheader.xml определяющий содержание верхней части Navigation Drawer. Файл должен быть размещён в папке res/layout/ .
  1. В activity_main.xml :
  • Обернём все компоненты в DrawerLayout , который позволит вытягивать создаваемое меню из-за границ экрана.
  • Добавим NavigationView снаяружи от CoordinatorLayout .
  1. В MainActivity.java :
  • Добавим следующее поле начале файла MainActivity:
  • В метод onCreate внутри MainActivity.java добавим следующие строки для настройки желаемого меню.
  • Добавим mDrawerLayout.openDrawer(GravityCompat.START); в MainActivity.java добавим методы для открытия меню по касанию на кнопку «гамбургер» в меню.

Добавим Floating Action Button (FAB) и вызовем появление SnackBar

Парящая кнопка действия — поэтичный перевод FAB — используется для основного действия в вашем приложении и подчеркивает свою силу и важность паря над UI вашего аппа как единственная круглая кнопка. Создадим FAB, которая бы вызывала SnackBar, элемент, который обеспечивает легкий для восприятия ответ от интерфейса на операцию, проводимую пользователем.

Советы по дизайну:

  • Не каждый экран нуждается в FAB. FAB используется только для базового, действия в приложении.
  • Только одна кнопка floating action button может находиться на одном экране, для упрощения подчеркивания её важности.Она должна представлять только самое общее действие
  • Floating action button не обязательно должна быть размещена в нижнем правом углу экрана. Верхний левый, верхний правый угол, перекрытие Toolbar так же являются хорошим местом для её размещения.
  • FAB уменьшенного размера может использоваться в ситуациях, когда этого требует стиль остальных элемнтов на этом экране.
  1. В activity_main.xml добавим FloatingActionButton в конце CoordinatorLayout .
  2. В MainActivity.java , добавим слушатель на касание FAB, которое будет создавать SnackBar
  1. В папке values-2 , обновим styles.xml , чтобы сделать системную плашку прозрачной на Android 5 и выше.
  1. In CardContentFragment.java file add methods when buttons within card pressed shows snackbar.

Приложение должно выглядеть следующим образом:

Обратите внимание, что snack bar приподнимает floating action bar при анимации на экране. Это поведение обеспечивается CoordinatorView in activity_main.xml.

В качестве эксперимента попробуйте вынести FloatingActionButton за пределы CoordinatorView . (Для этого необходимо будет объявить дополнительный RelativeLayout .) Snack bar теперь будет игнорировать существование FAB при анимации собственного появления!

Поскольку анимация это неотъемлемая часть Material Design, удостоверяйтесь, что все view были помещены внутрь CoordinatorView , и делайте расширение CoordinatorLayout.Behavior если ваши views нуждаются в осуществлении некоторой анимации.

Используемые принципы Material Design:

  • Meaningful motion
  • Print-like design

Создадим Detail View

Используем Intent , чтобы позволить пользователям перемещаться между карточками и их полной репрезентацией. Создадим такой detail view в нашем приложении:

  1. Создадим DetailActivity.java и activity_detail.xml .
  2. Для каждого из элементов списка ListContentFragment.java , TileContentFragment.java , и CardContentFragment.java создадим новый Intent, чтобы каждый из элементов списка имел ссылку на подробный экран с развёрнутой информацией о контенте элемента.
  1. Не забудьте прописать ваш activity в AndroidManifest.xml .

Переход к Collapsing Toolbar

Collapsing Toolbar сворачивает toolbar, когда пользователь прокручивает экран вниз и разворачивает при прокручивании вверх. Давайте же двинемся вперёд к collapsing toolbar:

  1. В activity_detail.xml , добавим AppBarLayout и CollapsingToolbarLayout вместе с CoordinatorLayout.
  1. В DetailActivity.java установим заголовок для CollapsingToolbar.

Ура, дело сделано! Теперь вы готовы создавать приложения, основанные на принципах material design.

Если у вас будет свободная минутка, то мы будем очень рады получить отзывы на это занятие. Мы используем эту информацию для улучшения наших уроков и этого урока в частности..

ЖДЁМ ОБРАТНОЙ СВЯЗИ

Что мы прошли:

  • Темы и цвета для создания тактильных поверхностей и print-like design
  • Лучшие способы использования layout для упрощения понимания навигации в приложении
  • Анимации и ответ на касание для выражения значимых перемещений.

Следующие шаги

Теперь пришло время добавить material design в ваши собственные приложения.

Понравилась статья? Поделиться с друзьями:
Все языки программирования для начинающих