Grafika w sekcji Utwórz

Wiele aplikacji musi mieć możliwość precyzyjnego kontrolowania tego, co jest wyświetlane na ekranie. 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

Głównym sposobem tworzenia elementów niestandardowych w sekcji Komponowanie jest używanie modyfikatorów, takich jak Modifier.drawWithContent, Modifier.drawBehindModifier.drawWithCache.

Aby na przykład narysować coś za kompozycją, możesz użyć modyfikatora drawBehind, aby rozpocząć wykonywanie poleceń rysowania:

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

Jeśli potrzebujesz tylko kompozytowalnej funkcji, która rysuje, możesz użyć kompozytowalnej funkcji Canvas. Komponent Canvas to wygodna szata dla Modifier.drawBehind. Umieść Canvas w swoim układzie tak samo jak dowolny inny element interfejsu tworzenia wiadomości. 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. Obiekt DrawScope zawiera kilka przydatnych pól, takich jak size, oraz obiekt Size określający bieżące wymiary obiektu DrawScope.

Aby coś narysować, możesz użyć jednej z wielu funkcji rysowania w 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 dokumentacji Modyfikatory grafiki.

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 obiekcie DrawScope pozycja i rozmiar są podawane przez domyślne wartości parametrów. Parametry domyślne zwykle umieszczają element w miejscu [0, 0] na kanwie i zapewniają domyślną wartość size, która wypełnia całą powierzchnię rysunku, jak w przykładzie powyżej – prostokąt jest umieszczony w lewym górnym rogu. Aby dostosować rozmiar i położenie elementu, musisz zrozumieć system współrzędnych w Compose.

Punkt początkowy układu współrzędnych ([0,0]) znajduje się w lewym górnym rogu piksela obszar rysowania. Wartość x rośnie, gdy przesuwasz ją w prawo, a wartość y – gdy przesuwasz ją 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 / siatki rysunkowej.

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żyj parametru 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 niejednolicie powiększony
Rysunek 3. Zastosowanie operacji skalowania do okręgu w Canvas.

Przetłumacz

Użyj DrawScope.translate() możesz przesuwać elementy rysowania w górę, w dół, w lewo lub w prawo. Na przykład kod poniżej 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 przesunięty poza środek
Rysunek 4. Stosuję operację tłumaczenia do okręgu w Canvas.

Obróć

Użyj opcji DrawScope.rotate(), aby obracać rysunek 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 wypełnienie do poleceń rysowania:

Prostokąt z dodatkową przestrzenią wokół
Rysunek 6. Stosowanie wstawienia do wewnątrz 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. Użycie funkcji withTransform() jest wydajniejsze niż wywoływanie zagnieżdżonych funkcji w przypadku poszczególnych przekształceń, ponieważ wszystkie przekształcenia są wykonywane razem w ramach pojedynczej operacji, a nie wymagają obliczania i zapisywania przez funkcję Compose poszczególnych zagnieżdżonych przekształceń.

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 withTransform, aby zastosować zarówno obrót, jak i translację, obracając prostokąt i przesuwając go w lewo.

Typowe operacje rysowania

Rysowanie tekstu

Do rysowania tekstu w funkcji tworzenia wiadomości zwykle możesz użyć funkcji kompozycyjnej Text. Jeśli jednak korzystasz z poziomu DrawScope lub chcesz ręcznie narysować tekst z użyciem funkcji dostosowywania, możesz użyć metody DrawScope.drawText().

Aby narysować tekst, utwórz obiekt TextMeasurer za pomocą obiektu rememberTextMeasureri wywołaj funkcję drawText z użyciem narzędzia do pomiaru:

val textMeasurer = rememberTextMeasurer()

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

Wyświetla powitanie narysowane w Canvas
Rysunek 8. Rysowanie tekstu w Canvas.

Zmierz tekst

Rysowanie tekstu działa nieco inaczej niż inne polecenia rysowania. Zazwyczaj podajesz polecenie rysowania rozmiar (szerokość i wysokość), aby narysować kształt lub 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świetlenie różowego tła tekstu:

Tekst wielowierszowy zajmujący ⅔ pełnej powierzchni z kwadratowym tłem
Rysunek 9. Tekst wielowierszowy, który zajmuje 2⁄3 pełnego obszaru, z prostokątem tła.

Zmiana ograniczeń, rozmiaru czcionki lub dowolnej właściwości wpływającej na zmierzony rozmiar powoduje zgłoszenie nowego rozmiaru. Możesz ustawić stały rozmiar zarówno dla: width, i height, a tekst – tak jak w polu TextOverflow. Na przykład poniższy kod renderuje tekst na wysokości ⅓ i szerokości ⅓ obszaru kompozycyjnego oraz ustawia wartość 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 na różowym tle z trójkropkiem.
Rysunek 10. TextOverflow.Ellipsis z ograniczeniami dotyczącymi pomiaru tekstu.

Rysowanie obrazu

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 przedstawiający psa namalowany na płótnie
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 jednej z wstępnie zdefiniowanych funkcji rysowania, takich jak drawCircle:

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

Interfejs API

Urządzenie wyjściowe

drawCircle()

narysuj okrąg

drawRect()

prostokąt do rysowania

drawRoundedRect()

draw rounded rect

drawLine()

rysowanie linii

drawOval()

narysuj owal

drawArc()

rysowanie łuku

drawPoints()

remisuj punkty

Narysuj ścieżkę

Ścieżka to seria instrukcji matematycznych, która po wykonaniu tworzy rysunek. DrawScope może narysować ścieżkę za pomocą 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 trójkąt fioletowej ścieżki na ekranie tworzenia
Rysunek 12. Tworzenie i rysowanie Path w Compose.

Dostęp do obiektu Canvas

DrawScope nie zapewnia bezpośredniego dostępu do obiektu Canvas. Możesz użyć DrawScope.drawIntoCanvas(), aby uzyskać dostęp do obiektu Canvas, którego możesz używać do wywoływania funkcji.

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

Czarny owalny ShapeDrawable w pełnym rozmiarze
Rysunek 13. Dostęp do obszaru roboczego w celu narysowania Drawable.

Więcej informacji

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

. .