Android studio canvas scale

Класс Canvas

Класс android.graphics.Canvas (Холст) предоставляет методы для рисования, которые отображают графические примитивы на исходном растровом изображении. При этом надо сначала подготовить кисть (класс Paint), который позволяет указывать, как именно графические примитивы должны отображаться на растровом изображении (цвет, обводка, стиль, сглаживание шрифта и т.д.).

Android поддерживает полупрозрачность, градиентные заливки, округлённые прямоугольники и сглаживание. Из-за ограниченных ресурсов векторная графика пока что не поддерживается, вместо этого используется традиционная растровая перерисовка.

Canvas работает с пикселями, поэтому следует заботиться о конвертации единиц dp в px и наоборот при необходимости. Начало координат находится в левом верхнем углу.

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

Методы

Ниже представлены некоторые методы класса Canvas, которые что-то рисуют.

  • drawARGB()/drawRGB()/drawColor(). Заполняет холст сплошным цветом.
  • drawArc(). Рисует дугу между двумя углами внутри заданной прямоугольной области.
  • drawBitmap(). Рисует растровое изображение на холсте. Вы можете изменять внешний вид целевой картинки, указывая итоговый размер или используя матрицу для преобразования.
  • drawBitmapMesh(). Рисует изображение с использованием сетки, с помощью которой можно управлять отображением итоговой картинки, перемещая точки внутри неё.
  • drawCircle(). Рисует круг/окружность с определённым радиусом вокруг заданной точки.
  • drawLine(s)(). Рисует линию (или последовательность линий) между двумя точками.
  • drawOval(). Рисует овал на основе прямоугольной области.
  • drawPaint(). Закрашивает весь холст с помощью заданного объекта Paint.
  • drawPath(). Рисует указанный контур, используется для хранения набора графических примитивов в виде единого объекта.
  • drawPicture(). Рисует объект Picture внутри заданного прямоугольника.
  • drawPoint(). Рисует точку в заданном месте.
  • drawPosText(). Рисует текстовую строку, учитывая смещение для каждого символа.
  • drawRect(). Рисует прямоугольник.
  • drawRoundRect(). Рисует прямоугольник с закруглёнными углами.
  • drawText(). Рисует текстовую строку на холсте. Шрифт, размер, цвет и свойства отображения текста задаются в соответствующем объекте Paint.
  • drawTextOnPath(). Рисует текст, который отображается вокруг определённого контура.
  • drawVertices(). Рисует набор треугольников в виде совокупности вершинных (вертексных) точек.
  • rotate() и restore(). Вращение холста
  • Методы scale() и translate(). Изменение и перемещение координатной системы

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

Метод drawArc()

В API 21 появилась перегруженная версия метода, в котором можно указать координаты двух точек вместо RectF.

Метод drawArc() позволяет рисовать дуги и сектора. Ниже приводится код для трёх вариантов: сектор с заливкой (похож на PacMan), сектор без заливки (контур) и часть дуги:

Метод drawBitmap()

Вывести готовое изображение просто.

Метод drawCircle()

Первые два аргумента определяют координаты центра окружности/круга, следующий аргумент — её радиус в пикселах, последний — объект Paint. В зависимости от выбранного стиля кисти можно нарисовать закрашенный круг или только окружность.

Нарисуем зелёный круг.

drawLine(s)()

Простой метод — указываем начальные и конечные координаты отрезка.

Метод drawOval()

Метод drawOval() рисует овалы. Естественно, если вы зададите одинаковые размеры ширины и высоты, то получите круг/окружность.

Если вам нужно наклонить овал в ту или иную сторону, то поверните холст на требуемый угол с помощью метода rotate(). Не забудьте потом повернуть холст обратно, что следующие фигуры выводились нормально.

Повернём синий овал из предыдущего примера:

В API 21 появилась перегруженная версия метода, в котором можно указать координаты двух точек вместо RectF:

Метод drawPaint()

Метод позволяет закрасить весь холст одним цветом.

Метод drawRect()

У метода существует три перегруженные версии для рисования прямоугольника. Рассмотрим один из них:

Метод drawRoundRect()

Для рисования прямоугольников с закруглёнными углами используется метод drawRoundRect (RectF rect, float rx, float ry, Paint paint).

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

Читайте также:  Java cache для android

Реализуем три разных способа:

В API 21 появилась перегруженная версия метода, в котором можно указать координаты двух точек вместо RectF.

Метод drawPath()

Для рисования соединённых отрезков можно использовать метод drawPath(), указав в параметрах настройки для рисования и массив координат точек. Для удобства добавим в класс Draw2D новый класс Pt, который позволит быстро создать массив точек с заданными координатами. Далее настраиваем объекты для рисования и формируем путь через созданный массив. В результате получим кошкин дом.

Путь можно составлять не только из точек, но и из фигур, например, дуг. Сначала формируем дугу, добавляем её в путь при помощи метода Path.addArc(), повторяем операцию снова несколько раз, а в конце выводим окончательный вариант:

Можно нарисовать символ парашюта:

Метод drawPoint()

Простой метод для рисования точки в нужно месте указанной кистью. Для координат используются значения типа float.

Метод drawText()

С помощью метода drawText() можно выводить текст в заданной позиции. Добавим сначала несколько эффектов, чтобы казалось, что текст парит над поверхностью:

Центрируем текст

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

Но вычисление ширины текста через textBounds.width(); приводит к небольшому смещению. Лучше воспользоваться методом кисти measureText(). Тогда текст отцентрируется точнее.

Пример на Kotlin с дополнительной информацией.

Методы rotate() и restore()

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

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

Вращение происходит вокруг начальной точки холста (0, 0). Но можно также использовать перегруженную версию метода rotate(float degrees, float px, float py), в которой можно указать координаты точки поворота.

Методы scale() и translate()

Стандартная система координат начинает свой отсчёт с верхнего левого угла. Иногда, для рисования сложных фигур удобнее назначить свою систему координат. Например, для рисования циферблата часов удобнее рисовать относительно центра экрана в диапазоне от -1 до 1.

Чтобы установить свою систему координат, нужно произвести трансформацию. В следующем примере мы установим координаты в диапазоне от 0 до 10 и нарисуем график в стандартном виде из точки 0,0 в левом нижнем углу в точку 10,10 в верхнем правом углу.

Для наглядности я добавил на оси несколько точек. Следует обратить внимание, что мы задали диапазон от 0 до 10 и все размеры должны масштабироваться в новых величинах, в том числе и ширина обводки в методе setStrokeWidth(). Поэтому значения должны быть достаточно маленькими, иначе толщина обводки может просто оказаться больше самой фигуры. Кстати, в некоторых случаях с текстом и другими методами рисование масштабирование может сыграть злую шутку и дробные значения не позволят увидеть текст и некоторые линии. В этих случаях приходиться создавать цепочку преобразований, когда временно масштаб увеличивается до нормальных размеров, рисуется текст с подходящим размером шрифта, затем опять всё уменьшается и т.д. Это долгая история.

Источник

Полный список

— используем Matrix для геометрических преобразований фигур

Рисовать фигуры мы умеем, но бывает необходимость эти фигуры перемещать по экрану, поворачивать и менять их размеры. Тут нам поможет Matrix. Будем называть этот объект матрицей. Тем более, что это действительно 3х3 матрица из алгебры.

Матрица умеет выполнять четыре основные операции над фигурой:

scale – изменение размера

Рассмотрим эти возможности на примерах. Начнем с перемещения.

Перемещение

Project name: P1441_MatrixTransform
Build Target: Android 2.3.3
Application name: MatrixTransform
Package name: ru.startandroid.develop.p1441matrixtransform
Create Activity: MainActivity

В конструкторе DrawView создаем объекты matrix и path.

Читайте также:  Flash player для андроид что это такое

В onDraw очищаем path, добавляем к нему пару прямоугольников, чтобы получился крест, и выводим на экран зеленым цветом. Далее очищаем матрицу методом reset и настраиваем смещение на 300 вправо и 200 вниз методом setTranslate. Матрица настроена и готова к выполнению преобразований.

Методом transform объекта path мы выполняем преобразование этого объекта согласно переданной в этот метод матрице. Т.е. фигура path должна сместиться вправо на 300 и вниз на 200.

Включаем синий цвет и выводим измененную фигуру path на экран. На скриншоте видно, что синяя фигура смещена так, как мы и планировали.

Вот и весь алгоритм использования матрицы. Т.е. сначала мы матрицу настраиваем, а потом применяем к какой-либо фигуре и фигура трансформируется согласно настройкам этой матрицы.

Изменение размера

Перепишем класс DrawView:

Рассмотрим тот же path, что и в первом примере. Но теперь для настройки матрицы используем метод setScale. На вход ему передаем коэффициенты изменения размера в ширину (2), в высоту (2.5) и координаты точки (375, 100), относительно которой будет выполнено изменение размера.

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

Существует также вариант метода setScale, который позволяет не указывать точку. В этом случае используется точка (0,0).

Поворот

Перепишем класс DrawView:

Здесь мы в path добавляем два прямоугольника, чтобы получился крест, и рисуем мелкий круг в верхней части креста. Выводим path на экран зеленым цветом.

Далее настраиваем матрицу методом setRotate. На вход метод принимает угол (120) поворота и координаты точки (600,400), относительно которой будет выполнен поворот. Применяем матрицу к фигуре path и рисуем ее синим цветом.

Черным цветом рисуем мелкий круг в точке (600,400), относительно которой был выполнен поворот. Делаем это для наглядности результата. На скриншоте видно, что фигура повернута относительно черного кружка по часовой на 120 градусов.

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

Порядок операций

Методы set* настраивают матрицу на выполнение одной определенной трансформации. Но матрица может содержать в себе несколько трансформаций. Если возникает такая необходимость, то необходимо использовать методы pre* и post*.

Методы pre* добавляют трансформацию в самое начало списка трансформаций матрицы. Методы post* — в самый конец.

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

Рассмотрим пример. Перепишем класс DrawView:

Создаем path из одного прямоугольника и рисуем его черным цветом.

Настраиваем матрицу на поворот на 45 градусов относительно точки (400,200), а затем методом postTranslate добавляем к матрице трансформу перемещения на 500 направо. Применяем результат к path методом transform, который полученный результат поместит в объект pathDst, а path оставит прежним. Это необходимо, т.к. нам дальше еще понадобится оригинальный path. Выводим pathDst зеленым цветом.

Далее делаем все аналогично, только используем метод preTranslate, который добавит трансформу перемещения в начало матрицы. И результат выводим красным цветом.

Для наглядности выведем мелкий круг в точке (400,200), которая у нас являлась точкой поворота в методах setRotate. Эта точка, кстати, является серединой первоначального квадрата.

Как был получен зеленый квадрат? Матрица взяла черный квадрат, повернула (setRotate) его вокруг его же центра на 45 градусов и сместила (postTranslate) вправо на 500. Все примерно так и выглядит на скриншоте.

А вот красный квадрат уехал. Разбираемся. Мы также, как и в случае с зеленым квадратом, сначала попросили матрицу повернуть (setRotate) черный квадрат на 45 относительно своего центра. А вот трансформацию смещения мы добавили методом preTranslate. Т.е. она пошла в начало матрицы и выполнилась до поворота. Т.е. красный квадрат сначала был смещен на 500 вправо, а потом повернут относительно точки (400,200), которая уже вовсе не являлась его центром. И поэтому квадрат уехал вниз по часовой стрелке на 45 градусов относительно точки (400,200).

Читайте также:  Супер камера для андроид

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

Наклон

Перепишем класс DrawView:

path содержит один прямоугольник. Выводим его на экран черным цветом.

Далее настраиваем матрицу на смещение на 200 вправо. И методом postSkew настраиваем наклон. На вход ему передаем значения наклона по оси X (0), наклона по оси Y (0.5) и координаты точки, относительно которой будет выполнен наклон (300,100). Применяем матрицу к path и рисуем результат. Также для наглядности рисуем круг в точке, относительно которой был наклон.

На скриншоте это левый зеленый наклоненный квадрат. Он наклонен по оси Y с коэффициентом 0.5. Видим, что его правая (относительно точки наклона) часть ушла вниз.

Аналогично рисуем второй зеленый квадрат, но точку наклона используем другую. Тут уже видно, что при том же наклоне (0.5 по оси Y) левая часть уходит вверх.

Далее аналогично выводим два синих квадрата, но у них уже наклон идет по оси X. Видно, что нижняя часть при этом наклоняется вправо, а верхняя влево.

Несколько дополнений к наклону.

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

Разумеется, можно сразу задавать наклон по обоим осям. Просто в этом примере для упрощения мы наклоняли каждый квадрат только по какой-то одной оси.

Точка наклона может быть любой, она не должна принадлежать фигуре. Есть аналог метода setSkew, который принимает только коэффициенты наклона, а в качестве точки использует (0,0).

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

Map методы

mapRadius – даете на вход радиус (если собираетесь трансформировать круг), а метод вам вернет значение радиуса после трансформаци

mapPoints – даете массив точек, матрица выполняет над ними свои операции преобразования и возвращает вам в результате новый массив точек

mapVectors – то же, что и mapPoints, но преобразования перемещения выполнены не будут

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

Перепишем класс DrawView:

К path добавляем квадрат и выводим черным цветом.

Настраиваем преобразования матрицы. Это поворот на 45 градусов относительно центра квадрата (150,150). Затем растянем его по горизонтали на 1.2 и сожмем по вертикали на 0.8. И переместим на 200 вправо.

Применяем матрицу к path и выводим результат зеленым цветом.

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

Видим, что зеленым нарисована фигура, которая получилась из прямоугольника после преобразований, а синим – границы фигуры, которые были получены из прямоугольника методом mapRect. Т.е. mapRect сообщает нам, какие границы будут у прямоугольника после преобразований.

Операции над матрицами

set – считает настройки с переданной матрицы в нашу матрицу

setConcat – соберет преобразования из двух матриц в вашу матрицу

preConcat – добавит преобразования из переданной матрицы в начало вашей матрицы

postConcat – добавит преобразования из переданной матрицы в конец вашей матрицы

invert – настроит вашу матрицу на преобразования, обратные тем, на которые настроена переданная матрица

Мы рассмотрели почти все методы матрицы. Есть еще два интересных и полезных метода: setRectToRect и setPolyToPoly. Но по ним получилась целая простыня объяснений и я вынес их в следующий урок.

На следующем уроке:

— разбираемся с методами setRectToRect и setPolyToPoly

Присоединяйтесь к нам в Telegram:

— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.

— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Kotlin, RxJava, Dagger, Тестирование

— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня

— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме

Источник

Оцените статью