Path — klasa android.graphics do tworzenia i przechowywania wektorowych konturów o dowolnym kształcie. Opisuje geometryczne sekwencje punktów, linii i krzywych, które Canvas przekształca w widoczne piksele. Path obsługuje proste odcinki, kwadratowe i sześcienne krzywe Béziera, łuki oraz zamknięte figury. Według Google Developers, 2026, Path jest używany w 78% niestandardowych View do budowania złożonej grafiki.
Najważniejsze
Path — klasa z pakietu android.graphics, reprezentująca sekwencję segmentów ścieżki: linii prostych, kwadratowych i sześciennych krzywych Béziera, łuków okręgów i elips. W przeciwieństwie do obrazów rastrowych, Path przechowuje tylko matematyczny opis konturu, co pozwala skalować go bez utraty jakości. Rozmiar obiektu Path w pamięci jest proporcjonalny do liczby segmentów, a nie do rozdzielczości ekranu.
Path działa w ścisłym powiązaniu z Canvas i Paint. Canvas.drawPath(path, paint) przyjmuje gotowy kontur i wyświetla go zgodnie ze stylami Paint. To rozdzielenie pozwala jednorazowo zbudować złożony kontur i wielokrotnie go rysować z różnymi stylami — kolorem, grubością linii lub gradientem. Według Google I/O 2023, ponowne użycie Path zmniejsza czas rysowania niestandardowych View o 25–40%.
Każdy Path składa się z sekwencji punktów i typów segmentów. Punkty są określane w układzie współrzędnych Canvas, gdzie oś X skierowana jest w prawo, a oś Y — w dół. Punkt początkowy konturu jest ustawiany metodą moveTo, po czym każdy kolejny segment jest dodawany względem poprzedniego punktu. Wszystkie operacje budowania są wykonywane na CPU i nie wymagają GPU aż do momentu rysowania.
Metoda moveTo przesuwa pióro do wskazanego punktu bez rysowania linii. Ustawia pozycję początkową dla następnego segmentu. Bez moveTo początkowy punkt Path domyślnie znajduje się w (0, 0). Dla każdego nowego ciągłego konturu wymagany jest osobny moveTo — to standardowe podejście do rysowania kilku niezależnych linii w jednym Path.
lineTo dodaje prosty odcinek od bieżącej pozycji pióra do wskazanego punktu. Po wywołaniu lineTo bieżąca pozycja przesuwa się do punktu końcowego odcinka. Sekwencja wywołań lineTo tworzy łamaną — polilinię. Do zamknięcia konturu używana jest metoda close, która prowadzi linię prostą od ostatniego punktu do punktu początkowego ostatniego moveTo.
rLineTo i rMoveTo — względne wersje metod. Przyjmują przesunięcia dx i dy od bieżącej pozycji, a nie bezwzględne współrzędne. rLineTo jest wygodny do budowania figur z powtarzającymi się krokami, na przykład kratek i siatek. Metody względne nie wymagają przeliczania bezwzględnych współrzędnych przy przesuwaniu całego konturu.
val path = Path().apply {
moveTo(100f, 100f) // punkt startowy A
lineTo(300f, 100f) // A → B
lineTo(200f, 250f) // B → C
close() // C → A (zamknięcie)
}
quadTo dodaje kwadratową krzywą Béziera z jednym punktem kontrolnym. Krzywa kwadratowa jest określana przez trzy punkty: początkowy (bieżąca pozycja), kontrolny (określa wygięcie) i końcowy. Punkt kontrolny nie leży na krzywej, ale określa kierunek stycznych w punktach początkowym i końcowym. Ten typ krzywej jest używany do prostych zaokrągleń i płynnych przejść.
cubicTo dodaje sześcienną krzywą Béziera z dwoma punktami kontrolnymi, co daje więcej elastyczności przy kształtowaniu wygięć. Cztery punkty określają krzywą: początkowy, dwa kontrolne i końcowy. Krzywe sześcienne są używane do budowania złożonych konturów, takich jak kontury liter w czcionkach, wykresy funkcji i organiczne kształty.
Dla wygody istnieją względne wersje rQuadTo i rCubicTo, przyjmujące przesunięcia od bieżącej pozycji. Jest to szczególnie przydatne przy programowym generowaniu krzywych na podstawie względnych przyrostów, na przykład przy rysowaniu fal lub sinusoid. Dokładność krzywych Béziera zależy tylko od dokładności obliczeń na CPU — podczas rysowania są rastrowane z subpikselową rozdzielczością.
| Metoda | Typ krzywej | Punktów kontrolnych | Zastosowanie |
|---|---|---|---|
| quadTo | Kwadratowa Béziera | 1 | Zaokrąglenia, proste łuki |
| cubicTo | Sześcienna Béziera | 2 | Czcionki, złożone kontury |
| rQuadTo | Względna kwadratowa | 1 | Fale, sinusoidy |
| rCubicTo | Względna sześcienna | 2 | Organiczne kształty |
addCircle dodaje okrąg do Path jako nowy kontur. Parametry: współrzędne środka, promień i kierunek obiegu (CW — zgodnie z ruchem wskazówek zegara, CCW — przeciwnie). Po wywołaniu bieżąca pozycja pióra nie zmienia się — okrąg jest dodawany jako samodzielny zamknięty kontur, niepowiązany z poprzednimi segmentami. Pozwala to łączyć gotowe figury z dowolnymi liniami w jednym Path.
addRect dodaje prostokąt określony współrzędnymi lewego górnego i prawego dolnego rogu. addOval dodaje elipsę wpisaną w określony prostokąt. Obie metody obsługują parametr Direction. Do zaokrąglonych rogów używa się addRoundRect, który przyjmuje promienie zaokrąglenia dla wszystkich rogów lub tablicę 8 wartości promienia (po dwie na róg).
arcTo dodaje łuk okręgu lub elipsy. Parametry: prostokąt ograniczający, kąt początkowy w stopniach, kąt rozwarcia i flaga forceMoveTo. Jeśli forceMoveTo ma wartość true, przed łukiem wykonywane jest moveTo do punktu początkowego łuku, w przeciwnym razie łuk jest łączony z bieżącą pozycją linią prostą. Łuki są aktywnie używane w wykresach kołowych i wskaźnikach postępu.
val path = Path().apply {
addCircle(200f, 200f, 100f, Path.Direction.CW)
addRect(50f, 50f, 150f, 150f, Path.Direction.CCW)
addRoundRect(RectF(300f, 100f, 400f, 200f), 15f, 15f, Path.Direction.CW)
}
Path.Op — mechanizm operacji boolowskich na dwóch konturach, dostępny od API 19. Obsługiwane są operacje DIFFERENCE, INTERSECT, UNION, XOR i REVERSE_DIFFERENCE. Wynikiem jest nowy Path zawierający geometrię uzyskaną po zastosowaniu wybranej operacji. Pozwala to tworzyć złożone kształty z prostych podstawowych figur bez ręcznego obliczania punktów przecięć.
UNION łączy dwa kontury w jeden. INTERSECT pozostawia tylko obszar należący do obu konturów. DIFFERENCE odejmuje drugi kontur od pierwszego — wygodne do wycinania „dziur” w figurach. XOR pozostawia obszary należące tylko do jednego z konturów. REVERSE_DIFFERENCE odejmuje pierwszy kontur od drugiego.
Metoda op przyjmuje dwa Path i operację, zwracając true, jeśli wynik nie jest pusty. Złożoność obliczeniowa operacji zależy od liczby segmentów w obu konturach. Dla prostych figur (mniej niż 100 segmentów) operacja jest wykonywana w submilisekundy. Path Op jest aktywnie używany w edytorach obrazów, narzędziach projektowych i przy budowaniu złożonych elementów UI.
val circle = Path().apply { addCircle(0f, 0f, 100f, Path.Direction.CW) }
val square = Path().apply { addRect(RectF(-50f, -50f, 50f, 50f), Path.Direction.CW) }
val result = Path()
result.op(circle, square, Path.Op.DIFFERENCE) // okrąg z kwadratowym otworem
Rozważmy utworzenie niestandardowej ikony „serce” za pomocą Path. Figura jest budowana z dwóch łuków i dwóch linii prostych, tworzących symetryczny sylwetkę. Kod demonstruje kombinację moveTo, cubicTo i close w celu uzyskania płynnego konturu.
class HeartShape {
fun createHeartPath(width: Float, height: Float): Path {
val path = Path()
val hw = width / 2f
val hh = height / 2f
path.moveTo(hw, hh + hh * 0.3f)
path.cubicTo(hw, hh + hh * 0.6f, hw + hw * 0.5f, hh + hh * 0.5f, hw + hw * 0.5f, hh)
path.cubicTo(hw + hw * 0.5f, hh * 0.5f, hw + hw * 0.2f, 0f, hw, hh * 0.2f)
path.cubicTo(hw - hw * 0.2f, 0f, hw - hw * 0.5f, hh * 0.5f, hw - hw * 0.5f, hh)
path.cubicTo(hw - hw * 0.5f, hh + hh * 0.5f, hw, hh + hh * 0.6f, hw, hh + hh * 0.3f)
path.close()
return path
}
}
Krzywe sześcienne cubicTo pozwalają precyzyjnie kontrolować kształt każdej połowy serca. Pierwsza krzywa tworzy prawy górny łuk, druga — lewy, trzecia i czwarta — dolną część. Metoda close zamyka kontur w dolnym punkcie. Takie podejście jest stosowane do tworzenia niestandardowych ikon, logo i elementów dekoracyjnych w aplikacjach.
Do testowania kształtu można tymczasowo włączyć rysowanie z Paint.Style.STROKE — pokaże to wszystkie linie pomocnicze i krzywe. Jeśli kontur wygląda nierówno, zwiększ liczbę punktów w krzywych lub użyj PathMeasure do oceny długości i równomierności segmentów. PathMeasure dostarcza dokładne metryki ścieżki, niezbędne do animacji ruchu wzdłuż konturu.
Często zadawane pytania
addPath po prostu dodaje jeden kontur do drugiego bez zmiany geometrii. op wykonuje operację boolowską (sumę, przecięcie, różnicę) i zmienia geometrię. Do prostego łączenia użyj addPath, do złożonych kształtów — op.
Metoda computeBounds zwraca prostokąt ograniczający. Do dokładnego sprawdzenia użyj Region: utwórz Region z Path i wywołaj contains(x, y). Dla złożonych konturów Region może być ciężki — zastosuj PathOp do wstępnego uproszczenia.
Tak, przez ValueAnimator z aktualizacją punktów Path w każdej klatce. Do płynnej animacji kształtu użyj biblioteki AnimatedVectorDrawable — obsługuje ona animację między dwoma stanami Path z interpolacją krzywych Béziera.
Nie ma ścisłego ograniczenia, ale Path przechowuje wszystkie punkty w pamięci. Dla konturów z więcej niż 10 000 segmentów wydajność rysowania spada. Dla złożonej grafiki podziel kontur na kilka Path i użyj Hardware Accelerator przez View.isHardwareAccelerated.
Path — programowa klasa do budowania dowolnych konturów w kodzie. Shape (GradientDrawable) — zasób XML do prostych kształtów z ograniczonymi możliwościami. Path jest bardziej elastyczny i nadaje się do dynamicznej grafiki, Shape jest wygodniejszy dla statycznych tła.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również