Многим приложениям необходимо точно контролировать, что именно отображается на экране. Это может быть как простой прямоугольник или круг, расположенный в нужном месте экрана, так и сложная композиция из графических элементов разных стилей.
Простой рисунок с модификаторами и DrawScope
Основной способ нарисовать что-то в Compose – использовать модификаторы, например Modifier.drawWithContent, Modifier.drawBehind и Modifier.drawWithCache.
Например, чтобы нарисовать что-то за вашей composable-функцией, можно использовать модификатор drawBehind, чтобы начать выполнение команд рисования:
Spacer( modifier = Modifier .fillMaxSize() .drawBehind { // this = DrawScope } )
Если вам нужен только отрисовываемый компонент, используйте компонент Canvas. Компонуемый элемент Canvas – это удобная оболочка для Modifier.drawBehind. Вы размещаете Canvas в макете так же, как и любой другой элемент интерфейса Compose. Внутри элемента Canvas можно рисовать элементы, точно управляя их стилем и местоположением.
Все модификаторы рисования предоставляют DrawScope – область рисования, которая поддерживает собственное состояние. Это позволяет задавать параметры для группы графических элементов. Объект DrawScope содержит несколько полезных полей, например size и объект Size, в котором указаны текущие размеры объекта DrawScope.
Чтобы нарисовать что-нибудь, используйте одну из многочисленных функций рисования на DrawScope. Например, следующий код рисует прямоугольник в левом верхнем углу экрана:
Canvas(modifier = Modifier.fillMaxSize()) { val canvasQuadrantSize = size / 2F drawRect( color = Color.Magenta, size = canvasQuadrantSize ) }
Подробнее о различных модификаторах рисования можно узнать из документации по модификаторам графики.
Система координат
Чтобы нарисовать что-либо на экране, вам нужно знать смещение (x и y) и размер объекта. Во многих методах рисования в DrawScope положение и размер задаются значениями параметров по умолчанию. Параметры по умолчанию обычно размещают объект в точке [0, 0] на холсте и задают размер size, который заполняет всю область рисования, как в примере выше. Вы можете видеть, что прямоугольник расположен в левом верхнем углу. Чтобы настроить размер и положение элемента, необходимо понимать систему координат в Compose.
Начало координат ([0,0]) находится в верхнем левом пикселе области рисования. x увеличивается при движении вправо, а y – при движении вниз.
Например, если вы хотите нарисовать диагональную линию из правого верхнего угла области холста в левый нижний, вы можете использовать функцию DrawScope.drawLine() и указать смещение начала и конца с соответствующими позициями x и y:
Canvas(modifier = Modifier.fillMaxSize()) { val canvasWidth = size.width val canvasHeight = size.height drawLine( start = Offset(x = canvasWidth, y = 0f), end = Offset(x = 0f, y = canvasHeight), color = Color.Blue ) }
Основные преобразования
DrawScope предлагает преобразования, позволяющие изменить место или способ выполнения команд рисования.
Масштаб
Используйте функцию
DrawScope.scale(),
чтобы увеличить размер операций рисования в несколько раз. Такие операции, как scale(), применяются ко всем операциям рисования в соответствующей лямбда-функции. Например, следующий код увеличивает значение параметра scaleX в 10 раз, а параметра scaleY – в 15 раз:
Canvas(modifier = Modifier.fillMaxSize()) { scale(scaleX = 10f, scaleY = 15f) { drawCircle(Color.Blue, radius = 20.dp.toPx()) } }
Перевести
Используйте клавиши со стрелками DrawScope.translate(), чтобы перемещать элементы рисунка вверх, вниз, влево или вправо. Например, следующий код перемещает изображение на 100 пикселей вправо и на 300 пикселей вверх:
Canvas(modifier = Modifier.fillMaxSize()) { translate(left = 100f, top = -300f) { drawCircle(Color.Blue, radius = 200.dp.toPx()) } }
Повернуть
Используйте функцию DrawScope.rotate(), чтобы поворачивать элементы рисунка вокруг точки привязки. Например, следующий код поворачивает прямоугольник на 45 градусов:
Canvas(modifier = Modifier.fillMaxSize()) { rotate(degrees = 45F) { drawRect( color = Color.Gray, topLeft = Offset(x = size.width / 3F, y = size.height / 3F), size = size / 3F ) } }
rotate(), чтобы применить поворот к текущей области рисования, которая поворачивает прямоугольник на 45 градусов.
Отступ
Используйте DrawScope.inset(), чтобы изменить параметры текущего DrawScope, скорректировав границы рисунка и соответствующим образом переместив его:
Canvas(modifier = Modifier.fillMaxSize()) { val canvasQuadrantSize = size / 2F inset(horizontal = 50f, vertical = 30f) { drawRect(color = Color.Green, size = canvasQuadrantSize) } }
Этот код добавляет поля к командам рисования:
Несколько преобразований
Чтобы применить к рисункам несколько преобразований, используйте функцию DrawScope.withTransform(), которая создает и применяет одно преобразование, объединяющее все нужные изменения. Использование функции
withTransform() эффективнее, чем вложенные вызовы отдельных преобразований, поскольку все преобразования выполняются вместе в рамках одной операции, а не по отдельности, как при вложенных преобразованиях.
Например, в следующем коде к прямоугольнику применяются и сдвиг, и поворот:
Canvas(modifier = Modifier.fillMaxSize()) { withTransform({ translate(left = size.width / 5F) rotate(degrees = 45F) }) { drawRect( color = Color.Gray, topLeft = Offset(x = size.width / 3F, y = size.height / 3F), size = size / 3F ) } }
withTransform, чтобы применить и поворот, и сдвиг, повернув прямоугольник и сдвинув его влево.Основные операции рисования
Нарисовать текст
Чтобы нарисовать текст в Compose, обычно используется компонуемый элемент Text. Однако если вы находитесь в DrawScope или хотите нарисовать текст вручную с настройками, можно использовать метод DrawScope.drawText().
Чтобы нарисовать текст, создайте TextMeasurer, используя rememberTextMeasurer, и вызовите drawText с помощью измерителя:
val textMeasurer = rememberTextMeasurer() Canvas(modifier = Modifier.fillMaxSize()) { drawText(textMeasurer, "Hello") }
Как измерить текст
Ввод текста отличается от других команд рисования. Обычно в команде рисования указывается размер (ширина и высота) фигуры или изображения. При работе с текстом есть несколько параметров, которые влияют на размер отображаемого текста, например размер шрифта, шрифт, лигатуры и межбуквенный интервал.
В Compose можно использовать TextMeasurer, чтобы получить доступ к измеренному размеру текста с учетом перечисленных выше факторов. Если вы хотите нарисовать фон за текстом, то можете использовать полученные данные, чтобы определить размер области, которую занимает текст:
val textMeasurer = rememberTextMeasurer() Spacer( modifier = Modifier .drawWithCache { val measuredText = textMeasurer.measure( AnnotatedString(longTextSample), constraints = Constraints.fixedWidth((size.width * 2f / 3f).toInt()), style = TextStyle(fontSize = 18.sp) ) onDrawBehind { drawRect(pinkColor, size = measuredText.size.toSize()) drawText(measuredText) } } .fillMaxSize() )
Этот фрагмент кода создает розовый фон для текста:
Если изменить ограничения, размер шрифта или любое другое свойство, влияющее на размер, будет сообщен новый размер. Вы можете задать фиксированный размер для width и height, а текст будет соответствовать заданному TextOverflow. Например, следующий код отрисовывает текст, занимающий треть высоты и треть ширины области, и задает для TextOverflow значение TextOverflow.Ellipsis:
val textMeasurer = rememberTextMeasurer() Spacer( modifier = Modifier .drawWithCache { val measuredText = textMeasurer.measure( AnnotatedString(longTextSample), constraints = Constraints.fixed( width = (size.width / 3f).toInt(), height = (size.height / 3f).toInt() ), overflow = TextOverflow.Ellipsis, style = TextStyle(fontSize = 18.sp) ) onDrawBehind { drawRect(pinkColor, size = measuredText.size.toSize()) drawText(measuredText) } } .fillMaxSize() )
Теперь текст отображается в заданных границах, а в конце стоит многоточие:
TextOverflow.Ellipsis с фиксированными ограничениями на измерение текста.Создание изображений
Чтобы нарисовать ImageBitmap с помощью DrawScope, загрузите изображение, используя ImageBitmap.imageResource(), а затем вызовите drawImage:
val dogImage = ImageBitmap.imageResource(id = R.drawable.dog) Canvas(modifier = Modifier.fillMaxSize(), onDraw = { drawImage(dogImage) })
ImageBitmap на холсте.Как рисовать простые фигуры
На устройстве DrawScope есть много функций для рисования фигур. Чтобы нарисовать фигуру, используйте одну из стандартных функций рисования, например drawCircle:
val purpleColor = Color(0xFFBA68C8) Canvas( modifier = Modifier .fillMaxSize() .padding(16.dp), onDraw = { drawCircle(purpleColor) } )
API |
Результат |
|
|
|
|
|
|
|
|
|
|
|
|
|
Нарисовать путь
Путь – это последовательность математических инструкций, которые при выполнении приводят к созданию рисунка. DrawScope может нарисовать путь с помощью метода DrawScope.drawPath().
Например, вы хотите нарисовать треугольник. Вы можете создать путь с помощью таких функций, как lineTo() и moveTo(), используя размер области рисования.
Затем вызовите функцию drawPath() с новым путем, чтобы получить треугольник.
Spacer( modifier = Modifier .drawWithCache { val path = Path() path.moveTo(0f, 0f) path.lineTo(size.width / 2f, size.height / 2f) path.lineTo(size.width, 0f) path.close() onDrawBehind { drawPath(path, Color.Magenta, style = Stroke(width = 10f)) } } .fillMaxSize() )
Path в Compose.Доступ к объекту "Canvas"
В DrawScope у вас нет прямого доступа к объекту Canvas. Вы можете использовать DrawScope.drawIntoCanvas(), чтобы получить доступ к самому объекту Canvas, для которого можно вызывать функции.
Например, если вы хотите нарисовать на холсте пользовательский объект Drawable, вы можете получить доступ к холсту и вызвать метод Drawable#draw(), передав ему объект Canvas:
val drawable = ShapeDrawable(OvalShape()) Spacer( modifier = Modifier .drawWithContent { drawIntoCanvas { canvas -> drawable.setBounds(0, 0, size.width.toInt(), size.height.toInt()) drawable.draw(canvas.nativeCanvas) } } .fillMaxSize() )
Drawable.Подробнее…
Дополнительную информацию о рисовании в Compose можно найти в следующих ресурсах:
- Модификаторы графики – узнайте о различных типах модификаторов рисования.
- Кисть – узнайте, как настроить рисование контента.
- Специальные макеты и графика в Compose – Саммит для разработчиков Android 2022. Узнайте, как создавать собственный интерфейс в Compose с помощью макетов и графики.
- Пример JetLagged – пример Compose, в котором показано, как нарисовать собственную диаграмму.
Рекомендуем
- Примечание. Текст ссылки показывается, когда JavaScript отключен.
- Модификаторы графики
- Графика в режиме создания письма
- Линии выравнивания в Jetpack Compose