Многим приложениям требуется возможность точно контролировать, что именно отображается на экране. Это может быть как простое размещение прямоугольника или круга в нужном месте экрана, так и сложная композиция из графических элементов в разных стилях.
Базовое рисование с модификаторами и DrawScope
Основной способ нарисовать что-то пользовательское в Compose – использовать модификаторы, такие как
Modifier.drawWithContent,
Modifier.drawBehind и
Modifier.drawWithCache.
Например, чтобы нарисовать что-то за composable-функцией, можно использовать модификатор drawBehind, который позволяет выполнять команды рисования.
Spacer( modifier = Modifier .fillMaxSize() .drawBehind { // this = DrawScope } )
Если вам нужна только composable-функция, которая рисует, вы можете использовать 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() эффективнее, чем вложенные вызовы отдельных преобразований, поскольку все преобразования выполняются вместе за одну операцию, а не Compose, требующему вычисления и сохранения каждого из вложенных преобразований.
Например, следующий код применяет к прямоугольнику и перенос, и поворот:
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, обычно можно использовать composable-функцию 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. Например, следующий код отображает текст в ⅓ высоты и ⅓ ширины области composable-функции и устанавливает для 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 в Canvas.Рисовать основные формы
В 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. Чтобы получить доступ к объекту Canvas, для которого можно вызывать функции, используйте DrawScope.drawIntoCanvas().
Например, если у вас есть пользовательский объект 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 отключен.
- Модификаторы графики
- Графика в Compose
- Линии выравнивания в Jetpack Compose