Rysowanie na obiektach Canvas

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 urządzeniach z Androidem dostępnych jest kilka technik wdrażania niestandardowych grafiki i animacji 2D w widokach danych.

Oprócz korzystania z rysunków możesz też rysować 2D, korzystając z metod rysowania klasy Canvas. Canvas to powierzchnia rysowania 2D, która udostępnia metody rysowania. Jest to przydatne, gdy aplikacja musi regularnie rysować siebie samodzielnie, ponieważ to, co widzi użytkownik, zmienia się z czasem. Z tego modułu ćwiczeń dowiesz się, jak utworzyć i narysować obiekt canvas wyświetlany w narzędziu View.

Typy działań, które możesz wykonać na płótnie, obejmują:

  • Wypełnij cały obszar roboczy kolorem.
  • Narysuj kształty, takie jak prostokąty, łuki i ścieżki, które mają styl zgodny z obiektem Paint. Obiekt Paint zawiera informacje o stylu i kolorze określające sposób rysowania geometrii (np. linii, prostokąta, owalu i ścieżek) lub na przykład krój czcionki tekstu.
  • Zastosuj przekształcenia, takie jak transformacja, skalowanie lub przekształcenia niestandardowe.
  • Klip oznacza, że do kształtu można zastosować kształt lub ścieżkę, aby zdefiniować widoczne części.

Jak rysujesz Androida (bardzo uproszczone)

Rysowanie w Androidzie oraz w innych nowoczesnych systemach to złożony proces obejmujący warstwy abstrakcji i optymalizacje aż po sprzęt. Rysowanie Androida jest fascynującym tematem. Widać, ile zostało napisane, a szczegóły wykraczają poza zakres tego ćwiczenia.

W kontekście tego ćwiczenia z programowania i aplikacji, która rysuje na płótnie jako wyświetlacz w trybie pełnoekranowym, możesz myśleć o tym w następujący sposób.

  1. Potrzebujesz widoku, w którym chcesz rysować. Może to być jeden z widoków dostarczonych przez system Android. Możesz też utworzyć widok niestandardowy, który służy jako widok treści aplikacji (MyCanvasView).
  2. Ten widok, tak jak wszystkie widoki, ma własny obszar roboczy (canvas).
  3. Aby w najprostszy sposób rysować w obszarze roboczym widoku, zastępujesz metodę onDraw() i rysujesz na płótnie.
  4. Podczas tworzenia rysunku musisz zapisać go w pamięci podręcznej. Dane można zapisywać w pamięci podręcznej na kilka sposobów. Jednym z nich jest bitmapa (extraBitmap). Innym sposobem jest zapisanie historii narysowanych danych jako współrzędnych i instrukcji.
  5. Aby narysować mapę bitową pamięci podręcznej (extraBitmap) za pomocą interfejsu API rysowania w Canvas, utwórz obszar roboczy pamięci podręcznej (extraCanvas) do tej mapy.
  6. Następnie rysujesz obiekt canvas w pamięci podręcznej (extraCanvas), który jest rysowany do mapy bitowej pamięci podręcznej (extraBitmap).
  7. Aby wyświetlić wszystko, co widać na ekranie, poinformuj kanwę widoku (canvas) o konieczności narysowania mapy bitowej pamięci podręcznej (extraBitmap).

Co musisz wiedzieć

  • Jak utworzyć aplikację z aktywnością, podstawowym układem i uruchomić ją przy użyciu Android Studio.
  • Jak powiązać moduły obsługi zdarzeń z widokami.
  • Jak utworzyć widok niestandardowy

Czego się nauczysz

  • Jak utworzyć obiekt Canvas i rysować na nim w odpowiedzi na dotknięcia ekranu przez użytkownika.

Jakie zadania wykonasz:

  • Utwórz aplikację, która rysuje linie na ekranie w odpowiedzi na dotknięcie ekranu przez użytkownika.
  • Przechwytuje zdarzenia ruchu i w odpowiedzi rysuje linie na obszarze roboczym, które są wyświetlane na pełnym ekranie w widoku niestandardowym.

Aplikacja MiniPaint wykorzystuje widok niestandardowy, aby wyświetlać linię w odpowiedzi na dotknięcia ekranu, jak widać na zrzucie ekranu poniżej.

Krok 1. Tworzenie projektu MiniPaint

  1. Utwórz nowy projekt Kotlin o nazwie MiniPaint, który korzysta z szablonu Pusta aktywność.
  2. Otwórz plik app/res/values/colors.xml i dodaj dwa poniższe kolory.
<color name="colorBackground">#FFFF5500</color>
<color name="colorPaint">#FFFFEB3B</color>
  1. Otwórz: styles.xml
  2. W elemencie nadrzędnym danego stylu AppTheme zastąp DarkActionBar wartością NoActionBar. Spowoduje to usunięcie paska działań i rysowanie na pełnym ekranie.
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">

Krok 2. Tworzenie klasy MyCanvasView

W tym kroku utworzysz widok niestandardowy MyCanvasView do rysowania.

  1. W pakiecie app/java/com.example.android.minipaint utwórz nowy plik/klasę Kotlin o nazwie MyCanvasView.
  2. Ustaw klasę MyCanvasView jako klasę rozszerzoną View i przekaż ją w context: Context. Zaakceptuj sugerowane importy.
import android.content.Context
import android.view.View

class MyCanvasView(context: Context) : View(context) {
}

Krok 3. Ustawianie widoku MyCanvasView

Aby wyświetlić zawartość rysunku MyCanvasView, musisz ustawić ją jako widok treści MainActivity.

  1. Otwórz strings.xml i zdefiniuj ciąg znaków używany do opisu zawartości widoku danych.
<string name="canvasContentDescription">Mini Paint is a simple line drawing app.
   Drag your fingers to draw. Rotate the phone to clear.</string>
  1. Otwórz: MainActivity.kt
  2. onCreate() – usuń grupę setContentView(R.layout.activity_main).
  3. Utwórz instancję MyCanvasView.
val myCanvasView = MyCanvasView(this)
  1. Poniżej poproś o pełny ekran układu myCanvasView. Aby to zrobić, ustaw flagę SYSTEM_UI_FLAG_FULLSCREEN na stronie myCanvasView. W ten sposób cały ekran wypełnia się widokiem.
myCanvasView.systemUiVisibility = SYSTEM_UI_FLAG_FULLSCREEN
  1. Dodaj opis treści.
myCanvasView.contentDescription = getString(R.string.canvasContentDescription)
  1. Poniżej widoku widoku treści ustaw myCanvasView.
setContentView(myCanvasView)
  1. Uruchom aplikację. Pojawi się całkowicie biały ekran, ponieważ obiekt canvas nie ma rozmiaru i nie został jeszcze narysowany.

Krok 1. Zastąp onSizeChanged()

Metoda onSizeChanged() jest wywoływana przez system Android za każdym razem, gdy zmieni się rozmiar widoku. Widok zaczyna się od braku rozmiaru, więc metoda onSizeChanged() uruchamia się także po utworzeniu i zawyżeniu aktywności. Ta metoda onSizeChanged() jest więc idealnym miejscem do tworzenia i konfigurowania przestrzeni roboczej widoku.

  1. W MyCanvasView na poziomie klasy zdefiniuj zmienne dla obszaru roboczego i bitmapy. Zadzwoń do nich extraCanvas i extraBitmap. To jest Twoja bitmapa i obszar roboczy do zapisywania wcześniej zapisanych danych.
private lateinit var extraCanvas: Canvas
private lateinit var extraBitmap: Bitmap
  1. Zdefiniuj zmienną na poziomie klasy backgroundColor (kolor tła) obszaru roboczego i zainicjuj ją, wybierając colorBackground wcześniej zdefiniowany.
private val backgroundColor = ResourcesCompat.getColor(resources, R.color.colorBackground, null)
  1. W MyCanvasView zastąp metodę onSizeChanged(). Ta metoda wywołania zwrotnego jest wywoływana przez system Android ze zmienionymi wymiarami ekranu, czyli dla nowej szerokości i wysokości (aby zmienić na), a także dla starej szerokości i wysokości (aby je zmienić).
override fun onSizeChanged(width: Int, height: Int, oldWidth: Int, oldHeight: Int) {
   super.onSizeChanged(width, height, oldWidth, oldHeight)
}
  1. W onSizeChanged() utwórz instancję Bitmap o nowej szerokości i wysokości, która odpowiada rozmiarowi ekranu, i przypisz ją do extraBitmap. Trzeci argument to konfiguracja kolorów bitmapy. ARGB_8888 przechowuje każdy kolor w 4 bajtach i jest zalecany.
extraBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
  1. Utwórz instancję Canvas z instancji extraBitmap i przypisz ją do instancji extraCanvas.
 extraCanvas = Canvas(extraBitmap)
  1. Określ kolor tła, w którym chcesz wpisać extraCanvas.
extraCanvas.drawColor(backgroundColor)
  1. Gdy uruchamiasz funkcję, przy każdym działaniu onSizeChanged() jest tworzony nowy bitmapa i obszar roboczy. Potrzebujesz nowej bitmapy, bo jej rozmiar się zmienił. Jednak to wyciek pamięci, który pozostawia stare mapy bitowe. Aby rozwiązać ten problem, odzyskuj extraBitmap przed utworzeniem kolejnego, dodając ten kod bezpośrednio po wywołaniu funkcji super.
if (::extraBitmap.isInitialized) extraBitmap.recycle()

Krok 2. Zastąp onDraw()

Wszystkie zadania związane z rysunkiem MyCanvasView mają miejsce onDraw().

Zacznij od wyświetlenia obszaru roboczego, wypełniając ekran kolorem ustawionym w narzędziu onSizeChanged().

  1. Zastąp onDraw() i pobierz zawartość pamięci podręcznej extraBitmap w obszarze roboczym powiązanym z widokiem. Metoda drawBitmap() Canvas jest dostępna w kilku wersjach. W tym kodzie podajesz bitmapę, współrzędne X i y (w pikselach) lewego górnego rogu i nullPaint.
override fun onDraw(canvas: Canvas) {
   super.onDraw(canvas)
canvas.drawBitmap(extraBitmap, 0f, 0f, null)
}


Zwróć uwagę na to, że obszar roboczy, który jest przekazywany do onDraw() i używany przez system do wyświetlania mapy bitowej, różni się od obszaru roboczego utworzonego w metodzie onSizeChanged() i używanej przez Ciebie do rysowania w mapie bitowej.

  1. Uruchom aplikację. Powinien wyświetlić się cały ekran w określonym kolorze tła.

Aby narysować obiekt, potrzebujesz obiektu Paint, który określa styl elementów podczas rysowania, oraz obiektu Path, który określa, co jest rysowane.

Krok 1. Inicjowanie obiektu Paint

  1. W aplikacji MyCanvasView.kt zdefiniuj stałą szerokość kreski na najwyższym poziomie pliku.
private const val STROKE_WIDTH = 12f // has to be float
  1. Na poziomie klasy MyCanvasView zdefiniuj zmienną drawColor do przechowywania koloru i zainicjuj ją za pomocą wcześniej zdefiniowanego zasobu colorPaint.
private val drawColor = ResourcesCompat.getColor(resources, R.color.colorPaint, null)
  1. Na poziomie klasy poniżej dodaj zmienną paint dla obiektu Paint i zainicjuj ją w ten sposób:
// Set up the paint with which to draw.
private val paint = Paint().apply {
   color = drawColor
   // Smooths out edges of what is drawn without affecting shape.
   isAntiAlias = true
   // Dithering affects how colors with higher-precision than the device are down-sampled.
   isDither = true
   style = Paint.Style.STROKE // default: FILL
   strokeJoin = Paint.Join.ROUND // default: MITER
   strokeCap = Paint.Cap.ROUND // default: BUTT
   strokeWidth = STROKE_WIDTH // default: Hairline-width (really thin)
}
  • color elementu paint to zdefiniowany wcześniej drawColor.
  • isAntiAlias określa, czy chcesz zastosować wygładzanie krawędzi. Ustawienie wartości isAntiAlias na true wygładza krawędzie rysowanych obiektów bez wpływu na kształt.
  • Wartość isDither, gdy true, ma wpływ na to, że kolory z większą dokładnością niż w przypadku urządzenia są próbkowane. Na przykład barwienie to najpowszechniejszy sposób zmniejszenia zakresu kolorów zdjęć do maksymalnie 256 kolorów.
  • style ustawia typ malowania na kreskę, czyli jest to linia. Paint.Style określa, czy obiekt podstawowy jest rysowany, czy jest rysowany lub oba (w tym samym kolorze). Wartość domyślna to wypełnienie obiektu, do którego zastosowano farbę. ("Fill" koloruje wnętrze kształtu, a &"kreska" jest kontynuowana).
  • strokeJoin z Paint.Join określa, w jaki sposób linie i segmenty krzywej łączą się na ścieżce. Wartość domyślna to MITER.
  • strokeCap ustawia kształt końca wiersza jako limit. Paint.Cap określa, jak początek i koniec linii kreski i ścieżki. Wartość domyślna to BUTT.
  • strokeWidth określa szerokość kreski w pikselach. Domyślna szerokość to bardzo cienka szerokość, więc będzie ustawiona na ustaloną wcześniej stałą STROKE_WIDTH.

Krok 2. Inicjowanie obiektu ścieżki

Path to ścieżka rysowana przez użytkownika.

  1. W narzędziu MyCanvasView dodaj zmienną path i zainicjuj ją za pomocą obiektu Path, by przechowywał ścieżkę, która jest rysowana podczas dotknięcia ekranu przez użytkownika. Importuj android.graphics.Path z Path.
private var path = Path()

Krok 1. Reaguj na ruch na wyświetlaczu

Metoda onTouchEvent() w widoku danych jest wywoływana za każdym razem, gdy użytkownik dotknie wyświetlacza.

  1. W MyCanvasView zastąp metodę onTouchEvent() pamięci podręcznej x i y przekazanej wartości w event. Następnie użyj wyrażenia when, aby obsługiwać zdarzenia ruchu, np. dotykając ekranu, przesuwając go po ekranie albo zwalniając go. Są to interesujące Cię czynności związane z rysowaniem linii. W przypadku każdego typu zdarzenia wywołaj metodę mediów określoną w poniższym kodzie. Pełną listę zdarzeń dotyku znajdziesz w dokumentacji zajęć MotionEvent.
override fun onTouchEvent(event: MotionEvent): Boolean {
   motionTouchEventX = event.x
   motionTouchEventY = event.y

   when (event.action) {
       MotionEvent.ACTION_DOWN -> touchStart()
       MotionEvent.ACTION_MOVE -> touchMove()
       MotionEvent.ACTION_UP -> touchUp()
   }
   return true
}
  1. Na poziomie klasy dodaj brakujące zmienne motionTouchEventX i motionTouchEventY, by zapisać współrzędne x i y bieżącego zdarzenia dotknięcia (współrzędne MotionEvent). Zainicjuj je do 0f.
private var motionTouchEventX = 0f
private var motionTouchEventY = 0f
  1. Utwórz namiary na 3 funkcje: touchStart(), touchMove() i touchUp().
private fun touchStart() {}

private fun touchMove() {}

private fun touchUp() {}
  1. Twój kod powinien być tworzony i uruchamiany, ale nie zobaczysz jeszcze niczego poza kolorowym tłem.

Krok 2. Zaimplementuj touchStart()

Ta metoda jest wywoływana, gdy użytkownik po raz pierwszy dotknie ekranu.

  1. Na poziomie klasy dodaj zmienne, by zapisać najnowsze wartości x i y. Gdy użytkownik przestanie się poruszać i uniesie rękę, rozpocznie się kolejna ścieżka (rysunek z tego fragmentu).
private var currentX = 0f
private var currentY = 0f
  1. Zaimplementuj metodę touchStart() w ten sposób: Zresetuj path, przejdź do współrzędnych x y zdarzenia dotknięcia (motionTouchEventX i motionTouchEventY) i przypisz do tych wartości wartości currentX oraz currentY.
private fun touchStart() {
   path.reset()
   path.moveTo(motionTouchEventX, motionTouchEventY)
   currentX = motionTouchEventX
   currentY = motionTouchEventY
}

Krok 3. Zaimplementuj touchmove()

  1. Na poziomie klasy dodaj zmienną touchTolerance i ustaw ją na ViewConfiguration.get(context).scaledTouchSlop.
private val touchTolerance = ViewConfiguration.get(context).scaledTouchSlop

Korzystając ze ścieżki, nie musisz rysować każdego piksela i za każdym razem prosić o odświeżenie wyświetlacza. Zamiast tego możesz interpolować ścieżkę między punktami, by uzyskać dużo większą skuteczność.

  • Jeśli palec jest niemal niewysunięty, nie trzeba rysować.
  • Jeśli palec przesunął się niżej niż touchTolerance, nie rysuj.
  • scaledTouchSlop zwraca odległość w pikselach, która może dotknąć, zanim system wykryje, że użytkownik przewija stronę.
  1. Określ metodę touchMove(). Oblicz przebytą odległość (dx, dy), utwórz krzywą między dwoma punktami, zapisz ją w tabeli path, zaktualizuj liczby w biegach currentX i currentY, a następnie narysuj path. Następnie wywołaj invalidate(), aby wymusić ponowne przesłanie ekranu przy użyciu zaktualizowanego path.
private fun touchMove() {
   val dx = Math.abs(motionTouchEventX - currentX)
   val dy = Math.abs(motionTouchEventY - currentY)
   if (dx >= touchTolerance || dy >= touchTolerance) {
       // QuadTo() adds a quadratic bezier from the last point,
       // approaching control point (x1,y1), and ending at (x2,y2).
       path.quadTo(currentX, currentY, (motionTouchEventX + currentX) / 2, (motionTouchEventY + currentY) / 2)
       currentX = motionTouchEventX
       currentY = motionTouchEventY
       // Draw the path in the extra bitmap to cache it.
       extraCanvas.drawPath(path, paint)
   }
   invalidate()
}

Szczegółowe informacje o tej metodzie:

  1. Oblicz przebytą odległość (dx, dy).
  2. Jeśli ruch jest większy niż tolerancja dotyku, dodaj do ścieżki segment.
  3. Ustaw punkt początkowy kolejnego segmentu na punkt końcowy tego segmentu.
  4. Wyznaczenie linii quadTo() zamiast lineTo() spowoduje płynnie rysowaną linię bez narożników. Zobacz Krzywe Beziera.
  5. Wywołaj invalidate(), aby ostatecznie połączyć się z elementem onDraw(), i zmienić widok danych.

Krok 4. Zaimplementuj touchUp()

Gdy użytkownik uniesie palec, wystarczy zresetować ścieżkę, aby nie rysowała się ponownie. Nie są pobierane żadne dane, więc unieważnienie nie jest potrzebne.

  1. Zaimplementuj metodę touchUp().
private fun touchUp() {
   // Reset the path so it doesn't get drawn again.
   path.reset()
}
  1. Uruchom kod i rysuj palcem na ekranie. Zwróć uwagę, że jeśli obrócisz urządzenie, ekran zostanie wyczyszczony, bo stan rysowania nie został zapisany. W przypadku tej przykładowej aplikacji chodzi o to, aby użytkownik mógł w prosty sposób wyczyścić ekran.

Krok 5. Narysuj ramkę wokół szkicu

Gdy użytkownik rysuje na ekranie, aplikacja tworzy ścieżkę i zapisuje ją w mapie bitowej extraBitmap. Metoda onDraw() wyświetla dodatkową mapę bitową w obszarze roboczym widoku. Dodatkowe możliwości rysowania znajdziesz w onDraw(). Na przykład po narysowaniu bitmap możesz rysować kształty.

W tym kroku narysujesz ramkę wokół krawędzi zdjęcia.

  1. W MyCanvasView dodaj zmienną o nazwie frame, która zawiera obiekt Rect.
private lateinit var frame: Rect
  1. Na końcu onSizeChanged() definiujesz miejsce i dodaj kod, aby utworzyć Rect element, który będzie używany w ramce, z nowymi wymiarami i wcięciem.
// Calculate a rectangular frame around the picture.
val inset = 40
frame = Rect(inset, inset, width - inset, height - inset)
  1. W onDraw() po narysowaniu bitmap narysuj prostokąt.
// Draw a frame around the canvas.
canvas.drawRect(frame, paint)
  1. Uruchom aplikację. Zwróć uwagę na ramkę.

Zadanie (opcjonalnie): przechowywanie danych na ścieżce

W bieżącej aplikacji informacje o rysunkach są przechowywane w mapie bitowej. To dobre rozwiązanie, ale nie jest ono jedynym sposobem przechowywania informacji o rysunkach. Sposób przechowywania historii rysowania zależy od aplikacji i różnych wymagań. Jeśli na przykład rysujesz kształty, możesz zapisać listę kształtów wraz z lokalizacjami i wymiarami. W przypadku aplikacji MiniPaint możesz zapisać ścieżkę jako Path. Jeśli chcesz je wypróbować, poniżej znajdziesz ogólny opis tej czynności.

  1. W kodzie MyCanvasView usuń cały kod extraCanvas i extraBitmap.
  2. Dodaj do tej pory zmienne do bieżącej ścieżki, a także rysowaną obecnie ścieżkę.
// Path representing the drawing so far
private val drawing = Path()

// Path representing what's currently being drawn
private val curPath = Path()
  1. W onDraw() zamiast rysować bitmap, narysuj zapisane i bieżące ścieżki.
// Draw the drawing so far
canvas.drawPath(drawing, paint)
// Draw any current squiggle
canvas.drawPath(curPath, paint)
// Draw a frame around the canvas
canvas.drawRect(frame, paint)
  1. W touchUp() dodaj obecną ścieżkę do poprzedniej i zresetuj ją.
// Add the current path to the drawing so far
drawing.addPath(curPath)
// Rewind the current path for the next touch
curPath.reset()
  1. Uruchamiaj aplikację. Tak, nie powinno być żadnych zmian.

Pobierz kod ukończonych ćwiczeń z programowania.

$  git clone https://github.com/googlecodelabs/android-kotlin-drawing-canvas


Możesz też pobrać repozytorium jako plik ZIP, rozpakować go i otworzyć w Android Studio.

Pobierz aplikację Zip

  • Canvas to powierzchnia rysowania 2D, która udostępnia metody rysowania.
  • Element Canvas może być powiązany z instancją View, która je wyświetla.
  • Obiekt Paint zawiera informacje o stylu i kolorze określające sposób rysowania geometrii (linii, prostokąta, owalu i ścieżek) oraz tekstu.
  • W przypadku pracy z odbitką na płótnie zwykle jest tworzony widok niestandardowy, który zastępuje metody onDraw() i onSizeChanged().
  • Zastąp metodę onTouchEvent(), aby rejestrować kliknięcia użytkowników i reagować na nie, rysując rzeczy.
  • Możesz używać dodatkowej mapy bitowej do zapisywania w pamięci podręcznej informacji na temat rysunków, które zmieniają się z upływem czasu. Możesz też zapisać kształty lub ścieżkę.

Kurs Udacity:

Dokumentacja dla programistów Androida:

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

Które z poniższych elementów są wymagane do pracy z Canvas? Wybierz wszystkie pasujące odpowiedzi.

Bitmap

Paint

Path

View

Pytanie 2

Jak działa połączenie z (invalidate())?

▢ unieważnia i ponownie uruchamia aplikację.

▢ usuwa rysunek z bitmapy.

▢ Wskazuje, że poprzedni kod nie powinien być uruchomiony.

▢ Informuje system, że musi ponownie usunąć ekran.

Pytanie 3

Jaka jest funkcja obiektów Canvas, Bitmap i Paint?

▢ Ekran rysowania 2D, bitmapa wyświetlana na ekranie, informacje o stylu do rysowania.

▢ Rysowanie 3D, bitmapa do zapisywania ścieżki w pamięci podręcznej; informacje o stylu do rysowania.

▢ Rysowanie 2D, bitmapa wyświetlana na ekranie, styl widoku.

▢ Pamięć podręczna do informacji o rysunku, bitmapa do rysowania, informacje o stylach rysowania.

Linki do innych ćwiczeń z programowania znajdziesz w kursie dotyczącym programowania na Androida dla zaawansowanych w Kotlin.