Графика и анимация Android

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

Обзор

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

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

Платформы API пользовательского интерфейса в Android можно разделить на две категории: графику и анимацию.

Графики разделяются на различные подходы к выполнению трехмерной и трехмерной графики. Трехмерная графика доступна через ряд встроенных платформ, таких как OpenGL ES (мобильная версия OpenGL), и сторонние платформы, такие как MonoGame (кроссплатформенный набор средств, совместимый с набором средств XNA). Хотя трехмерные рисунки не находятся в область этой статьи, мы рассмотрим встроенные методы рисования 2D.

Android предоставляет два разных API для создания 2D-графики. Один — это высокий декларативный подход, а другой — программный низкоуровневый API:

  • Ресурсы, доступные для рисования. Они используются для создания пользовательской графики программным способом или (более обычно) путем внедрения инструкций рисования в XML-файлы. Рисуемые ресурсы обычно определяются как XML-файлы, содержащие инструкции или действия для Android для отрисовки 2D-рисунка.

  • Холст — это API низкого уровня, который включает в себя рисование непосредственно на базовом растровом рисунке. Он обеспечивает очень точный контроль над отображаемым.

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

  • Анимации , доступные для рисования— Android также поддерживает анимации по кадрам, известные как анимация с возможностью рисования. Это самый простой API анимации. Android последовательно загружает и отображает ресурсы, доступные для рисования, в последовательности (как и в мультфильме).

  • Просмотр анимаций . Просмотр анимаций — это исходный API анимации в Android и доступен во всех версиях Android. Этот API ограничен тем, что он будет работать только с объектами View и может выполнять только простые преобразования в этих представлениях. Анимации просмотра обычно определяются в XML-файлах, найденных в папке /Resources/anim .

  • Анимации свойств — Android 3.0 появился новый набор API анимации, известный как "Анимация свойств". В этих новых API появилась расширяемая и гибкая система, которую можно использовать для анимации свойств любого объекта, а не только для просмотра объектов. Эта гибкость позволяет инкапсулировать анимации в различных классах, которые упрощают общий доступ к коду.

Анимации просмотра более подходят для приложений, которые должны поддерживать более старый API до Android 3.0 (уровень API 11). В противном случае приложения должны использовать более новый API анимации свойств по причинам, которые были упоминание выше.

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

Специальные возможности

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

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

Дополнительные сведения об использовании API специальных возможностей Android см. в руководстве по специальным возможностям Google.

2D Графика

Рисуемые ресурсы являются популярным способом в приложениях Android. Как и в других ресурсах, ресурсы, доступные для рисования, декларативны — они определены в XML-файлах. Такой подход позволяет очистить разделение кода от ресурсов. Это может упростить разработку и обслуживание, так как не требуется изменять код для обновления или изменения графики в приложении Android. Однако, хотя рисуемые ресурсы полезны для многих простых и распространенных графических требований, они не имеют возможности и управления API холста.

Другой метод, использующий объект Canvas , очень похож на другие традиционные платформы API, такие как System.Drawing или основной рисунок iOS. Использование объекта Canvas обеспечивает большую часть управления тем, как создаются 2D-графики. Это подходит для ситуаций, когда ресурс, доступный для рисования, не будет работать или будет трудно работать. Например, может потребоваться нарисовать пользовательский элемент управления ползунка, внешний вид которого изменится на основе вычислений, связанных со значением ползунка.

Сначала рассмотрим ресурсы, доступные для рисования. Они проще и охватывают наиболее распространенные пользовательские варианты рисования.

Ресурсы, доступные для рисования

Ресурсы, доступные для рисования, определяются в XML-файле в каталоге /Resources/drawable. В отличие от внедрения PNG или JPEG, не требуется предоставлять версии ресурсов, зависящих от плотности. Во время выполнения приложение Android загружает эти ресурсы и использует инструкции, содержащиеся в этих XML-файлах, для создания 2D-графики. Android определяет несколько различных типов рисуемых ресурсов:

  • ShapeDrawable — это объект, который рисует примитивную геометрическую фигуру и применяет ограниченный набор графических эффектов для этой фигуры. Они очень полезны для таких задач, как настройка кнопок или настройка фона TextViews. Пример использования более поздних версий ShapeDrawable см. в этой статье.

  • StateListDrawable — это ресурс, который изменит внешний вид на основе состояния мини-приложения или элемента управления. Например, кнопка может изменить его внешний вид в зависимости от того, нажимается ли она или нет.

  • LayerDrawable — этот ресурс, который будет стекать несколько других рисуемых элементов поверх другого. Пример объекта LayerDrawable показан на следующем снимке экрана:

    LayerDrawable example

  • TransitionDrawable — это layerDrawable, но с одной разницей. TransitionDrawable может анимировать один слой вверх поверх другого.

  • LevelListDrawable — это очень похоже на StateListDrawable, в котором он будет отображать изображение на основе определенных условий. Однако, в отличие от StateListDrawable, LevelListDrawable отображает изображение на основе целочисленного значения. Примером levelListDrawable будет отображение силы сигнала WiFi. По мере изменения силы сигнала Wi-Fi отображаемый объект будет изменяться соответствующим образом.

  • ScaleDrawable/ClipDrawable — как подразумевает их имя, эти рисования предоставляют функции масштабирования и вырезки. ScaleDrawable будет масштабировать еще один рисуемый объект, в то время как clipDrawable будет вырезать еще один рисуемый объект.

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

  • Xml BitmapDrawable — этот файл представляет собой набор инструкций в ФОРМАТЕ XML, которые должны выполняться на фактическом растровом рисунке. Некоторые действия, которые могут выполнять Android, являются тилинг, дитеринг и анти-псевдоним. Одним из самых распространенных способов этого является плитка растрового изображения в фоновом режиме макета.

Пример рисования

Давайте рассмотрим краткий пример создания 2D-рисунка с помощью .ShapeDrawable Можно ShapeDrawable определить одну из четырех основных фигур: прямоугольник, овал, линию и кольцо. Также можно применить основные эффекты, такие как градиент, цвет и размер. Следующий XML-код — это ShapeDrawable код, который можно найти в проекте-компаньоне AnimationsDemo (в файле Resources/drawable/shape_rounded_blue_rect.xml). Он определяет прямоугольник с фиолетовым градиентным фоном и округленными углами:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<!-- Specify a gradient for the background -->
<gradient android:angle="45"
          android:startColor="#55000066"
          android:centerColor="#00000000"
          android:endColor="#00000000"
          android:centerX="0.75" />

<padding android:left="5dp"
          android:right="5dp"
          android:top="5dp"
          android:bottom="5dp" />

<corners android:topLeftRadius="10dp"
          android:topRightRadius="10dp"
          android:bottomLeftRadius="10dp"
          android:bottomRightRadius="10dp" />
</shape>

Мы можем ссылаться на этот декларативный ресурс рисования в макете или другом объекте, как показано в следующем XML:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#33000000">
    <TextView android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:layout_centerInParent="true"
              android:background="@drawable/shape_rounded_blue_rect"
              android:text="@string/message_shapedrawable" />
</RelativeLayout>

Рисование ресурсов также можно применять программным способом. В следующем фрагменте кода показано, как программно задать фон TextView:

TextView tv = FindViewById<TextView>(Resource.Id.shapeDrawableTextView);
tv.SetBackgroundResource(Resource.Drawable.shape_rounded_blue_rect);

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

Textview with a custom background, drawable with a gradient and rounded corners

Дополнительные сведения о XML-элементах и синтаксисе drawable Resources см . в документации Google.

Использование API рисования холста

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

Один из классов, часто используемых с Холстом, — это класс Paint . Этот класс содержит сведения о цвете и стиле о том, как нарисовать. Он используется для предоставления таких цветов и прозрачности.

API холста использует модель художника для рисования 2D-графики. Операции применяются в последовательных слоях поверх друг друга. Каждая операция будет охватывать некоторую область базового растрового изображения. Когда область перекрывается ранее окрашенной областью, новая краска частично или полностью скрывает старый. Это тот же способ, что многие другие API рисования, такие как System.Drawing и основная графика iOS.

Существует два способа получения Canvas объекта. Первым способом является определение объекта Bitmap , а затем создание экземпляра Canvas объекта с ним. Например, следующий фрагмент кода создает новый холст с базовым растровым изображением:

Bitmap bitmap = Bitmap.CreateBitmap(100, 100, Bitmap.Config.Argb8888);
Canvas canvas = new Canvas(b);

Другим способом получения Canvas объекта является метод обратного вызова OnDraw , предоставленный базовым классом View . Android вызывает этот метод, когда он решает, что представление должно нарисовать себя и передает объект Canvas для работы с Представлением.

Класс Canvas предоставляет методы для программного предоставления инструкций по рисованию. Например:

  • Canvas.DrawPaint — заполняет растровое изображение всего холста указанным краской.

  • Canvas.DrawPath — рисует указанную геометрическую фигуру с помощью указанной краски.

  • Canvas.DrawText — рисует текст на холсте с указанным цветом. Текст рисуется в расположении x,y .

Рисование с помощью API холста

Ниже приведен пример API холста в действии. В следующем фрагменте кода показано, как нарисовать представление:

public class MyView : View
{
    protected override void OnDraw(Canvas canvas)
    {
        base.OnDraw(canvas);
        Paint green = new Paint {
            AntiAlias = true,
            Color = Color.Rgb(0x99, 0xcc, 0),
        };
        green.SetStyle(Paint.Style.FillAndStroke);

        Paint red = new Paint {
            AntiAlias = true,
            Color = Color.Rgb(0xff, 0x44, 0x44)
        };
        red.SetStyle(Paint.Style.FillAndStroke);

        float middle = canvas.Width * 0.25f;
        canvas.DrawPaint(red);
        canvas.DrawRect(0, 0, middle, canvas.Height, green);
    }
}

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

Screen with red paint and green paint objects

Анимация

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

  • Анимация просмотра — это исходный API. Эти анимации привязаны к определенному представлению и могут выполнять простые преобразования содержимого представления. Из-за простоты этот API по-прежнему полезен для таких вещей, как альфа-анимация, повороты и т. д.

  • Анимация свойств — анимации свойств появились в Android 3.0. Они позволяют приложению анимировать практически все. Анимации свойств можно использовать для изменения любого свойства любого объекта, даже если этот объект не отображается на экране.

  • Анимация с возможностью рисования — это специальный ресурс рисования, используемый для применения очень простого эффекта анимации к макетам.

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

Просмотр анимаций

Анимации просмотра ограничены представлениями и могут выполнять анимацию только для значений, таких как начальные и конечные точки, размер, поворот и прозрачность. Эти типы анимаций обычно называются анимациями tween. Анимации просмотра можно определить двумя способами— программным способом в коде или с помощью XML-файлов. XML-файлы — это предпочтительный способ объявления анимаций представления, так как они являются более удобочитаемыми и проще поддерживать.

XML-файлы анимации будут храниться в /Resources/anim каталоге проекта Xamarin.Android. Этот файл должен иметь один из следующих элементов в качестве корневого элемента:

  • alpha — анимация исчезания или отключаемой анимации.

  • rotate — анимация поворота.

  • scale — анимация изменения размера.

  • translate — горизонтальное и /или вертикальное движение.

  • set — контейнер, который может содержать один или несколько других элементов анимации.

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

Можно повлиять на скорость изменения анимации с помощью интерполятора. Интерполятор позволяет ускорить, повторять или уменьшать эффекты анимации. Платформа Android предоставляет несколько интерполяторов из поля, таких как (но не ограничено):

  • AccelerateInterpolator / DecelerateInterpolator — эти интерполяторы увеличивают или снижают скорость изменения анимации.

  • BounceInterpolator — изменение отскакивает в конце.

  • LinearInterpolator — скорость изменений является константой.

В следующем XML-файле показан пример файла анимации, объединяющего некоторые из этих элементов:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android=http://schemas.android.com/apk/res/android
     android:shareInterpolator="false">

    <scale android:interpolator="@android:anim/accelerate_decelerate_interpolator"
           android:fromXScale="1.0"
           android:toXScale="1.4"
           android:fromYScale="1.0"
           android:toYScale="0.6"
           android:pivotX="50%"
           android:pivotY="50%"
           android:fillEnabled="true"
           android:fillAfter="false"
           android:duration="700" />

    <set android:interpolator="@android:anim/accelerate_interpolator">
        <scale android:fromXScale="1.4"
               android:toXScale="0.0"
               android:fromYScale="0.6"
               android:toYScale="0.0"
               android:pivotX="50%"
               android:pivotY="50%"
               android:fillEnabled="true"
               android:fillBefore="false"
               android:fillAfter="true"
               android:startOffset="700"
               android:duration="400" />

        <rotate android:fromDegrees="0"
                android:toDegrees="-45"
                android:toYScale="0.0"
                android:pivotX="50%"
                android:pivotY="50%"
                android:fillEnabled="true"
                android:fillBefore="false"
                android:fillAfter="true"
                android:startOffset="700"
                android:duration="400" />
    </set>
</set>

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

Анимация может быть программно применена к представлению, раздувая анимацию, а затем применяя ее к представлению. Android предоставляет вспомогательный класс Android.Views.Animations.AnimationUtils , который будет раздувать ресурс анимации и возвращать экземпляр Android.Views.Animations.Animation. Этот объект применяется к представлению путем вызова StartAnimation и передачи Animation объекта. В следующем фрагменте кода показан пример:

Animation myAnimation = AnimationUtils.LoadAnimation(Resource.Animation.MyAnimation);
ImageView myImage = FindViewById<ImageView>(Resource.Id.imageView1);
myImage.StartAnimation(myAnimation);

Теперь, когда у нас есть базовое представление анимации, позволяет перейти к анимациям свойств.

Анимации свойств

Аниматоры свойств — это новый API, который был представлен в Android 3.0. Они предоставляют более расширяемый API, который можно использовать для анимации любого свойства в любом объекте.

Все анимации свойств создаются экземплярами подкласса Animator . Приложения не используют этот класс напрямую, а используют один из подклассов:

  • ValueAnimator — этот класс является самым важным классом во всем API анимации свойств. Он вычисляет значения свойств, которые необходимо изменить. Вместо этого он не обновляет эти значения напрямую. Он ViewAnimator вызывает события, которые можно использовать для обновления анимированных объектов.

  • ObjectAnimator — этот класс является подклассом ValueAnimator . Он предназначен для упрощения процесса анимации объектов путем принятия целевого объекта и свойства для обновления.

  • AnimationSet — этот класс отвечает за оркестрацию того, как анимации выполняются в отношении друг друга. Анимации могут выполняться одновременно, последовательно или с указанной задержкой между ними.

Вычислители — это специальные классы , используемые аниматорами для вычисления новых значений во время анимации. Вне поля Android предоставляет следующие вычислители:

  • IntEvaluator — вычисляет значения для целочисленных свойств.

  • FloatEvaluator — вычисляет значения для свойств float.

  • ArgbEvaluator — вычисляет значения для свойств цвета.

Если анимированное свойство не является цветом или цветомfloatint, приложения могут создать собственный ITypeEvaluator средство оценки путем реализации интерфейса. (Реализация пользовательских вычислителей выходит за рамки область этого раздела.)

Использование ValueAnimator

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

Вы получите экземпляр ValueAnimator , вызвав один из следующих методов фабрики:

  • ValueAnimator.OfInt
  • ValueAnimator.OfFloat
  • ValueAnimator.OfObject

После этого ValueAnimator экземпляр должен иметь свой набор длительности, а затем его можно запустить. В следующем примере показано, как анимировать значение от 0 до 1 за 1000 миллисекундах:

ValueAnimator animator = ValueAnimator.OfInt(0, 100);
animator.SetDuration(1000);
animator.Start();

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

MyCustomObject myObj = new MyCustomObject();
myObj.SomeIntegerValue = -1;

animator.Update += (object sender, ValueAnimator.AnimatorUpdateEventArgs e) =>
{
    int newValue = (int) e.Animation.AnimatedValue;
    // Apply this new value to the object being animated.
    myObj.SomeIntegerValue = newValue;
};

Теперь, когда у нас есть понимание ValueAnimator, давайте узнаем больше о ObjectAnimator.

Использование ObjectAnimator

ObjectAnimator — это подкласс ViewAnimator , который объединяет подсистему времени и вычисления ValueAnimator значений логики, необходимой для провода обработчиков событий. Требуется ValueAnimator , чтобы приложения явно проводя обработчик событий, ObjectAnimator позаботится об этом шаге.

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

MyCustomObject myObj = new MyCustomObject();
myObj.SomeIntegerValue = -1;

ObjectAnimator animator = ObjectAnimator.OfFloat(myObj, "SomeIntegerValue", 0, 100);
animator.SetDuration(1000);
animator.Start();

Как видно из предыдущего фрагмента кода, можно уменьшить и упростить код, ObjectAnimator необходимый для анимации объекта.

Анимации, доступные для рисования

Последний API анимации — ЭТО API анимации, доступный для рисования. Анимации, доступные для рисования, загружают ряд ресурсов, доступных для рисования, один за другим и отображают их последовательно, как и мультипликация.

Ресурсы, доступные для рисования, определяются в XML-файле, который имеет <animation-list> элемент в качестве корневого элемента и ряд элементов, определяющих <item> каждый кадр в анимации. Этот XML-файл хранится в /Resource/drawable папке приложения. Следующий XML-код является примером анимации, доступной для рисования:

<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:drawable="@drawable/asteroid01" android:duration="100" />
  <item android:drawable="@drawable/asteroid02" android:duration="100" />
  <item android:drawable="@drawable/asteroid03" android:duration="100" />
  <item android:drawable="@drawable/asteroid04" android:duration="100" />
  <item android:drawable="@drawable/asteroid05" android:duration="100" />
  <item android:drawable="@drawable/asteroid06" android:duration="100" />
</animation-list>

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

AnimationDrawable _asteroidDrawable;

protected override void OnCreate(Bundle bundle)
{
    base.OnCreate(bundle);
    SetContentView(Resource.Layout.Main);

    _asteroidDrawable = (Android.Graphics.Drawables.AnimationDrawable)
    Resources.GetDrawable(Resource.Drawable.spinning_asteroid);

    ImageView asteroidImage = FindViewById<ImageView>(Resource.Id.imageView2);
    asteroidImage.SetImageDrawable((Android.Graphics.Drawables.Drawable) _asteroidDrawable);

    Button asteroidButton = FindViewById<Button>(Resource.Id.spinAsteroid);
    asteroidButton.Click += (sender, e) =>
    {
        _asteroidDrawable.Start();
    };
}

На этом этапе мы рассмотрели основы API анимации, доступные в приложении Android.

Итоги

В этой статье представлено множество новых концепций и API, которые помогут добавить некоторые графические элементы в приложение Android. Сначала он обсудил различные графические API 2D и продемонстрировал, как Android позволяет приложениям рисовать непосредственно на экране с помощью объекта Canvas. Мы также видели некоторые альтернативные методы, позволяющие декларативно создавать графику с помощью XML-файлов. Затем мы обсудили старые и новые API для создания анимаций в Android.