Главная » Разработка для Android » Отрисовываемые объекты в Android приложении

0

 

Отрисовываемый объект (Drawablе) – это объект, знающий, как отобразить себя на холсте Canvas. Поскольку во время отображения Drawablе поддается полному контролю, даже самый сложный процесс отображения можно «упаковать» так, что пользоваться им не составит никакого труда.

В примерах 9.7 и 9.8 показаны изменения, которые необходимо сделать, чтобы реализовать пример, показанный на рис. 9.3, при помощи Drawable. Код, рисующий красный и зеленый текст, путем рефакторинга был преобразован в класс Неї 1 oAndroidTextDrawablе, используемый методом onDraw при отображении (этот метод относится к виджету).

Пример 9.7. Использование TextDrawable

Для использования новой реализации Drawable потребуется внести в метод onDraw из нашего примера всего несколько небольших изменений.

Пример 9.8. Использование виджета Drawable

В какой-то мере этот код уже позволяет оценить огромный потенциал Drawable. Такая реализация TransformedViewWidget может преобразовать любой Drawable независимо от того, что именно предполагается рисовать. Код уже не имеет жесткой привязки к вращению и масштабированию нашего исходного жестко закодированного текста. Его можно использовать многократно для преобразования как текста, взятого из предыдущего примера, так и фотографии, снятой на фотоаппарат (рис. 9.4). Рисунок даже можно преобразовать в Drawablе-анимацию.

Рис. 9.4. Преобразованные виды с фотографиями

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

Попробуем представить, как можно дополнить предыдущий пример, чтобы за минуту каждое из шести изображений на какое-то время «выцветало» и на его месте оставался просто белый квадрат. Разумеется, нужно просто изменить код из примера 9.8, добавив к нему эффект выцветания. Другой – гораздо более интересный – вариант реализации связан с написанием одного нового Drawable.

Конструктор этого нового отрисовываемого объекта (назовем такой объект FaderDrawable) будет принимать в качестве аргумента ссылку на целевой объект, тот Drawable, который будет «выцветать» до белого квадрата. Кроме того, этот объект должен иметь какое-то представление о времени, например целое число – назовем его t, – приращение которого происходит по мере работы таймера. При каждом вызове метода draw, относящегося к объекту FaderDrawable, он сначала вызывает метод draw своей цели. Но потом он постепенно зарисовывает ту же целевую область белым цветом, используя значение t для определения прозрачности рисунка, как это показано в примере 9.2. Со временем t увеличивается, белый цвет становится все более насыщенным и целевой объект Drawable полностью исчезает из вида.

Такой гипотетический объект FaderDrawable демонстрирует несколько важных свойств отрисовываемых объектов. FaderDrawable по определению пригоден для многократного использования. Применяя его, можно «растворить» практически любой отрисовываемый объект. Кроме того, поскольку FaderDrawable дополняет Drawable, FaderDrawable можно использовать во всех тех местах, где мы бы применяли и его целевой объект, то есть Drawable, «выцветающий» до белого квадрата. Любой код, использующий Drawable в процессе отображения, может применять и FaderDrawable без изменений.

Разумеется, и сам FaderDrawable может быть заключен в другой объект. На самом деле можно достичь^достаточно сложных эффектов, просто построив цепь оболочек Drawable. В инструментарии Android предоставляются оболочки Drawable, поддерживающие такой способ работы, в том числе CI ipDrawable, RotateDrawable и ScaleDrawable.

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

Вы, наверное, заметили, что отрисовываемые объекты имеют немало общих функций с классом View: расположение, размеры, видимость и т. д. Не всегда бывает просто принять решение о том, когда View должен рисовать прямо на Canvas, когда – делегировать эту задачу своему подвиду, а когда – одному или нескольким отрисовываемым объектам. Есть даже класс DrawableContai пег, позволяющий группировать несколько дочерних Drawable внутри родительского элемента. Можно строить деревья Drawable, аналогичные деревьям View, которые мы использовали до сих пор. Работая с фреймворком пользовательского интерфейса Android, мы просто признаем, что есть несколько способов сделать одно и то же.

Разница между двумя способами заключается в том, что отрисовываемые объекты не реализуют свойственный для View протокол измерения/компоновки. Как вы помните, такой протокол позволяет дочерним видам, находящимся внутри контейнерного вида, «договариваться» о компоновке компонентов в зависимости от изменения размеров вида. Когда отображаемому объекту требуется добавить, удалить или перегруппировать свои внутренние компоненты – это серьезный аргумент в пользу того, что в данном случае следует использовать полнофункциональный View, а не Drawable.

Вторая проблема, которую необходимо учитывать, состоит в том, что, поскольку объекты Drawable полностью заключают в себе процесс рисования, они не рисуются так, как объекты Stri ng или Rect. Например, не существует никаких методов Canvas, которые бы отображали Drawable в конкретных координатах.

Возможно, вы задумаетесь, что лучше сделать, чтобы дважды отобразить одно и то же изображение: применить метод View.onDraw, который будет использовать два разных неизменяемых Drawable, или дважды задействовать один и тот же Drawable, переустановив его координаты после первого применения.

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

Существенная часть процесса рисования происходит с сохранением состояния. Вы настраиваете Paint, области отсечения, Canvas, а потом рисуете. При совместной работе по цепочке Drawable нужно внимательно следить за тем, чтобы после изменения состояний Drawable между ними не возникало конфликтов. Проблема заключается в том, что при построении цепочки Drawable невозможно явно и сразу определить по типу объекта, какие конфликты могут возникнуть (ведь перед нами просто группа отрисовываемых объектов). Самое незначительное изменение может вызывать нежелательные последствия, которые плохо поддаются отладке.

Чтобы проиллюстрировать эту ситуацию, представим себе два класса-обертки Drawable, один из которых должен ужимать контент, а другой – поворачивать его на 90°. Если каждая операция реализуется путем присвоения матрице преобразований конкретного значения, то совместное использование этих классов может дать нежелательный эффект. Еще хуже ситуация, в которой А отлично оборачивает В, а В совсем не оборачивает Л! Поэтому важно подробно описывать в документации, как именно работает данный Drawable.

Источник: Android. Программирование на Java для нового поколения мобильных устройств

По теме:

  • Комментарии