android что такое canvas
Полный список
— используем матрицу канвы для преобразований
Канва имеет свою матрицу, которая будет срабатывать для любого объекта, который вы собираетесь нарисовать. Методы настройки этой матрицы нам уже известны из Урока 144:
— translate (перемещение)
— scale (изменение размера)
— rotate (поворот)
— skew (наклон)
У канвы эти методы являются pre-методами. Т.е. помещают преобразование в начало матрицы, сохраняя остальные.
Рассмотрим это на примере.
Преобразования
Project name: P1461_CanvasTransform
Build Target: Android 2.3.3
Application name: CanvasTransform
Package name: ru.startandroid.develop.p1461canvastransform
Create Activity: MainActivity
Рисуем черным цветом path с прямоугольником. Затем настраиваем матрицу на поворот на 30 градусов относительно точки (0,0) (т.к. не указана иная) и на перемещение на 500 вправо. Т.к. используем методы pre, то сначала будет перемещение, потом поворот. Преобразуем path и выводим синим цветом.
Попробуем сделать то же самое, с помощью канвы.
Сначала выводим прямоугольник rectf черным цветом. Затем настраиваем матрицу канвы. Задаем те же преобразования, в том же порядке. Т.к. эти методы являются аналогами pre-методов, то сначала выполнится перемещение, затем поворот.
Матрица канвы настроена, теперь все объекты, которые мы будем рисовать на канве, будут преобразованы согласно ее матрице. Нарисуем тот же прямоугольник rectf зеленым цветом.
Заметьте, что мы никак не преобразуем rectf. Он остается с теми же координатами. Канва сама преобразует его при рисовании.
Зеленый прямоугольник находится там же, где в прошлый раз был синий. Т.е. преобразования с помощью отдельной матрицы идентичны преобразованиям матрицы канвы.
Сохранение и возврат состояния
Мы можем запоминать состояние матрицы канвы и потом восстанавливать его.
Рассмотрим это на примерах. Перепишем DrawView:
Без всяких преобразований они выглядят так:
Несколько раз настраиваем перемещение на 100 вправо и каждый раз рисуем первый квадрат зеленым цветом. Затем сбрасываем матрицу канвы методом restore в изначальное состояние. И рисуем второй квадрат синим цветом.
Видим, что первый (зеленый) квадрат рисовался со смещением согласно настройкам канвы, а метод restore все эти настройки преобразования сбросил и второй (синий) квадрат был нарисован без преобразований.
Можно настроить канву так, что метод restore будет сбрасывать ее настройки не в изначальное, а в промежуточное, сохраненное нами, состояние.
Снова несколько раз настраиваем перемещение на 100 вправо и каждый раз рисуем первый квадрат зеленым цветом. Затем для канвы выполняем метод save. Он запомнит текущие настройки матрицы. Далее еще пару раз перемещаем вправо на 100 и рисуем первый квадрат, но уже красным цветом, чтобы визуально отличить вывод до и после сохранения канвы.
Затем выполняем метод restore, который сбросит канву в состояние, которые было сохранено методом save. И рисуем второй квадрат синим цветом.
Видим, что второй (синий) квадрат нарисован с тем состоянием канвы, которое было сохранено методом save. Метод restore вернул нас к нему из текущего состояния.
Сохранение методом save не затирает предыдущее сохраненное состояние. Т.е. вы можете несколько раз вызывать save и все эти состояния будут хранится в некоем стеке. А методом restore состояния из этого стека вытаскивать.
Мы несколько раз применяем перемещение на 100, рисуя первый квадрат. При этом периодически сохраняем состояние матрицы методом save, при этом меняя цвет для более удобного визуального восприятия.
Далее, мы несколько раз вызываем метод restore, который возвращает канву в сохраненные ранее состояния и рисуем второй квадрат. В итоге мы приходим к изначальному состоянию канвы.
Метод save возвращает нам int значение. Это значение мы можем передать в метод restoreToCount и матрица вернется к указанному состоянию, минуя остальные.
Мы запоминаем состояние в самом начале и сохраняем значение метода save в переменную initSave. Далее мы выполняем перемещения, несколько раз сохраняем канву, и один раз пишем значение сохранения в needSave.
Затем мы возвращаемся к сохраненным состояниям, используя метод restoreToCount и переменные initSave и needSave.
В прошлом примере мы методом restore перебирали все сохраненные состояния. А здесь метод restoreToCount позволил нам вернуться сразу к необходимому состоянию.
И напоследок еще три метода канвы
setMatrix(Matrix matrix) – меняет матрицу канвы на указанную матрицу
getMatrix() – позволяет получить копию матрицы канвы
concat(Matrix matrix) – добавляем в начало текущей матрицы преобразования из указанной матрицы
На следующем уроке:
Присоединяйтесь к нам в Telegram:
— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.
— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование
— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня
— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме
Полный список
— получаем доступ к Canvas
Наконец-то начинаем цикл уроков по графике в Android. Не прошло и двух с половиной лет с момента создания сайта.
Для начала рассмотрим обычное 2D рисование.
Сразу скажу, что канва является лишь инструментом для рисования. А весь результат сохраняется на Bitmap. Мы не можем напрямую попросить Bitmap нарисовать на себе линию или круг, поэтому канва выступает посредником и помогает нам нарисовать то, что нужно.
В этом уроке разберем два способа получения доступа к канве.
Первый способ – через наследника View класса. Нам нужно просто переопределить его метод onDraw и он даст нам доступ к канве. Кода тут минимум и все предельно просто. Но есть недостаток – все рисование выполняется в основном потоке. Это прокатит, если у вас статичная картинка или не слишком динамичная анимация.
Второй способ – через SurfaceView. Этот способ подойдет, если планируете рисовать что-то тяжелое и динамичное. Под рисование здесь будет выделен отдельный поток. Это уже немного посложнее в реализации, чем первый способ.
Project name: P1411_CanvasView
Build Target: Android 2.3.3
Application name: CanvasView
Package name: ru.startandroid.develop.p1411canvasview
Create Activity: MainActivity
В onCreate мы в метод setContentView передаем не layout-файл, как обычно, а свой view-компонент DrawView. Он будет занимать все содержимое Activity.
Класс DrawView является наследником View и переопределяет его метод onDraw. А этот метод дает нам доступ к объекту Canvas. Пока что не будем рисовать ничего особенного, а просто закрасим все зеленым цветом с помощью метода drawColor.
Собственно, все. Готово первое приложение, которое что-то рисует на экране.
Все сохраняем, запускаем и видим результат.
Экран зеленый, как мы и просили.
Метод onDraw был вызван системой, когда возникла необходимость прорисовать View-компонент на экране. Это также произойдет, например, если выключить-включить экран. Попробуйте поставить в onDraw лог и посмотреть результат.
Если вам надо, чтобы на канве была какая-то анимация, необходимо самим постоянно вызывать перерисовку экрана, когда ваши изменения готовы к отображению. Для этого используется метод invalidate. Вызываете его и он в свою очередь вызовет onDraw. Также есть реализации метода invalidate, которые позволяет перерисовать не весь компонент, а только его часть, указав координаты.
Если нужна цикличная прорисовка, можно поместить метод invalidate прямо в onDraw и View будет постоянно перерисовываться. В некоторых уроках, думаю, будем так делать, но только для упрощения кода. А в действительности это не очень хорошая практика, т.к. это все будет идти в основном потоке. И правильнее будет реализовать такую постоянную перерисовку через SurfaceView.
Давайте посмотрим как это делается.
SurfaceView
Стало чуть сложнее, правда? ) Сейчас разберемся что к чему.
Метод onCreate, собственно, ничуть не изменился. Мы также в метод setContentView передаем наш объект DrawView.
Смотрим DrawView. Он является наследником SurfaceView и заодно реализует интерфейс обработчика SurfaceHolder.Callback. Напоминаю, что с SurfaceView мы уже работали в уроке про камеру (Урок 132). Этот компонент только отображает контент. А работа с ним ведется через обработчика SurfaceHolder.
В конструкторе DrawView мы получаем SurfaceHolder и сообщаем ему, что сами будем обрабатывать его события. Таких событий три:
surfaceCreated – SurfaceView создан и готов к отображению информации
surfaceDestroyed – вызывается перед тем, как SurfaceView будет уничтожен
В surfaceCreated мы создаем свой поток прорисовки (о нем чуть позже), передаем ему SurfaceHolder. Вызовом метода setRunning(true) ставим ему метку о том, что он может работать и стартуем его.
В surfaceDestroyed мы своему потоку сообщаем (setRunning(false)) о том, что его работа должна быть прекращена, т.к. SurfaceView сейчас будет уничтожено. Далее запускаем цикл, который ждет, пока не завершит работу наш поток прорисовки. Дождаться надо обязательно, иначе поток может попытаться нарисовать что-либо на уничтоженном SurfaceView.
DrawThread, наследник Thread, – это наш поток прорисовки. В нем и будет происходить рисование.
В конструктор передаем SurfaceHolder. Он нам нужен, чтобы добраться до канвы.
Метод setRunning ставит метку работы, сообщающую потоку, можно ли работать.
Метод run. В нем видим цикл, который выполняется пока позволяет метка работы (running). В цикле обнуляем переменную канвы, затем от SurfaceHolder получаем канву методом lockCanvas. На всякий случай проверяем, что канва не null, и можно рисовать: снова просто закрашиваем все зеленым цветом. После того, как нарисовали, что хотели, мы возвращаем канву объекту SurfaceHolder методом unlockCanvasAndPost в секции finally (обязательной для выполнения) и SurfaceView отобразит наши художества.
Соответственно, когда в surfaceDestroyed вызывается метод setRunning(false), происходит выход из цикла в методе run и поток завершает свою работу.
Все сохраняем, запускаем и видим результат.
Когда мы рассматривали первый способ получения канвы (через onDraw), я упомянул, что надо самим вызывать invalidate, если нужна постоянная перерисовка. Во втором способе ничего такого делать уже не надо. У нас итак идет постоянная перерисовка в цикле.
На этом вводный урок закончим. Мы рассмотрели два способа получения канвы. В последующих уроках я буду использовать первый способ, т.к. он проще, кода в нем значительно меньше и можно будет сосредоточиться непосредственно на работе с канвой и рисовании.
На следующем уроке:
— рисуем фигуры
— выводим текст
Присоединяйтесь к нам в Telegram:
— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.
— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование
— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня
— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме
Русские Блоги
Описание рисунка Android Canvas Краткое описание метода Android Canvas
Android использует движок обработки графики, 2D-часть предоставляется Android SDK, а 3D-часть использует Open GL ES 1.0. Сегодня мы в основном хотим понять, что такое 2D, если вы хотите смотреть 3D, вы можете пропустить эту статью.
Большинство API-интерфейсов, используемых в 2D, находятся в пакетах android.graphics и android.graphics.drawable. Они обеспечивают обработку графики: Canvas, ColorFilter, Point (точка) и RetcF (прямоугольник) и т. Д., А также некоторые связанные с анимацией: AnimationDrawable, BitmapDrawable и TransitionDrawable. Что касается обработки графики, то чаще всего мы используем для рисования некоторых изображений, фигур или настраиваемого текстового содержимого в представлении. Здесь все мы реализованы с использованием Canvas. Вы можете получить объект Canvas в представлении, нарисовать несколько настраиваемых фигур, а затем вызвать метод View. Invalidate, чтобы обновить представление, а затем нарисовать новую форму для достижения эффекта 2D-анимации. Ниже мы в основном разберемся, как использовать Canvas.
Есть два способа получить объект Canvas: один состоит в том, что мы переопределяем метод View.onDraw. Объект Canvas в представлении будет передан в качестве параметра. Когда мы работаем с этим Canvas, эффект будет непосредственно отражен в представлении. Другой метод используется, когда вы хотите создать объект Canvas:
Приведенный выше код создает Bitmap размером 100 * 100 и использует его в качестве объекта операции Canvas. В этот момент Canvas создается с использованием метода создания. После использования созданного холста для выполнения метода рисования на растровом изображении вы также можете отправить результат рисования на другой холст, чтобы добиться эффекта совместной работы двух холстов и упростить логику. Но Android SDK рекомендует использовать Canvas, указанный в параметре View.onDraw. Нет необходимости создавать новый объект Canvas самостоятельно. Затем давайте посмотрим, какие методы Canvas предоставляет нам для рисования графики. Мы создаем настраиваемый объект View и используем Canvas, предоставляемый методом onDraw, для рисования графики.
Используйте следующий код:
Сравнивая эти две цифры, мы можем обнаружить, что когда useCenter в drawArcs (rect, startAngel, sweepAngel, useCenter, paint) имеет значение false, область дуги напрямую связана с начальным и конечным углом дуги. Когда useCenter имеет значение true, Начальный и конечный углы дуги соединяются с центральной точкой, образуя веерную форму.
Графика
Пакет android.graphics имеет все необходимые библиотеки для работы с двухмерной графикой. Существует несколько подходов для рисования графики.
Для рисования простой графики, которая не будет динамически изменяться во время работы приложения, обычно используют класс, наследующий от View и задействуют метод onDraw().
В метод передаётся объект Canvas, у которого есть различные графические методы.
Стандартная реализация подобного подхода выглядит следующим образом:
В методе setContentView() вместо ссылки на разметку передаётся класс MyView, наследующий от View:
В методе onDraw() можете рисовать:
Для рисования динамической графики больше подойдёт класс SurfaceView, имеющий дополнительные возможности. Данному классу мы посвятим отдельный материал.
Класс Color
Класс Color отвечает за цвета. Цвета можно описывать четырьмя числами в формате ARGB, по одному для каждого канала(Alpha, Red, Green, Blue).
Класс Paint
Класс Paint содержит стили, цвета и другую графическую информацию для рисования графических объектов. Он позволяет выбирать способ отображения графических примитивов, которые вы рисуете на объекте Canvas с помощью методов. Изменяя объект Paint, можно контролировать цвет, стиль, шрифт и специальные эффекты, используемые при рисовании. Например, чтобы установить сплошной цвет для рисования линии, нужно вызвать метод Paint.setColor().
В этом примере мы использовали готовую константу. Также можно указать 32-битное целое число, закодированное в схеме ARGB8888.
Можно установить цвет через его составляющие:
Стиль объекта Paint, задаваемый с помощью метода setStyle(), позволяет рисовать либо очертания графического примитива (STROKE), либо его заливку (FILL), либо и то, и другое сразу (STROKE_AND_FILL).
Помимо этих простых методов класс Paint поддерживает прозрачность и может быть изменён с помощью различных шейдеров, фильтров и эффектов, которые предоставляют богатый набор сложных красок и кистей.
Использование полупрозрачности
Любой цвет в Android содержит свойство прозрачности (альфа-канал). Указать его можно при создании описывающей цвет переменной, используя методы argb() и parseColor():
Но мы можем задать прозрачность уже существующего объекта Paint с помощью метода setAlpha():
Пример использования метода setAlpha() для наложения двух картинок.
Режим Xfermode
Изменение режима Xfermode для объекта Paint влияет на способ наложения новых цветов поверх уже нарисованных. В обычных обстоятельствах при рисовании поверх имеющегося рисунка создастся новый верхний слой. Если новый объект Paint на 100% непрозрачный, он полностью закрасит все, что находится под областью для рисования; если он полупрозрачный, то только затенит лежащие ниже цвета. Подклассы Xfermode позволяют изменить такое поведение.
Для того чтобы применить один из этих режимов, используйте метод setXferMode():
Сглаживание
При создании нового объекта Paint вы можете передать в его конструктор несколько флагов, которые будут влиять на способ отображения. Одним из наиболее интересных из них считается флаг ANTI_ALIAS_FLAG, обеспечивающий сглаживание диагональных линий, рисуемых объектом Paint (снижая при этом производительность).
Сглаживание играет важную роль в процессе отрисовки текста, значительно упрощает его восприятие. Чтобы сделать текст более гладким, можете использовать флаг SUBPIXEL_TEXT_FLAG, который применяет субпиксельное сглаживание. Можно задать оба этих флага программно, используя методы setSubpixelText() и setAntiAlias():
Класс Path
Класс Canvas
Класс Canvas представляет собой специальную поверхность (холст), на которой вы можете рисовать. С помощью многочисленных методов класса вы можете рисовать линии, окружности, дуги и так далее.
Класс Bitmap
Класс Bitmap отвечает за растровые картинки.
Android что такое canvas
Android framework API предоставляет набор классов для плоского рисования на экране приложения, которые позволяют Вам нарисовать любую графику и текст, или модифицировать имеющиеся представления View согласно Вашим пожеланиям и чувствам. Когда рисуете 2D-графику, обычно это делают двумя способами:
a. Рисование графики или анимации в пределах объекта View, находящегося на разметке окна программы (layout). В этом случае рисование графики обрабатывается системой по обычной иерархии процесса рисования View — Вы просто задаете нужные графические представления внутри View.
b. Рисование графики напрямую на экране программы как на холсте (на Canvas). В этом случае Вы персонально вызываете подходящий метод класса onDraw() (передавая ему Ваш Canvas), или одним из методов Canvas, начинающимся на draw. () (наподобие drawPicture()). При этом Вы также контролируете любую анимацию.
Опция «a», рисование в View, является лучшим выбором, когда Вы хотите нарисовать простые графические объекты, которые не нужно динамически изменять, и которые не являются частью требовательной к быстроте прорисовки игры. Например, Вы должны рисовать Вашу графику в View, когда хотите отобразить статическую графику или заранее предопределенную анимацию в некотором статическом приложении. Для получения подробностей см. ниже раздел «Рисуемые объекты (Drawables)».
Опция «b», рисование на Canvas, лучше подходит, когда Ваше приложение требует регулярной собственной перерисовки. Приложения наподобие видеоигр должны самостоятельно рисовать на Canvas. Однако есть несколько способов такого рисования:
[Рисование с помощью Canvas]
Когда Вы пишете приложение, которое должно выполнять отрисовку некоторой специализированной графики и/или управлять некоторыми сложными графическими анимациями (игра), это следует делать с помощью Canvas. Canvas работает для Вас как специальный интерфейс, символизирующий реальную поверхность, на которой вы будете рисовать — он содержит в себе все нужные методы для рисования (их названия начинаются на «draw»). С помощью Canvas Ваше рисование в действительности происходит на нижележащую растровую картинку (Bitmap), которая размещена на экране программы.
Теперь Ваш Canvas будет рисовать на заданной картинке Bitmap. После рисования вместе с Canvas Вы можете перенести Вашу картинку Bitmap на другой Canvas одним из методов Canvas.drawBitmap(Bitmap. ). Это рекомендуется, если Вы рисуете конечную графику через Canvas, предоставленный Вам в View.onDraw() или SurfaceHolder.lockCanvas() (см. это в последующих секциях).
Класс Canvas имеет свои собственные методы рисования, которые Вы можете использовать, наподобие drawBitmap(. ), drawRect(. ), drawText(. ) и многие другие. Другие классы, которые Вы можете использовать, также имеют методы draw(). Например, у Вас возможно будут некоторые Drawable-объекты, который захотите поместить на Canvas. Drawable имеет свой собственный метод draw(), который получает Ваш Canvas как аргумент.
[Рисование на View]
Чтобы начать, расширьте класс View (или произведите от него дочерний) и определите метод обратного вызова onDraw(). Этот метод будет вызван фреймворком Android framework для запроса перерисовки View самого себя. В этом месте будут все Ваши вызовы рисования на Canvas, который будет передан через обратный вызов onDraw().
Фреймворк Android будет вызывать onDraw() только при необходимости. Каждый раз, когда Ваше приложение будет подготовлено к отрисовке, Вы должны запросить View стать недействительным вызовом invalidate(). Это показывает, что нужно перерисовать View, и Android сделает вызов onDraw() (хотя не гарантируется, что обратный вызов будет исполнен немедленно).
Внутри метода onDraw() Вашего компонента View используйте предоставленный Вам Canvas для всех отрисовок, используя многочисленные методы Canvas.draw. () или другие методы draw() класса (Canvas передается в виде аргумента). Как только Ваш onDraw() завершится, фреймворк Android будет использовать Ваш Canvas для отрисовки Bitmap с обработкой на уровне системы.
Примечание: чтобы сделать запрос перерисовки invalidate из другого потока, не из главного потока активности (main Activity thread), Вы должны вызвать postInvalidate().
Для дополнительной информации по расширению класса View прочитайте руководство Building Custom Components.
[Рисование на SurfaceView]
SurfaceView является специальным подклассом View, который предоставляет выделенную поверхность рисования в пределах иерархии View. Цель состоит в том, чтобы предоставить эту вторичную поверхность рисования второму потоку, чтобы приложению не требовалось ждать, пока системная иерархия View будет готова к отрисовке. Вместо этого второй поток, который имеет ссылку на SurfaceView, может рисовать в своем Canvas и в своем темпе.
Чтобы начать, нужно создать новый класс, который расширяет (extends) класс SurfaceView. Класс должен реализовать SurfaceHolder.Callback. Этот подкласс является интерфейсом, который уведомит Вас о событиях нижележащей поверхности, таких как создание, изменение или уничтожение. Эти события важны для того, чтобы Вы знали, когда можно начать рисовать, нужно ли внести изменения на основе новых свойств поверхности, и когда нужно остановить рисование и потенциально прибить некоторые задачи. Хорошим решением будет также определить внутри Вашего класса Ваш класс второго потока Thread, который будет выполнять все процедуры рисования на Вашем Canvas.
Вместо того, чтобы напрямую обрабатывать объект поверхности Surface, Вы должны делать это через SurfaceHolder. Когда Ваш SurfaceView проинициализирован, получите SurfaceHolder вызовом getHolder(). Затем Вы должны оповестить SurfaceHolder, что хотите принимать методы обратного вызова SurfaceHolder (из SurfaceHolder.Callback) путем вызова addCallback(). Затем перезадайте каждый из методов SurfaceHolder.Callback внутри Вашего класса SurfaceView.
Чтобы рисовать на Surface Canvas из второго потока, Вы должны передать потоку ваш SurfaceHandler и получить Canvas вызовом lockCanvas(). Теперь Вы можете взять Canvas, предоставленный Вам SurfaceHolder, и сделать на нем все нужные отрисовки. Как только Вы завершили рисовать вместе с Canvas, вызовите unlockCanvasAndPost(), передав при этом Ваш объект Canvas. Теперь Surface перерисуется в соответствии с оставленным Вами Canvas. Каждый раз, когда нужно перерисовать, выполняйте эту последовательность захвата (locking) и освобождения (unlocking) Canvas.
Примечание: на каждом проходе получения Canvas от SurfaceHolder будет возвращено предыдущее состояние Canvas. Чтобы правильно анимировать графику, Вы должны перерисовать всю поверхность. Например, Вы можете очистить предыдущее состояние Canvas путем заливки цветом с drawColor() или установкой фоновой картинки с drawBitmap(). Иначе Вы увидите ранее выполненные отрисовки.
[Рисуемые объекты (Drawables)]
Android предоставляет отдельную библиотеку 2D-графики для рисования фигур и картинок. В пакете android.graphics.drawable можно найти общие классы, используемые для рисования в двух измерениях. В этом разделе обсуждаются базовые основы использования объектов Drawable, чтобы рисовать графику, и как использовать связанные подклассы класса Drawable. Для дополнительной информации как делать покадровую анимацию с помощью Drawable см. [2].
Drawable является главной абстракцией для «чего-нибудь, что можно нарисовать». Вы обнаружите, что класс Drawable был расширен для определения различных видов рисуемой графики, включая BitmapDrawable, ShapeDrawable, PictureDrawable, LayerDrawable и некоторых других. Конечно, Вы также можете расширить их для того, чтобы определить собственные Drawable-объекты, которые будут работать уникальным образом.
Есть 3 способа определить и задействовать Drawable:
1. Использовать картинку, сохраненную в ресурсах проекта.
2. Использовать файл XML, который будет задавать свойства Drawable.
3. Использовать традиционные конструкторы класса.
Ниже будут обсуждаться первые две техники (использование конструкторов не представляет собой ничего нового для опытного разработчика).
[Создание графики из ресурсов картинок]
Следующие куски кода демонстрируют, как построить ImageView, использующий картинку их ресурсов drawable, и как добавить её в разметку интерфейса программы (layout).
В других случаях Вы можете обрабатывать Ваш ресурс изображения (image resource) как объект Drawable. Чтобы сделать это, создайте Drawable из ресурса примерно так:
Примечание: каждый уникальный ресурс в Вашем проекте может поддерживать только одно состояние, независимо от того, сколько разных объектов Вы создадите из него. Например, если Вы создадите два Drawable-объекта из одного и того же ресурса картинки, затем поменяете свойство (такое как alpha) для одного из этих Drawable, то это также повлияет и на другого. Поэтому когда имеете дело с несколькими экземплярами ресурса изображения, то вместо прямого трансформирования Drawable Вы должны выполнить tween animation [см. 3].
Кусок кода XML ниже показывает, как добавить ресурс Drawable к ImageView в XML layout (для забавы с некоторым красным оттенком).
Дополнительную информацию по типам ресурсов и их использованию см. в [3, 4, 5].
[Создание графики из ресурса XML]
Теперь Вы познакомились с принципами оформления интерфейса пользователя программы Android. Таким образом, Вы понимаете мощь и гибкость, свойственную определению объектов в XML. Эта философия переносится и на классы View, как и на Drawable. Если есть некий объект Drawable, который Вы хотите создать, то начальные значения свойств объекта можно задать не только в коде приложения через переменные, но и в путем определения Drawable в XML, что является хорошим решением. Даже если Вы ожидаете, что Ваш Drawable изменит свои свойства в результате взаимодействия с пользователем в приложении, Вы должны рассмотреть определение объекта в XML, поскольку в дальнейшем Вы все равно можете менять его свойства после создания экземпляра объекта.
Вот пример файла XML, который определяет TransitionDrawable:
С этим XML, сохраненным в файл res/drawable/expand_collapse.xml, следующий код создает экземпляр TransitionDrawable и устанавливает его как содержимое ImageView:
Затем этот переход (transition) может быть запущен вперед (на одну секунду):
Дополнительную информацию по поддерживаемым атрибутом вышеперечисленных классов Drawable см. в их документации.
[Рисуемая фигура (Shape Drawable)]
Когда Вам нужно динамически нарисовать какую-нибудь двухмерную графику, то возможно объект ShapeDrawable то, что Вам нужно. С ShapeDrawable, Вы можете программно рисовать примитивные фигуры и задать им всевозможные стили.
ShapeDrawable является расширением от Drawable, так что его можно использовать везде, где ожидается Drawable — возможно для заднего фона View, что можно сделать вызовом setBackgroundDrawable(). Конечно, Вы также можете рисовать фигуры и использовать их как custom View, чтобы добавить в разметку интерфейса приложения (layout) так, как пожелаете. Поскольку ShapeDrawable имеет собственный метод draw(), Вы можете создать подкласс View, который рисует ShapeDrawable в методе View.onDraw(). Здесь приведен базовый пример расширения класса View, который рисует ShapeDrawable как View:
В конструкторе ShapeDrawable задан как OvalShape. Затем устанавливается цвет и границы фигуры. Если Вы не установите границы, то фигура не будет нарисована, и если не установите цвет, то по по умолчанию фигура будет черной.
С заданным custom View он может быть отрисован любым способом, который Вам нравится. Вышеприведенный пример фигуры может быть отрисован программно в Activity:
Если Вы хотите рисовать этот пользовательский рисунок из XML вместо того, чтобы это делать в из Activity, то класс CustomDrawable должен перезадать конструктор View(Context, AttributeSet), который вызывается при создании объекта, заданного из XML. Затем добавьте элемент CustomDrawable в XML, примерно так:
Класс ShapeDrawable (как и многие другие типы Drawable в пакете the android.graphics.drawable) позволяют Вам задать различные свойства рисуемых фигур через публичные методы. Вы можете захотеть подстроить некоторые свойства, включая alpha transparency (прозрачность), color filter (фильтрация цвета), dither (дизеринг), opacity (непрозрачность) и цвет.
Вы также можете с использование XML задать примитивные отрисованные фигуры. Для дополнительной информации см. [3], описание типа ресурса Shape Drawable.
[Nine-patch]
Бордюр используется для задания растягиваемой и статической областей картинки. Вы показываете растягиваемую секцию путем рисования одной (или большего количества) 1-пиксельной по толщине линии (или линий) в левой и верхней части бордюра (другие пикселы бордюра должны быть полностью прозрачными или белыми). Вы можете иметь столько растягиваемых секций, сколько захотите: их относительные размеры останутся теми же самыми, так что самые большие секции так и останутся самыми большими.
Вы также можете определить опциональную drawable-секцию изображения (обычно для дополнительных строк, padding lines) путем рисования линии справа и внизу. Если объект View установит NinePatch в качестве фона (background) и затем укажет свой текст, то он View сам растянется так, чтобы текст уместился в обозначенные линиями области справа и внизу (если эти линии есть). Если padding lines не заданы, то Android будет использовать линии слева и вверху для определения рисуемой области.
Чтобы отличать линии для разных целей, линии слева и вверху задают пикселы картинки, которыми разрешено реплицировать картинку при её растягивании. Линии внизу и справа задают относительную область, в котором должно находиться содержимое.
Вот пример файла NinePatch для определения кнопки:
Этот NinePatch задает одну растягиваемую область с левой и верхней линиями, и рисуемую область нижней и правой линиями. На верхней картинке серым пунктиром показаны регионы картинки, которые будут реплицированы при растягивании изображения. Розовый прямоугольник на нижней картинке показывает область, в которой разрешено размещение содержимого View. Если содержимое не поместится в этот регион, то изображение будет растянуто, пока содержимое не поместится.
Инструмент Draw 9-patch tool предоставляет очень удобный путь для создания изображений NinePatch, используя редактор WYSIWYG. Он даже выдает предупреждения, если заданный Вами регион для растягиваемой области создает риск для создания артефактов в результате реплицирования пикселов.
Здесь приведен пример layout XML, который демонстрирует, как добавить картинку NinePatch для набора кнопок (картинка NinePatch сохранена в файл res/drawable/my_button_background.9.png).
Обратите внимание, что ширина width и высота height установлены в значение «wrap_content» для того, чтобы кнопка по размеру подходила содержащемуся в ней тексту. Ниже показано, как выглядят две кнопки, которые отрисованы из XML и картинки NinePatch, показанной выше. Обратите внимание, как ширина и высота кнопки меняются в зависимости от текста, и как растягивается фоновая картинка, чтобы разместить текст.