To ćwiczenie programowania jest częścią kursu „Android dla zaawansowanych w Kotlinie”. Korzyści z tego kursu będą dla Ciebie najbardziej wartościowe, jeśli wykonasz je w sekwencjach ćwiczeń z programowania, ale nie jest to obowiązkowe. Wszystkie ćwiczenia z kursu są wymienione na stronie Zaawansowane ćwiczenia z programowania na Androida w Kotlin.
Wstęp
Na potrzeby tych ćwiczeń z programowania przycinanie umożliwia definiowanie regionów obrazu, obszaru roboczego lub bitu obrazu, które są selektywnie rysowane lub niewidoczne na ekranie. Jednym z zadań jest zmniejszenie obrysu. Rysowanie dotyczy sytuacji, w której piksel na ekranie zostanie wyświetlony więcej niż raz, aby wyświetlić końcowy obraz. Minimalizowanie przerysowań pozwala zminimalizować liczbę pikseli lub regionów wyświetlania, co pozwala zmaksymalizować skuteczność rysowania. Możesz go też używać do tworzenia ciekawych efektów podczas projektowania i animowania interfejsu.
Gdy na przykład rysujesz stos nakładających się kart, jak pokazano poniżej, zamiast rysować całą kartę od dołu, efektywniej jest wyświetlić tylko widoczne fragmenty. "Zazwyczaj wiążą się z tym również koszty operacji przycinania, a system Android wykonuje bardzo dużo operacji rysowania.
Aby narysować tylko widoczne części kart, musisz określić region przycinania dla każdej karty. Jeśli na przykład na diagramie poniżej przycięcie jest przypisane do obrazu, wyświetli się tylko jego część.
Obszar przycinania jest zazwyczaj prostokątem, ale może to być dowolny kształt lub kombinacja kształtów, a nawet tekst. Możesz też określić, czy chcesz, aby region wewnątrz obszaru przycinania został uwzględniony lub wykluczony. Możesz na przykład utworzyć okrągły region przycinania i wyświetlać tylko okręgi poza tym okręgiem.
W tym ćwiczeniu zmierzysz różne sposoby tworzenia klipów.
Co musisz wiedzieć
Pamiętaj:
- Jak utworzyć aplikację w
Activity
i uruchomić ją przy użyciu Android Studio. - Tworzenie i rysowanie na
Canvas
- Jak utworzyć niestandardowy
View
i zastąpićonDraw()
orazonSizeChanged()
.
Czego się nauczysz
- Jak przycinać obiekty, aby narysować coś na
Canvas
. - Zapisywanie i przywracanie stanów rysowania obszaru roboczego.
- Stosowanie przekształceń do przestrzeni roboczej i tekstu.
Jakie zadania wykonasz:
- Aplikacja, która rysuje na ekranie przycięte kształty, ukazując różne sposoby przycięcia i wynik tych widocznych efektów.
- Narysujesz także tekst przetłumaczony i zniekształcony.
Aplikacja ClippingExample pokazuje, jak za pomocą kombinacji i kształtów określić, które części obszaru roboczego mają być wyświetlane w widoku. Ostateczna wersja aplikacji będzie wyglądać tak jak na zrzucie ekranu poniżej.
Będziesz tworzyć tę aplikację od zera, więc musisz skonfigurować projekt, zdefiniować wymiary i ciągi tekstowe oraz zadeklarować niektóre zmienne.
Krok 1. Utwórz projekt ClippingExample
- Utwórz projekt Kotlin o nazwie
ClippingExample
i szablon Pusta aktywność. Użyj prefiksucom.example.android
jako prefiksu nazwy pakietu. - Otwórz aplikację
MainActivity.kt
. - W metodzie
onCreate()
zastąp domyślny widok treści i ustaw jego widok na nowe wystąpienieClippedView
. To będzie Twój widok niestandardowych przykładów przycinania, który utworzysz w następnym kroku.
setContentView(ClippedView(this))
- Na tym samym poziomie co
MainActivity.kt
utwórz nowy plik i klasę Kotlin dla widoku niestandardowegoClippedView
o rozszerzeniuView
. Wpisz podpis widoczny poniżej. Pozostałe zadania będą się odbywać wClippedView
. Adnotacja@JvmOverloads
instruuje kompilatorowi Kotlin generowanie przeciążeń tej funkcji, która zastępuje wartości parametrów domyślnych.
class ClippedView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
}
Krok 2. Dodaj wymiary i zasoby typu ciąg znaków
- Określ wymiary, których będziesz używać w przyciętych widokach w nowym pliku zasobów w
res/values/dimens.xml
. Domyślne wymiary są zakodowane na stałe i mieszczą się na niewielkim ekranie.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="clipRectRight">90dp</dimen>
<dimen name="clipRectBottom">90dp</dimen>
<dimen name="clipRectTop">0dp</dimen>
<dimen name="clipRectLeft">0dp</dimen>
<dimen name="rectInset">8dp</dimen>
<dimen name="smallRectOffset">40dp</dimen>
<dimen name="circleRadius">30dp</dimen>
<dimen name="textOffset">20dp</dimen>
<dimen name="strokeWidth">4dp</dimen>
<dimen name="textSize">18sp</dimen>
</resources>
Aby aplikacja wyglądała dobrze na większym ekranie (i łatwiej ją zobaczyć), możesz utworzyć plik dimens
z większymi wartościami, który będzie stosowany tylko na większych ekranach.
- W Android Studio kliknij prawym przyciskiem myszy folder values i wybierz Nowy > Wartość plik zasobów.
- W oknie Nowy plik zasobu wywołaj plik
dimens
. W sekcji Dostępne kwalifikatory wybierz Mała szerokość ekranu i kliknij przycisk >>, aby dodać go do Kwalifikatorów wybierz. Wpisz wartość 480 w polu Mała szerokość ekranu i kliknij OK.
- Plik powinien pojawić się w folderze wartości w sposób przedstawiony poniżej.
- Jeśli nie widzisz pliku, przełącz się na widok Pliki projektów aplikacji. Pełna ścieżka do nowego pliku wygląda poniżej:
ClippingExample/app/src/main/res/values-sw480dp/dimens.xml
.
- Zastąp domyślną zawartość pliku
values-sw480dp/dimens.xml
wymiarami opisanymi poniżej.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="clipRectRight">120dp</dimen>
<dimen name="clipRectBottom">120dp</dimen>
<dimen name="rectInset">10dp</dimen>
<dimen name="smallRectOffset">50dp</dimen>
<dimen name="circleRadius">40dp</dimen>
<dimen name="textOffset">25dp</dimen>
<dimen name="strokeWidth">6dp</dimen>
</resources>
- W
strings.xml
dodaj następujące ciągi znaków. Służą one do wyświetlania tekstu w obszarze roboczym.
<string name="clipping">Clipping</string>
<string name="translated">translated text</string>
<string name="skewed">"Skewed and "</string>
Krok 3. Utwórz i zainicjuj obiekt Paint i Ścieżka
- Wróć do widoku Androida projektu.
- W
ClippedView
określ zmiennąPaint
, która ma zostać wykorzystana. Włącz antyaliasing, a także szerokość kreski i rozmiar tekstu zdefiniowane w wymiarach, jak pokazano poniżej.
private val paint = Paint().apply {
// Smooth out edges of what is drawn without affecting shape.
isAntiAlias = true
strokeWidth = resources.getDimension(R.dimen.strokeWidth)
textSize = resources.getDimension(R.dimen.textSize)
}
- W
ClippedView
utwórz i zainicjujPath
, aby przechowywać lokalnie ścieżkę narysowanego ciągu. Importuj:android.graphics.Path
.
private val path = Path()
Krok 4. Skonfiguruj kształty
W tej aplikacji wyświetlasz kilka wierszy i dwóch kolumn kształtów przyciętych na różne sposoby.
Wszystkie one mają te same cechy:
- Duży prostokąt (kwadrat), który pełni rolę kontenera
- Przekątna biegnąca wzdłuż dużego prostokąta
- Okrąg
- Krótki ciąg tekstu
Na tym etapie konfigurujesz wymiary dla tych kształtów z zasobów, więc pobierasz wymiary tylko raz.
- W
ClippedView
podpath
dodaj zmienne wymiarów prostokąta przycinania wokół całego zestawu kształtów.
private val clipRectRight = resources.getDimension(R.dimen.clipRectRight)
private val clipRectBottom = resources.getDimension(R.dimen.clipRectBottom)
private val clipRectTop = resources.getDimension(R.dimen.clipRectTop)
private val clipRectLeft = resources.getDimension(R.dimen.clipRectLeft)
- Dodaj zmienne odstępów między prostokątem a odsunięciem małego prostokąta.
private val rectInset = resources.getDimension(R.dimen.rectInset)
private val smallRectOffset = resources.getDimension(R.dimen.smallRectOffset)
- Dodaj zmienną dla promienia koła. To promień okręgu narysowanego wewnątrz prostokąta.
private val circleRadius = resources.getDimension(R.dimen.circleRadius)
- Dodaj przesunięcie i rozmiar tekstu tekstu rysowanego w ramach prostokąta.
private val textOffset = resources.getDimension(R.dimen.textOffset)
private val textSize = resources.getDimension(R.dimen.textSize)
Krok 4. Skonfiguruj lokalizacje wierszy i kolumn
Kształty tej aplikacji wyświetlają się w dwóch kolumnach i czterech wierszach na podstawie wartości skonfigurowanych powyżej wymiarów. Matematyka nie jest częścią tego ćwiczenia z programowania, ale popatrz na to, jak kopiujesz kod do tego kroku.
- Skonfiguruj współrzędne dwóch kolumn.
private val columnOne = rectInset
private val columnTwo = columnOne + rectInset + clipRectRight
- Dodaj współrzędne każdego wiersza, w tym ostatni wiersz przekształconego tekstu.
private val rowOne = rectInset
private val rowTwo = rowOne + rectInset + clipRectBottom
private val rowThree = rowTwo + rectInset + clipRectBottom
private val rowFour = rowThree + rectInset + clipRectBottom
private val textRow = rowFour + (1.5f * clipRectBottom)
- Uruchom aplikację. Aplikacja powinna się otworzyć przy pustym białym ekranie pod nazwą aplikacji.
W onDraw()
wywołujesz metody rysujące siedem różnych przyciętych prostokątów, tak jak pokazano na zrzucie ekranu poniżej aplikacji. Prostokąty są rysowane w ten sam sposób. Jedyną różnicą są zdefiniowane regiony przycinania i lokalizacji na ekranie.
Algorytm używany do rysowania prostokątów działa na diagramie i wyjaśnieniu poniżej. W skrócie rysujesz serię prostokątów, przemieszczając punkt początkowy elementu Canvas
. Trasa obejmuje takie etapy:
(1) Najpierw przetłumacz Canvas
na miejsce, w którym chcesz narysować prostokąt. Oznacza to, że zamiast obliczać miejsce, w którym trzeba narysować następny prostokąt i wszystkie pozostałe kształty, przenosisz punkt początkowy Canvas
, czyli jego układ współrzędnych.
(2) Następnie rysujesz prostokąt w nowym miejscu obszaru roboczego. Oznacza to, że kształty rysujesz w tej samej lokalizacji w przetłumaczonym systemie współrzędnych. Jest to dużo łatwiejsze i nieco skuteczniejsze.
(3) Na koniec przywróć element Canvas
do pierwotnego elementu Origin
.
Algorytm, w którym wdrożysz ten algorytm:
- W funkcji
onDraw()
wywołaj funkcję, aby wypełnić elementCanvas
szarym kolorem tła i narysować pierwotne kształty. - Wywołaj funkcję każdego przyciętego prostokąta i tekst, który chcesz narysować.
W przypadku każdego prostokąta lub tekstu:
- Zapisz bieżący stan
Canvas
, aby móc go przywrócić. - Przetłumacz
Origin
obszaru roboczego na miejsce, w którym chcesz rysować. - Zastosuj przycinanie kształtów i ścieżek.
- Narysuj prostokąt lub tekst.
- Przywróć stan
Canvas
.
Krok: Zastąp onDraw()
- Zastąp wartość
onDraw()
zgodnie z poniższym kodem. Wywołujesz funkcję dla każdego tworzonego kształtu, który wdrożysz później.
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
drawBackAndUnclippedRectangle(canvas)
drawDifferenceClippingExample(canvas)
drawCircularClippingExample(canvas)
drawIntersectionClippingExample(canvas)
drawCombinedClippingExample(canvas)
drawRoundedRectangleClippingExample(canvas)
drawOutsideClippingExample(canvas)
drawSkewedTextExample(canvas)
drawTranslatedTextExample(canvas)
// drawQuickRejectExample(canvas)
}
- Utwórz wycinki dla każdej funkcji rysowania, aby kod nadal był kompilowany. Możesz skopiować poniższy kod.
private fun drawBackAndUnclippedRectangle(canvas: Canvas){
}
private fun drawDifferenceClippingExample(canvas: Canvas){
}
private fun drawCircularClippingExample(canvas: Canvas){
}
private fun drawIntersectionClippingExample(canvas: Canvas){
}
private fun drawCombinedClippingExample(canvas: Canvas){
}
private fun drawRoundedRectangleClippingExample(canvas: Canvas){
}
private fun drawOutsideClippingExample(canvas: Canvas){
}
private fun drawTranslatedTextExample(canvas: Canvas){
}
private fun drawSkewedTextExample(canvas: Canvas){
}
private fun drawQuickRejectExample(canvas: Canvas){
}
Aplikacja rysuje ten sam prostokąt i kształty 7 razy, najpierw bez przycinania, a następnie 6 razy z różnymi ścieżkami przycinania. Metoda drawClippedRectangle()
rozróżnia kod do rysowania jednego prostokąta, jak pokazano poniżej.
Krok 1. Utwórz metodę pullClippedRectangle()
- Utwórz metodę
drawClippedRectangle()
, która przyjmuje argumentcanvas
typuCanvas
.
private fun drawClippedRectangle(canvas: Canvas) {
}
- W metodzie
drawClippedRectangle()
ustaw granice prostokąta przycinania dla całego kształtu. Zastosuj prostokąt przycinania, który ogranicza do rysowania tylko kwadrat.
canvas.clipRect(
clipRectLeft,clipRectTop,
clipRectRight,clipRectBottom
)
Metoda Canvas.clipRect(...)
ogranicza obszar ekranu, na którym w przyszłości będą mogły zapisywać się operacje rysowania. Ustawia przycięcia na przycięcia w przecinku bieżącego prostokąta przycinania oraz prostokąta przekazywanego do clipRect()
. Jest wiele wariantów metody clipRect()
, które przyjmują różne formularze i umożliwiają wykonywanie różnych działań na prostokątnym polu przycinania.
- Wypełnij
canvas
białym kolorem. Tak. Cały obszar roboczy, ponieważ nie rysujesz prostokątów, został przycięty. Ze względu na prostokąt przycinania, tylko obszar zdefiniowany przez prostokąt zostanie przycięty, tworząc biały prostokąt. Pozostałe części powierzchni pozostaną szare.
canvas.drawColor(Color.WHITE)
- Zmień kolor na czerwony i narysuj ukośną linię wewnątrz prostokąta przycinania.
paint.color = Color.RED
canvas.drawLine(
clipRectLeft,clipRectTop,
clipRectRight,clipRectBottom,paint
)
- Ustaw kolor na zielony i narysuj okrąg wewnątrz prostokąta przycinania.
paint.color = Color.GREEN
canvas.drawCircle(
circleRadius,clipRectBottom - circleRadius,
circleRadius,paint
)
- Ustaw kolor na niebieski i narysuj tekst wyrównany do prawej krawędzi prostokąta przycinania. Użyj
canvas.drawText()
, aby narysować tekst.
paint.color = Color.BLUE
// Align the RIGHT side of the text with the origin.
paint.textSize = textSize
paint.textAlign = Paint.Align.RIGHT
canvas.drawText(
context.getString(R.string.clipping),
clipRectRight,textOffset,paint
)
Krok 2. Zaimplementuj metodę pullBackAndUnclippedRectangle()
- Aby zobaczyć, jak działa metoda
drawClippedRectangle()
, narysuj pierwszy nieprzycięty prostokąt, stosując metodędrawBackAndUnclippedRectangle()
zgodnie z opisem poniżej. Zapisz atrybutcanvas
, przetłumacz go na pierwszy wiersz i w kolumnie, rysuj, wywołując elementdrawClippedRectangle()
, a potem przywróćcanvas
poprzedni stan.
private fun drawBackAndUnclippedRectangle(canvas: Canvas){
canvas.drawColor(Color.GRAY)
canvas.save()
canvas.translate(columnOne,rowOne)
drawClippedRectangle(canvas)
canvas.restore()
}
- Uruchom aplikację. Pierwszy biały prostokąt z kółkiem, czerwoną linią i tekstem powinien być widoczny na szarym tle.
W poniższych przykładowych metodach przycinania stosujesz różne kombinacje przycinających obszarów, aby uzyskać efekt graficzny. Dowiedz się też, jak łączyć regiony przycinania, aby uzyskać odpowiedni kształt.
Każda z tych metod ma ten sam wzorzec.
- Zapisz bieżący stan obszaru roboczego:
canvas.
save(
)
Kontekst aktywności zawiera zestaw stanów rysowania. Stany rysowania składają się z bieżącej tablicy transformacji i bieżącego regionu przycinania. Możesz zapisać bieżący stan, wykonać działania, które zmienią ten stan (np. przetłumaczyć lub obrócić obszar roboczy), a następnie go przywrócić. (Uwaga: działa to jak w przypadku polecenia „&sht;stash"” w git!).
Gdy rysunek zawiera przekształcenia, łańcuchy i cofanie przekształceń poprzez ich odwrócenie jest podatne na błędy. Jeśli np. przetłumaczysz, rozciągniesz i obrócisz tekst, staje się on bardzo złożony. Zamiast tego zapisz stan obszaru roboczego, zastosuj przekształcenia, rysunki i przywróć poprzedni stan.
Możesz na przykład zdefiniować region przycinania i zapisać ten stan. Następnie przetłumacz obszar roboczy, dodaj obszar przycinania i obróć. Po zakończeniu rysowania możesz przywrócić pierwotny stan przycinania, a także kontynuować translację i przekształcenie, jak pokazano na diagramie.
- Przetłumacz punkt początkowy obszaru roboczego na współrzędne wiersza/kolumny:
canvas.
translate
()
Dużo prościej jest przenieść punkt odniesienia i narysować to samo w nowym układzie współrzędnych niż przesunąć wszystkie elementy. (Wskazówka: tej samej metody możesz używać do obracania elementów).
- Zastosuj przekształcenia do
path
(jeśli występują). - Zastosuj przycięcie:
canvas.clipPath(path)
- Narysuj kształty:
drawClippedRectangle() or drawText()
- Przywróć poprzedni stan obszaru roboczego:
canvas.restore()
Krok 1. Zaimplementuj przykład rysowania różnicy(canvaClip) (Canvas)
Dodaj kod, aby narysować drugi prostokąt. Wykorzystuje różnicę między dwoma prostokątami przycinania, aby utworzyć efekt ramki zdjęcia.
Użyj tego kodu, który umożliwia:
- Zapisz odbitkę na płótnie.
- Zamień punkt początkowy obszaru roboczego na pierwszy, drugi wiersz, na prawo od pierwszego prostokąta.
- Zastosuj 2 proste prostokąty. Operator
DIFFERENCE
odejmuje drugi prostokąt od pierwszego.
- Wywołaj metodę
drawClippedRectangle()
, by narysować zmodyfikowany obszar roboczy. - Przywróć stan obszaru roboczego.
private fun drawDifferenceClippingExample(canvas: Canvas) {
canvas.save()
// Move the origin to the right for the next rectangle.
canvas.translate(columnTwo,rowOne)
// Use the subtraction of two clipping rectangles to create a frame.
canvas.clipRect(
2 * rectInset,2 * rectInset,
clipRectRight - 2 * rectInset,
clipRectBottom - 2 * rectInset
)
// The method clipRect(float, float, float, float, Region.Op
// .DIFFERENCE) was deprecated in API level 26. The recommended
// alternative method is clipOutRect(float, float, float, float),
// which is currently available in API level 26 and higher.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O){
canvas.clipRect(
4 * rectInset,4 * rectInset,
clipRectRight - 4 * rectInset,
clipRectBottom - 4 * rectInset,
Region.Op.DIFFERENCE
)
} else {
canvas.clipOutRect(
4 * rectInset,4 * rectInset,
clipRectRight - 4 * rectInset,
clipRectBottom - 4 * rectInset
)
}
drawClippedRectangle(canvas)
canvas.restore()
}
- Uruchom aplikację, a powinna wyglądać tak.
Krok 2. Zaimplementuj przykładrysowanieCircularClipping(Canvas)
Następnie dodaj kod, aby narysować prostokąt z okrągłym obszarem przycinania utworzonym na podstawie okrągłej ścieżki. Zasadniczo usuniesz (nie rysujesz) okrąg, tym samym wyświetlając szare tło.
private fun drawCircularClippingExample(canvas: Canvas) {
canvas.save()
canvas.translate(columnOne, rowTwo)
// Clears any lines and curves from the path but unlike reset(),
// keeps the internal data structure for faster reuse.
path.rewind()
path.addCircle(
circleRadius,clipRectBottom - circleRadius,
circleRadius,Path.Direction.CCW
)
// The method clipPath(path, Region.Op.DIFFERENCE) was deprecated in
// API level 26. The recommended alternative method is
// clipOutPath(Path), which is currently available in
// API level 26 and higher.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
canvas.clipPath(path, Region.Op.DIFFERENCE)
} else {
canvas.clipOutPath(path)
}
drawClippedRectangle(canvas)
canvas.restore()
}
Krok 3. Zaimplementuj instrukcję pullIntersectionClippingExample(canvas)
Następnie dodaj kod, aby narysować przecięcie dwóch prostokątów przycinania w drugim wierszu i kolumnie.
Pamiętaj, że wygląd interfejsu może się różnić w zależności od rozdzielczości ekranu. Poeksperymentuj z wymiarem smallRectOffset
, aby zmienić rozmiar widocznego obszaru. Mniejszy smallRectOffset
oznacza większy region na ekranie.
private fun drawIntersectionClippingExample(canvas: Canvas) {
canvas.save()
canvas.translate(columnTwo,rowTwo)
canvas.clipRect(
clipRectLeft,clipRectTop,
clipRectRight - smallRectOffset,
clipRectBottom - smallRectOffset
)
// The method clipRect(float, float, float, float, Region.Op
// .INTERSECT) was deprecated in API level 26. The recommended
// alternative method is clipRect(float, float, float, float), which
// is currently available in API level 26 and higher.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
canvas.clipRect(
clipRectLeft + smallRectOffset,
clipRectTop + smallRectOffset,
clipRectRight,clipRectBottom,
Region.Op.INTERSECT
)
} else {
canvas.clipRect(
clipRectLeft + smallRectOffset,
clipRectTop + smallRectOffset,
clipRectRight,clipRectBottom
)
}
drawClippedRectangle(canvas)
canvas.restore()
}
Krok 4. Zaimplementuj rysowaniapołączonedopasowujące(na przykład)
Następnie połącz kształty, koło i prostokąt, a następnie narysuj dowolną ścieżkę, by zdefiniować region.
private fun drawCombinedClippingExample(canvas: Canvas) {
canvas.save()
canvas.translate(columnOne, rowThree)
path.rewind()
path.addCircle(
clipRectLeft + rectInset + circleRadius,
clipRectTop + circleRadius + rectInset,
circleRadius,Path.Direction.CCW
)
path.addRect(
clipRectRight / 2 - circleRadius,
clipRectTop + circleRadius + rectInset,
clipRectRight / 2 + circleRadius,
clipRectBottom - rectInset,Path.Direction.CCW
)
canvas.clipPath(path)
drawClippedRectangle(canvas)
canvas.restore()
}
Krok 5. Zaimplementuj element rysowaniaRoundedRectangleClipping(Canvas)
Następnie dodaj zaokrąglony prostokąt, który jest często używany do przycinania.
- Na najwyższym poziomie utwórz i zainicjuj zmienną prostokątną.
RectF
to klasa zawierająca współrzędne prostokąta w postaci zmiennoprzecinkowej.
private var rectF = RectF(
rectInset,
rectInset,
clipRectRight - rectInset,
clipRectBottom - rectInset
)
- Zaimplementuj funkcję
drawRoundedRectangleClippingExample()
. FunkcjaaddRoundRect()
przyjmuje prostokąty w promieniu x i y promienia narożnika i kieruje na półokrągły prostokąt.Path.Direction
określa, jak są kształtowane zamknięte kształty (np. prostokąty lub owale) podczas dodawania ich do ścieżki.CCW
oznacza ruch w lewo.
private fun drawRoundedRectangleClippingExample(canvas: Canvas) {
canvas.save()
canvas.translate(columnTwo,rowThree)
path.rewind()
path.addRoundRect(
rectF,clipRectRight / 4,
clipRectRight / 4, Path.Direction.CCW
)
canvas.clipPath(path)
drawClippedRectangle(canvas)
canvas.restore()
}
Krok 6. Zaimplementuj pullOutsideClippingExample(canvas)
Przytnij zewnętrznie wokół prostokąta, podwajając w nim odstępy prostokąta.
private fun drawOutsideClippingExample(canvas: Canvas) {
canvas.save()
canvas.translate(columnOne,rowFour)
canvas.clipRect(2 * rectInset,2 * rectInset,
clipRectRight - 2 * rectInset,
clipRectBottom - 2 * rectInset)
drawClippedRectangle(canvas)
canvas.restore()
}
Krok 7. Zaimplementuj rysowaniarysowane_teksty(przykład)
Rysowanie tekstu tak naprawdę nie różni się od innych kształtów. Możesz zastosować do niego przekształcenia. Możesz na przykład przetłumaczyć tekst, tłumacząc obszar roboczy i rysując go.
- Zaimplementuj tę funkcję poniżej.
private fun drawTranslatedTextExample(canvas: Canvas) {
canvas.save()
paint.color = Color.GREEN
// Align the RIGHT side of the text with the origin.
paint.textAlign = Paint.Align.LEFT
// Apply transformation to canvas.
canvas.translate(columnTwo,textRow)
// Draw text.
canvas.drawText(context.getString(R.string.translated),
clipRectLeft,clipRectTop,paint)
canvas.restore()
}
- Uruchom aplikację, aby zobaczyć przetłumaczony tekst.
Krok 8: Implementacja rysowaniaSkewedTextExample(canvas)
Tekst można zniekształcić. czyli zniekształcać je na różne sposoby.
- Utwórz poniższą funkcję w
ClippedView
.
private fun drawSkewedTextExample(canvas: Canvas) {
canvas.save()
paint.color = Color.YELLOW
paint.textAlign = Paint.Align.RIGHT
// Position text.
canvas.translate(columnTwo, textRow)
// Apply skew transformation.
canvas.skew(0.2f, 0.3f)
canvas.drawText(context.getString(R.string.skewed),
clipRectLeft, clipRectTop, paint)
canvas.restore()
}
- Uruchom aplikację, aby zobaczyć zniekształcony tekst przed przetłumaczonym tekstem.
Metoda quickReject()
Canvas
umożliwia sprawdzenie, czy określony prostokąt lub ścieżka znajduje się całkowicie poza aktualnie widocznymi regionami po zastosowaniu wszystkich przekształceń.
Metoda quickReject()
jest niezwykle przydatna przy tworzeniu bardziej złożonych rysunków, dlatego musisz je wykonywać tak szybko, jak to możliwe. Dzięki quickReject()
możesz skutecznie wybierać obiekty, których w ogóle nie chcesz rysować. Nie musisz pisać własnych algorytmów skrzyżowania.
- Metoda
quickReject()
zwracatrue
, jeśli prostokąt lub ścieżka w ogóle nie byłyby widoczne na ekranie. W przypadku częściowego pokrywania się musisz jeszcze samodzielnie przeprowadzić weryfikację. EdgeType
ma wartośćAA
(Antyaliasowany: krawędzie są zaokrąglane, ponieważ mogą być wygładzane), lubBW
(czarno-biały: krawędzie są zaokrąglane do najbliższej krawędzi piksela), co jest zaokrąglane do najbliższego piksela.
Istnieje kilka wersji aplikacji quickReject()
. Znajdziesz je również w dokumentacji.
| quickOdrzuć |
| quickOdrzuć |
| quickOdrzuć |
W tym ćwiczeniu będziesz rysować w nowym wierszu, pod tekstem i w części clipRect
, tak jak wcześniej.
- Najpierw wywołujesz funkcję
quickReject()
z prostokąteminClipRectangle
, który nakłada się naclipRect
.quickReject()
zwraca wartość false (fałsz),clipRect
jest wypełnione wartościąBLACK
i rysowany jest prostokątinClipRectangle
.
- Następnie zmień kod i zadzwoń do firmy
quickReject()
, używając operatoranotInClipRectangle
.quickReject()
zwraca wartość „prawda”, a poleclipRect
jest wypełnione wartościąWHITE
, a polenotInClipRectangle
nie jest rysowane.
Jeśli masz skomplikowane rysunki, możesz szybko stwierdzić, które kształty znajdują się całkowicie poza regionem przycinania, a w związku z tym konieczne może być wykonanie dodatkowych obliczeń i rysowanie, ponieważ znajdują się one w części obszaru przycinania.
Krok: eksperyment z funkcją QuickOdrzuć()
- Na najwyższym poziomie utwórz zmienną dla współrzędnych y dodatkowego wiersza.
private val rejectRow = rowFour + rectInset + 2*clipRectBottom
- Dodaj poniższą funkcję
drawQuickRejectExample()
doClippedView
. Przeczytaj ten kod, ponieważ zawiera on wszystko, co musisz wiedzieć o korzystaniu zquickReject()
.
private fun drawQuickRejectExample(canvas: Canvas) {
val inClipRectangle = RectF(clipRectRight / 2,
clipRectBottom / 2,
clipRectRight * 2,
clipRectBottom * 2)
val notInClipRectangle = RectF(RectF(clipRectRight+1,
clipRectBottom+1,
clipRectRight * 2,
clipRectBottom * 2))
canvas.save()
canvas.translate(columnOne, rejectRow)
canvas.clipRect(
clipRectLeft,clipRectTop,
clipRectRight,clipRectBottom
)
if (canvas.quickReject(
inClipRectangle, Canvas.EdgeType.AA)) {
canvas.drawColor(Color.WHITE)
}
else {
canvas.drawColor(Color.BLACK)
canvas.drawRect(inClipRectangle, paint
)
}
canvas.restore()
}
- W
onDraw()
usuń komentarz w wywołaniu metodydrawQuickRejectExample()
. - Uruchom aplikację, a pojawi się czarny prostokąt (wypełniony obszar przycinania) i części
inClipRectangle
, ponieważ te dwa prostokąty się nakładają, więcquickReject()
zwracafalse
iinClipRectangle
.
- W pliku
drawQuickRejectExample()
zmień kod w celu uruchomieniaquickReject()
–notInClipRectangle.
terazquickReject()
zwracatrue
, a region przycinania jest biały
Pobierz kod ukończonych ćwiczeń z programowania.
$ git clone https://github.com/googlecodelabs/android-kotlin-drawing-clipping
Możesz też pobrać repozytorium jako plik ZIP, rozpakować go i otworzyć w Android Studio.
Context
aktywności utrzymuje stan, który zachowuje przekształcenia i segmenty przycinania dlaCanvas
.- Użyj opcji
canvas.save()
icanvas.restore()
, aby narysować obraz i wrócić do pierwotnego stanu odbitki na płótnie. - Aby narysować wiele kształtów na płótnie, możesz obliczyć jej lokalizację lub przesunąć (przetłumaczyć) punkt początkowy powierzchni rysowania. Może on ułatwić tworzenie metod powtarzania sekwencji rysowania.
- Obszary przycinania mogą mieć dowolny kształt, kombinację kształtów lub ścieżek.
- Możesz dodawać, odejmować i nakładać na siebie regiony przycięcia, aby uzyskać dokładnie ten region, którego potrzebujesz.
- Możesz zastosować przekształcenia do tekstu, przekształcając obszar roboczy.
- Metoda
quickReject()
Canvas
umożliwia sprawdzenie, czy określony prostokąt lub ścieżka znajdują się w całości poza aktualnie widocznymi obszarami.
Kurs Udacity:
Dokumentacja dla programistów Androida:
- Klasa
Canvas
- Klasa
Bitmap
- Klasa
View
- Klasa
Paint
- Konfiguracje
Bitmap.config
- Operatory
Region.Op
- Klasa
Path
- Klasa
Canvas
- Klasa
Bitmap
- Klasa
View
- Klasa
Paint
- Konfiguracje
Bitmap.config
- Operatory
Region.Op
- Klasa
Path
- Narzędzia graficzne
android.graphics
Bitmap.Config
Canvas
konfiguracje- Odbitki na płótnie
- Do czego służy Canvas.translate()
- Omówienie funkcji()() i ()() w przypadku kontekstu Canvas
- przycinaniem
- oczekuj.
@JvmOverloads
Szczegółowe informacje o tym, jak platforma Android jest prezentowana na ekranie, znajdziesz też w serii artykułów Graphics Architecture (Architektura graficzna).
Ta sekcja zawiera listę możliwych zadań domowych dla uczniów, którzy pracują w ramach tego ćwiczenia w ramach kursu prowadzonego przez nauczyciela. To nauczyciel może wykonać te czynności:
- W razie potrzeby przypisz zadanie domowe.
- Poinformuj uczniów, jak przesyłać zadania domowe.
- Oceń projekty domowe.
Nauczyciele mogą wykorzystać te sugestie tak długo, jak chcą lub chcą, i mogą przypisać dowolne zadanie domowe.
Jeśli samodzielnie wykonujesz te ćwiczenia z programowania, możesz sprawdzić swoją wiedzę w tych zadaniach domowych.
Odpowiedz na te pytania
Pytanie 1
Jak wywoływać efektywne wykluczanie rysowania kształtów?
▢ excludeFromDrawing()
▢ quickReject()
▢ onDraw()
▢ clipRect()
Pytanie 2
Canvas.save()
i Canvas.restore()
zapiszą i przywrócą informacje?
▢ Kolor, szerokość linii itp.
▢ Tylko bieżące transformacje
▢ Bieżące przekształcenia i region przycinania
▢ Tylko obecny region przycinania
Pytanie 3
Paint.Align
określa:
▢ Jak wyrównać następujące kształty rysunku
▢ Wskazuje, skąd pochodzi tekst
▢ Kraj i miejsce przycięcia
▢ bok tekstu do wyrównania
Linki do innych ćwiczeń z programowania znajdziesz w kursie dotyczącym programowania na Androida dla zaawansowanych w Kotlin.