Grafika w sekcji Utwórz

Wiele aplikacji musi być w stanie dokładnie kontrolować to, co jest ekranu. Może to być na przykład umieszczenie pudełka lub okręgu na ekranie w odpowiednim miejscu. Może to też być skomplikowana grafika w różnych stylach.

Podstawowy rysunek z modyfikatorami i DrawScope

Podstawowym sposobem rysowania niestandardowych elementów w Compose są modyfikatory, takie jak Modifier.drawWithContent Modifier.drawBehind i Modifier.drawWithCache.

Aby na przykład narysować coś w tle swojego utworu kompozycyjnego, możesz użyć funkcji Modyfikator drawBehind, który umożliwia rozpoczęcie wykonywania poleceń rysowania:

Spacer(
    modifier = Modifier
        .fillMaxSize()
        .drawBehind {
            // this = DrawScope
        }
)

Jeśli potrzebujesz tylko narzędzia kompozycyjnego do rysowania, możesz użyć Canvas kompozycyjne. Funkcja kompozycyjna Canvas to wokół Modifier.drawBehind. umieszczasz: Canvas w: układ był taki sam jak w przypadku każdego innego elementu interfejsu Utwórz. W ciągu Canvas, możesz rysować elementy, zachowując ich dokładną kontrolę nad ich stylem lokalizacji.

Wszystkie modyfikatory rysowania udostępniają DrawScope – środowisko rysowania o zakresie która zachowuje własny stan. Umożliwia to ustawienie parametrów dla grupy elementów graficznych. DrawScope zawiera kilka przydatnych pól, takich jak size, obiekt Size określający bieżące wymiary obiektu DrawScope.

Aby coś narysować, możesz użyć jednej z wielu funkcji rysowania w przeglądarce DrawScope. Dla: poniższy kod spowoduje narysowanie prostokąta w lewym górnym rogu ekran:

Canvas(modifier = Modifier.fillMaxSize()) {
    val canvasQuadrantSize = size / 2F
    drawRect(
        color = Color.Magenta,
        size = canvasQuadrantSize
    )
}

Różowy prostokąt na białym tle, który zajmuje jedną czwartą ekranu
Rysunek 1. Prostokąt narysowany w Canvas w funkcji tworzenia wiadomości.

Więcej informacji o różnych modyfikatorach rysowania znajdziesz w artykule Modyfikatory grafiki. dokumentacji.

Układ współrzędnych

Aby narysować coś na ekranie, musisz znać przesunięcie (x i y) oraz rozmiar Twój produkt. W przypadku wielu metod rysowania w DrawScope są podawane przez wartości domyślne parametrów. Parametry domyślne ustaw element w punkcie [0, 0] obszaru roboczego i podaj domyślny size, który wypełnia cały obszar rysowania, tak jak w przykładzie powyżej – widać prostokąt jest na górze po lewej stronie. Aby dostosować rozmiar i położenie musisz poznać układ współrzędnych w funkcji Compose.

Punkt początkowy układu współrzędnych ([0,0]) znajduje się w lewym górnym rogu piksela obszar rysowania. Pozycja x rośnie, gdy przesuwa się w prawo, a y rośnie w miarę ruchu w dół.

Siatka z układem współrzędnych z lewym górnym [0, 0] i prawym dolnym [szerokość, wysokość]
Rysunek 2. Rysowanie układu współrzędnych lub siatki rysowania.

Jeśli na przykład chcesz narysować ukośną linię od prawego górnego rogu obszaru roboczego w lewym dolnym rogu, możesz użyć DrawScope.drawLine() i podaj przesunięcie czasu rozpoczęcia i zakończenia za pomocą funkcji odpowiednie pozycje x i 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
    )
}

Przekształcenia podstawowe

DrawScope oferuje przekształcenia umożliwiające zmianę miejsca lub sposobu poleceń rysowania .

Skala

Używaj DrawScope.scale() aby zwiększyć rozmiar operacji rysowania. Operacje takie jak scale() ma zastosowanie do wszystkich operacji rysowania w ramach danej funkcji lambda. Dla: przykład: ten kod zwiększa scaleX 10 razy i scaleY 15 razy:

Canvas(modifier = Modifier.fillMaxSize()) {
    scale(scaleX = 10f, scaleY = 15f) {
        drawCircle(Color.Blue, radius = 20.dp.toPx())
    }
}

Okrąg skalowany nierównomiernie
Rysunek 3. Zastosowanie operacji skalowania do okręgu w Canvas.

Przetłumacz

Używaj DrawScope.translate() możesz przesuwać elementy rysowania w górę, w dół, w lewo lub w prawo. Na przykład parametr ten kod przesuwa rysunek o 100 pikseli w prawo i o 300 pikseli w górę:

Canvas(modifier = Modifier.fillMaxSize()) {
    translate(left = 100f, top = -300f) {
        drawCircle(Color.Blue, radius = 200.dp.toPx())
    }
}

Okrąg, który przesunął się poza środek
Rysunek 4. Stosuję operację tłumaczenia do okręgu w Canvas.

Obróć

Używaj DrawScope.rotate() aby obrócić operacje rysowania wokół punktu obrotu. Na przykład parametr ten kod obraca prostokąt o 45 stopni:

Canvas(modifier = Modifier.fillMaxSize()) {
    rotate(degrees = 45F) {
        drawRect(
            color = Color.Gray,
            topLeft = Offset(x = size.width / 3F, y = size.height / 3F),
            size = size / 3F
        )
    }
}

Telefon z prostokątem obróconym na środku ekranu o 45 stopni
Rysunek 5. Użyjemy funkcji rotate(), by zastosować obrót do bieżącego zakresu rysowania, który powoduje obrót prostokąta o 45 stopni.

Odcięcie

Użyj DrawScope.inset(), aby dostosować domyślne parametry bieżącego DrawScope, zmienianie granic rysowania i tłumaczenie rysunków odpowiednio:

Canvas(modifier = Modifier.fillMaxSize()) {
    val canvasQuadrantSize = size / 2F
    inset(horizontal = 50f, vertical = 30f) {
        drawRect(color = Color.Green, size = canvasQuadrantSize)
    }
}

Ten kod dodaje dopełnienie do poleceń rysowania:

Prostokąt wyściełany dookoła
Rysunek 6. Stosuję wstawki do poleceń rysowania.

Wiele przekształceń

Aby zastosować wiele przekształceń do rysunków, użyj funkcji funkcji DrawScope.withTransform(), która tworzy i pozwala zastosować jedno przekształcenie, które łączy wszystkie pożądane zmiany. Zastosowanie Funkcja withTransform() jest skuteczniejsza niż wykonywanie zagnieżdżonych wywołań do poszczególnych transformacji, ponieważ wszystkie przekształcenia są wykonywane razem zamiast jednej operacji, zamiast tworzyć i zapisywać przekształceń zagnieżdżonych.

Na przykład ten kod stosuje zarówno translację, jak i obrót do prostokąt:

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
        )
    }
}

Telefon z obróconym prostokątem przesuniętym w bok ekranu
Rysunek 7. Użyj funkcji withTransform, aby zastosować obrót i przesunięcie, obracając prostokąt i przesuwając go w lewo.

Typowe operacje rysowania

Narysuj tekst

Do rysowania tekstu w funkcji tworzenia wiadomości zwykle możesz użyć funkcji kompozycyjnej Text. Pamiętaj jednak: jeśli używasz języka DrawScope lub chcesz narysować tekst ręcznie możesz użyć funkcji DrawScope.drawText(). .

Aby narysować tekst, utwórz TextMeasurer przy użyciu elementu rememberTextMeasurer i wywołaj polecenie drawText z miernikiem:

val textMeasurer = rememberTextMeasurer()

Canvas(modifier = Modifier.fillMaxSize()) {
    drawText(textMeasurer, "Hello")
}

Wyświetla powitanie narysowane w Canvas
Rysunek 8. Narysowany tekst w Canvas.

Zmierz tekst

Rysowanie tekstu działa trochę inaczej niż pozostałe polecenia do rysowania. Normalnie podaj w poleceniu rysowania rozmiar (szerokość i wysokość), według którego będzie rysowany kształt/obraz. W przypadku tekstu rozmiar renderowanej reklamy zależy od kilku parametrów. takich jak rozmiar i czcionka, ligatury czy odstępy między literami.

Aby uzyskać dostęp do zmierzonych wyników, możesz użyć opcji TextMeasurer wielkości tekstu w zależności od powyższych czynników. Jeśli chcesz narysować tło za tekstem, możesz użyć zmierzonych informacji, aby poznać rozmiar obszar, który zajmuje tekst:

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()
)

Ten fragment kodu powoduje wyświetlanie różowego tła w tekście:

Tekst wielowierszowy zajmujący 2⁄3 całego obszaru z prostokątem tła
Rysunek 9. Tekst wielowierszowy, który zajmuje 2⁄3 pełnego obszaru, z prostokątem tła.

Dostosowanie ograniczeń, rozmiaru czcionki lub innych właściwości, które mają wpływ na mierzony rozmiar powoduje wygenerowanie nowego rozmiaru. Możesz ustawić stały rozmiar zarówno dla: width, i height, a tekst – tak jak w polu TextOverflow. Dla: na przykład następujący kod renderuje tekst w 1⁄3 wysokości i 1⁄3 szerokości obszaru kompozycyjnego i ustawia TextOverflow na 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()
)

Tekst jest teraz rysowany w ograniczeniach z wielokropkiem na końcu:

Tekst narysowany na różowym tle z wycinaniem wielokropka.
Rysunek 10. TextOverflow.Ellipsis ze stałymi ograniczeniami dotyczącymi pomiaru tekstu.
.

Narysuj obraz

Aby narysować wzór ImageBitmap przy użyciu: DrawScope, wczytaj obraz za pomocą ImageBitmap.imageResource(), a następnie zadzwoń pod numer drawImage:

val dogImage = ImageBitmap.imageResource(id = R.drawable.dog)

Canvas(modifier = Modifier.fillMaxSize(), onDraw = {
    drawImage(dogImage)
})

Obraz psa narysowany w Canvas
Rysunek 11. Rysunek ImageBitmap w Canvas.
.

Narysuj kształty podstawowe

W DrawScope jest wiele funkcji rysowania kształtów. Aby narysować kształt, użyj jednego z nich zdefiniowanych wstępnie funkcji rysowania, takich jak drawCircle:

val purpleColor = Color(0xFFBA68C8)
Canvas(
    modifier = Modifier
        .fillMaxSize()
        .padding(16.dp),
    onDraw = {
        drawCircle(purpleColor)
    }
)

Interfejs API

Wyjście

drawCircle()

narysuj okrąg

drawRect()

prostokąt do rysowania

drawRoundedRect()

narysuj zaokrąglony prostokąt

drawLine()

narysuj linię

drawOval()

narysuj owal

drawArc()

rysuj łuk

drawPoints()

remisuj punkty

Narysuj ścieżkę

Ścieżka to seria instrukcji matematycznych, których wynikiem jest jeden rysunek . DrawScope może narysować ścieżkę przy użyciu metody DrawScope.drawPath().

Załóżmy, że chcesz narysować trójkąt. Możesz wygenerować ścieżkę za pomocą funkcji takie jak lineTo() i moveTo(), korzystając z rozmiaru obszaru rysowania. Następnie wywołaj funkcję drawPath(), używając tej nowo utworzonej ścieżki, aby uzyskać trójkąt.

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()
)

Odwrócony fioletowy trójkąt ścieżki narysowany w funkcji Utwórz
Rysunek 12. Tworzę i rysuję Path w Compose.

Uzyskuję dostęp do Canvas obiektu

DrawScope nie zapewnia bezpośredniego dostępu do obiektu Canvas. Za pomocą DrawScope.drawIntoCanvas(), aby otrzymać dostępu do samego obiektu Canvas, w którym można wywoływać funkcje.

Jeśli na przykład masz niestandardowy obiekt Drawable, który chcesz narysować na możesz uzyskać dostęp do obszaru roboczego i wywołać funkcję Drawable#draw(), przekazując Obiekt 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()
)

Owalny, czarny element shapeDrawable w pełnym rozmiarze
Rysunek 13. Uzyskuję dostęp do obszaru roboczego, aby narysować Drawable.

Więcej informacji

Więcej informacji o rysowaniu w funkcji Compose znajdziesz w tych artykułach: zasoby:

. .