Menggambar pada Objek Canvas

Codelab ini adalah bagian dari kursus Lanjutan Android di Kotlin. Anda akan mendapatkan manfaat maksimal dari kursus ini jika Anda mengerjakan codelab secara berurutan, tetapi ini tidak wajib. Semua codelab kursus tercantum di halaman landing codelab Android Lanjutan di Kotlin.

Pengantar

Di Android, Anda memiliki beberapa teknik yang tersedia untuk menerapkan grafik dan animasi 2D khusus dalam tampilan.

Selain menggunakan drawable, Anda dapat membuat gambar 2D menggunakan metode menggambar dari class Canvas. Canvas adalah permukaan gambar 2D yang menyediakan metode untuk menggambar. Hal ini berguna bila aplikasi Anda perlu menggambar ulang secara teratur, karena apa yang dilihat pengguna dari waktu ke waktu. Dalam codelab ini, Anda akan mempelajari cara membuat dan menggambar pada kanvas yang ditampilkan di View.

Jenis operasi yang dapat Anda lakukan pada kanvas meliputi:

  • Isi seluruh kanvas dengan warna.
  • Gambar bentuk, seperti persegi panjang, lengkungan, dan jalur yang diberi gaya seperti yang ditentukan dalam objek Paint. Objek Paint menyimpan informasi gaya dan warna tentang cara menggambar geometri (seperti garis, persegi panjang, oval, dan jalur), atau misalnya, jenis huruf teks.
  • Menerapkan transformasi, seperti terjemahan, penskalaan, atau transformasi kustom.
  • Clip, yaitu, menerapkan bentuk atau jalur ke kanvas untuk menentukan bagian yang terlihat.

Bagaimana pendapat Anda tentang gambar Android (sangat sederhana!)

Menggambar di Android atau di sistem modern lainnya, merupakan proses kompleks yang mencakup lapisan abstraksi, dan pengoptimalan untuk hardware. Cara Android menggambar adalah topik yang menarik tentang banyak yang telah ditulis, dan detailnya berada di luar cakupan codelab ini.

Dalam konteks codelab ini dan aplikasinya yang menggambar di kanvas untuk ditampilkan dalam tampilan layar penuh, Anda dapat memikirkannya dengan cara berikut.

  1. Anda memerlukan tampilan untuk menampilkan apa yang Anda gambar. Ini dapat berupa salah satu tampilan yang disediakan oleh sistem Android. Atau, dalam codelab ini, Anda akan membuat tampilan kustom yang berfungsi sebagai tampilan konten untuk aplikasi Anda (MyCanvasView).
  2. Tampilan ini, seperti semua tampilan, dilengkapi dengan kanvasnya sendiri (canvas).
  3. Untuk cara yang paling dasar untuk menggambar di kanvas tampilan, Anda mengganti metode onDraw() dan menggambar di kanvasnya.
  4. Saat membuat gambar, Anda perlu meng-cache apa yang telah digambar sebelumnya. Ada beberapa cara untuk menyimpan data dalam cache, salah satunya dalam bitmap (extraBitmap). Cara lainnya adalah dengan menyimpan histori koordinat yang Anda gambar.
  5. Untuk menggambar pada bitmap cache (extraBitmap) menggunakan API gambar kanvas, Anda membuat kanvas caching (extraCanvas) untuk bitmap cache.
  6. Kemudian Anda menggambar di kanvas cache (extraCanvas), yang digambar pada bitmap cache (extraBitmap).
  7. Untuk menampilkan semua yang digambar di layar, Anda memberi tahu kanvas tampilan (canvas) untuk menggambar bitmap cache (extraBitmap).

Yang harus sudah Anda ketahui

  • Cara membuat aplikasi dengan Aktivitas, tata letak dasar, dan menjalankannya menggunakan Android Studio.
  • Cara mengaitkan pengendali peristiwa dengan tampilan.
  • Cara membuat tampilan kustom.

Yang akan Anda pelajari

  • Cara membuat Canvas dan menggambarnya sebagai respons terhadap sentuhan pengguna.

Yang akan Anda lakukan

  • Buat aplikasi yang menggambar garis di layar sebagai respons terhadap pengguna yang menyentuh layar.
  • Rekam peristiwa gerakan, dan sebagai respons, gambar garis di kanvas yang ditampilkan dalam tampilan kustom layar penuh di layar.

Aplikasi MiniPaint menggunakan tampilan kustom untuk menampilkan garis sesuai dengan sentuhan pengguna, seperti yang ditunjukkan pada screenshot di bawah.

Langkah 1. Membuat project MiniPaint

  1. Buat project Kotlin baru bernama MiniPaint yang menggunakan template Empty Activity.
  2. Buka file app/res/values/colors.xml dan tambahkan dua warna berikut.
<color name="colorBackground">#FFFF5500</color>
<color name="colorPaint">#FFFFEB3B</color>
  1. Buka styles.xml
  2. Di induk gaya AppTheme tertentu, ganti DarkActionBar dengan NoActionBar. Tindakan ini akan menghapus panel tindakan, sehingga Anda dapat menggambar dalam layar penuh.
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">

Langkah 2. Membuat class MyCanvasView

Pada langkah ini, Anda membuat tampilan kustom, MyCanvasView, untuk gambar.

  1. Pada paket app/java/com.example.android.minipaint, buat New > Kotlin File/Class yang disebut MyCanvasView.
  2. Buat class MyCanvasView memperluas class View dan meneruskan context: Context. Setujui impor yang disarankan.
import android.content.Context
import android.view.View

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

Langkah 3. Menetapkan MyCanvasView sebagai tampilan konten

Untuk menampilkan apa yang akan Anda gambar di MyCanvasView, Anda harus menyetelnya sebagai tampilan konten MainActivity.

  1. Buka strings.xml dan tentukan string yang akan digunakan untuk deskripsi konten tampilan.
<string name="canvasContentDescription">Mini Paint is a simple line drawing app.
   Drag your fingers to draw. Rotate the phone to clear.</string>
  1. Buka MainActivity.kt
  2. Di onCreate(), hapus setContentView(R.layout.activity_main).
  3. Buat instance MyCanvasView.
val myCanvasView = MyCanvasView(this)
  1. Di bawahnya, minta layar penuh untuk tata letak myCanvasView. Lakukan hal ini dengan menetapkan tanda SYSTEM_UI_FLAG_FULLSCREEN di myCanvasView. Dengan cara ini, tampilan akan sepenuhnya memenuhi layar.
myCanvasView.systemUiVisibility = SYSTEM_UI_FLAG_FULLSCREEN
  1. Tambahkan deskripsi konten.
myCanvasView.contentDescription = getString(R.string.canvasContentDescription)
  1. Di bawahnya, tetapkan tampilan konten ke myCanvasView.
setContentView(myCanvasView)
  1. Jalankan aplikasi Anda. Anda akan melihat layar yang benar-benar putih, karena kanvas tidak memiliki ukuran dan Anda belum menggambar apa pun.

Langkah 1. Mengganti onSizeChanged()

Metode onSizeChanged() dipanggil oleh sistem Android setiap kali tampilan berubah ukuran. Karena tampilan dimulai tanpa ukuran, metode onSizeChanged() tampilan juga dipanggil setelah Aktivitas pertama kali membuat dan meng-inflate-nya. Oleh karena itu, metode onSizeChanged() ini adalah tempat yang ideal untuk membuat dan menyiapkan kanvas tampilan.

  1. Di MyCanvasView, pada tingkat class, tentukan variabel untuk kanvas dan bitmap. Beri nama extraCanvas dan extraBitmap. Ini adalah bitmap dan kanvas Anda untuk meng-cache apa yang telah digambar sebelumnya.
private lateinit var extraCanvas: Canvas
private lateinit var extraBitmap: Bitmap
  1. Tentukan variabel tingkat class backgroundColor untuk warna latar belakang kanvas dan inisialisasikan ke colorBackground yang Anda tentukan sebelumnya.
private val backgroundColor = ResourcesCompat.getColor(resources, R.color.colorBackground, null)
  1. Di MyCanvasView, ganti metode onSizeChanged(). Metode callback ini dipanggil oleh sistem Android dengan dimensi layar yang berubah, yaitu dengan lebar dan tinggi baru (yang akan berubah menjadi) serta lebar dan tinggi lama (yang akan diubah).
override fun onSizeChanged(width: Int, height: Int, oldWidth: Int, oldHeight: Int) {
   super.onSizeChanged(width, height, oldWidth, oldHeight)
}
  1. Di dalam onSizeChanged(), buat instance Bitmap dengan lebar dan tinggi baru, yang merupakan ukuran layar, dan tetapkan ke extraBitmap. Argumen ketiga adalah konfigurasi warna bitmap. ARGB_8888 menyimpan setiap warna dalam 4 byte dan direkomendasikan.
extraBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
  1. Buat instance Canvas dari extraBitmap dan tetapkan ke extraCanvas.
 extraCanvas = Canvas(extraBitmap)
  1. Tentukan warna latar belakang untuk mengisi extraCanvas.
extraCanvas.drawColor(backgroundColor)
  1. Melihat onSizeChanged(), bitmap dan kanvas baru dibuat setiap kali fungsi dieksekusi. Anda memerlukan bitmap baru, karena ukurannya telah berubah. Namun, ini adalah kebocoran memori, yang menyisakan bitmap lama. Untuk memperbaikinya, daur ulang extraBitmap sebelum membuat yang berikutnya dengan menambahkan kode ini tepat setelah panggilan ke super.
if (::extraBitmap.isInitialized) extraBitmap.recycle()

Langkah 2. Mengganti onDraw()

Semua pekerjaan menggambar untuk MyCanvasView dilakukan di onDraw().

Untuk memulai, tampilkan kanvas, yang mengisi layar dengan warna latar belakang yang Anda tetapkan di onSizeChanged().

  1. Ganti onDraw() dan gambar konten extraBitmap yang di-cache pada kanvas yang terkait dengan tampilan. Metode drawBitmap() Canvas tersedia dalam beberapa versi. Dalam kode ini, Anda memberikan bitmap, koordinat x dan y (dalam piksel) di sudut kiri atas, dan null untuk Paint, seperti yang akan Anda tetapkan nanti.
override fun onDraw(canvas: Canvas) {
   super.onDraw(canvas)
canvas.drawBitmap(extraBitmap, 0f, 0f, null)
}


Perhatikan, kanvas yang diteruskan ke onDraw() dan digunakan oleh sistem untuk menampilkan bitmap berbeda dengan yang Anda buat dalam metode onSizeChanged() dan digunakan oleh Anda untuk menggambar pada bitmap.

  1. Jalankan aplikasi. Anda akan melihat seluruh layar berisi warna latar belakang yang ditentukan.

Untuk menggambar, Anda memerlukan objek Paint yang menentukan gaya objek saat digambar, dan Path yang menentukan gaya yang sedang digambar.

Langkah 1. Melakukan inisialisasi objek Paint

  1. Di MyCanvasView.kt, di tingkat file atas, tentukan konstanta untuk lebar guratan.
private const val STROKE_WIDTH = 12f // has to be float
  1. Pada tingkat class MyCanvasView, tentukan variabel drawColor untuk menampung warna yang akan digambar, lalu inisialisasikan dengan resource colorPaint yang Anda tentukan sebelumnya.
private val drawColor = ResourcesCompat.getColor(resources, R.color.colorPaint, null)
  1. Pada tingkat class di bawah, tambahkan variabel paint untuk objek Paint lalu lakukan inisialisasi sebagai berikut.
// 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 dari paint adalah drawColor yang Anda tentukan sebelumnya.
  • isAntiAlias menentukan apakah akan menerapkan edge smoothing atau tidak. Menyetel isAntiAlias ke true akan meratakan tepi gambar yang tidak digambar tanpa memengaruhi bentuk.
  • isDither, saat true, memengaruhi bagaimana warna dengan presisi lebih tinggi dibandingkan dengan sampel di perangkat. Misalnya, dithering adalah cara yang paling umum untuk mengurangi rentang warna gambar hingga 256 (atau lebih sedikit) warna.
  • style menetapkan jenis lukisan untuk dilakukan goresan, yang pada dasarnya adalah sebuah garis. Paint.Style menentukan apakah primitif yang digambar diisi, diberi garis, atau keduanya (dalam warna yang sama). Defaultnya adalah mengisi objek tempat cat diterapkan. ("Isi" mewarnai bagian dalam bentuk, sedangkan "garis" mengikuti garis luarnya.)
  • strokeJoin dari Paint.Join menentukan cara segmen garis dan kurva bergabung pada jalur yang digores. Default-nya adalah MITER.
  • strokeCap menetapkan bentuk akhir baris menjadi batas. Paint.Cap menentukan cara awal dan akhir garis dan jalur goresan. Default-nya adalah BUTT.
  • strokeWidth menentukan lebar guratan dalam piksel. Defaultnya adalah lebar garis rambut, yang sangat tipis, sehingga ditetapkan ke konstanta STROKE_WIDTH yang Anda tentukan sebelumnya.

Langkah 2. Melakukan inisialisasi objek Path

Path adalah jalur gambar pengguna.

  1. Di MyCanvasView, tambahkan variabel path dan lakukan inisialisasi dengan objek Path untuk menyimpan jalur yang sedang digambar saat mengikuti sentuhan pengguna di layar. Impor android.graphics.Path untuk Path.
private var path = Path()

Langkah 1. Merespons gerakan pada layar

Metode onTouchEvent() pada tampilan akan dipanggil setiap kali pengguna menyentuh layar.

  1. Di MyCanvasView, ganti metode onTouchEvent() untuk meng-cache koordinat x dan y yang diteruskan di event. Kemudian gunakan ekspresi when untuk menangani peristiwa gerakan untuk menyentuh layar di bawah, menggerakkan layar, dan melepaskan sentuhan pada layar. Ini adalah peristiwa yang menarik untuk menggambar garis di layar. Untuk setiap jenis peristiwa, panggil metode utilitas, seperti yang ditunjukkan pada kode di bawah ini. Lihat dokumentasi class MotionEvent untuk daftar lengkap peristiwa sentuh.
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. Di tingkat class, tambahkan variabel motionTouchEventX dan motionTouchEventY yang tidak ada untuk menyimpan koordinat x dan y dalam cache peristiwa sentuh saat ini (koordinat MotionEvent). Lakukan inisialisasi ke 0f.
private var motionTouchEventX = 0f
private var motionTouchEventY = 0f
  1. Buat stub untuk tiga fungsi touchStart(), touchMove(), dan touchUp().
private fun touchStart() {}

private fun touchMove() {}

private fun touchUp() {}
  1. Kode akan dibuat dan dijalankan, tetapi Anda belum akan melihat tampilan apa pun yang berbeda dari latar belakang berwarna.

Langkah 2. Mengimplementasikan touchStart()

Metode ini dipanggil saat pengguna pertama kali menyentuh layar.

  1. Di tingkat class, tambahkan variabel untuk meng-cache nilai x dan y terbaru. Setelah pengguna berhenti bergerak dan mengangkat sentuhannya, ini adalah titik awal untuk jalur berikutnya (segmen garis berikutnya yang akan digambar).
private var currentX = 0f
private var currentY = 0f
  1. Implementasikan metode touchStart() seperti berikut. Reset path, pindahkan ke koordinat x-y peristiwa sentuh (motionTouchEventX dan motionTouchEventY), dan tetapkan currentX serta currentY ke nilai tersebut.
private fun touchStart() {
   path.reset()
   path.moveTo(motionTouchEventX, motionTouchEventY)
   currentX = motionTouchEventX
   currentY = motionTouchEventY
}

Langkah 3. Mengimplementasikan touchMove()

  1. Di tingkat class, tambahkan variabel touchTolerance dan tetapkan ke ViewConfiguration.get(context).scaledTouchSlop.
private val touchTolerance = ViewConfiguration.get(context).scaledTouchSlop

Dengan menggunakan jalur, Anda tidak perlu menggambar setiap piksel dan setiap kali meminta pemuatan ulang tampilan. Sebagai gantinya, Anda dapat (dan akan) menginterpolasi jalur antara poin untuk performa yang jauh lebih baik.

  • Jika jari diam saja, tidak perlu menggambar.
  • Jika jari bergerak kurang dari jarak touchTolerance, jangan gambar.
  • scaledTouchSlop akan menampilkan jarak dalam piksel yang dapat dijelajahi dengan sentuhan sebelum sistem menganggap pengguna sedang men-scroll.
  1. Tentukan metode touchMove(). Hitung jarak yang ditempuh (dx, dy), buat kurva di antara kedua titik dan simpan di path, perbarui penghitungan currentX dan currentY yang berjalan, lalu gambar path. Kemudian, panggil invalidate() untuk memaksa gambar ulang layar dengan path yang telah diupdate.
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()
}

Metode ini secara lebih detail:

  1. Hitung jarak yang telah dipindahkan (dx, dy).
  2. Jika gerakan lebih jauh dari toleransi sentuh, tambahkan segmen ke jalur.
  3. Tetapkan titik awal untuk segmen berikutnya ke titik akhir segmen ini.
  4. Menggunakan quadTo() dan bukan lineTo(), buat garis yang digambar dengan lancar tanpa sudut. Lihat Kurva Bezier.
  5. Panggil invalidate() untuk (nantinya memanggil onDraw() dan) menggambar ulang tampilan.

Langkah 4: Implementasikan touchUp()

Saat pengguna mengangkat sentuhannya, yang diperlukan hanyalah mereset jalur agar tidak digambar lagi. Tidak ada yang digambar, sehingga pembatalan tidak diperlukan.

  1. Implementasikan metode touchUp().
private fun touchUp() {
   // Reset the path so it doesn't get drawn again.
   path.reset()
}
  1. Jalankan kode dan gunakan jari Anda untuk menggambar di layar. Perhatikan bahwa jika Anda memutar perangkat, layar akan dihapus karena status gambar tidak disimpan. Untuk aplikasi contoh ini, ini memang sengaja didesain untuk memberi pengguna cara sederhana untuk mengosongkan layar.

Langkah 5: Gambar bingkai di sekitar sketsa

Saat pengguna menggambar di layar, aplikasi Anda akan membuat jalur dan menyimpannya dalam extraBitmap bitmap. Metode onDraw() menampilkan bitmap tambahan di kanvas tampilan. Anda dapat melakukan lebih banyak gambar dalam onDraw(). Misalnya, Anda dapat menggambar bentuk setelah menggambar bitmap.

Pada langkah ini, Anda menggambar bingkai di sekitar tepi gambar.

  1. Di MyCanvasView, tambahkan variabel bernama frame yang menyimpan objek Rect.
private lateinit var frame: Rect
  1. Di akhir onSizeChanged(), tentukan inset, dan tambahkan kode untuk membuat Rect yang akan digunakan untuk frame, menggunakan dimensi baru dan inset.
// Calculate a rectangular frame around the picture.
val inset = 40
frame = Rect(inset, inset, width - inset, height - inset)
  1. Di onDraw(), gambar persegi panjang setelah menggambar bitmap.
// Draw a frame around the canvas.
canvas.drawRect(frame, paint)
  1. Jalankan aplikasi Anda. Perhatikan bingkai.

Tugas (opsional): Menyimpan data di sebuah Path

Di aplikasi saat ini, informasi gambar disimpan di bitmap. Meskipun ini adalah solusi yang baik, ini bukan satu-satunya cara yang memungkinkan untuk menyimpan informasi gambar. Cara Anda menyimpan histori gambar bergantung pada aplikasi, dan berbagai persyaratan Anda. Misalnya, jika Anda menggambar bentuk, Anda dapat menyimpan daftar bentuk beserta lokasi dan dimensinya. Untuk aplikasi MiniPaint, Anda dapat menyimpan jalur sebagai Path. Di bawah ini adalah penjelasan umum tentang cara melakukannya, jika Anda ingin mencobanya.

  1. Di MyCanvasView, hapus semua kode untuk extraCanvas dan extraBitmap.
  2. Tambahkan variabel untuk jalur sejauh ini, dan jalur yang sedang digambar.
// Path representing the drawing so far
private val drawing = Path()

// Path representing what's currently being drawn
private val curPath = Path()
  1. Di onDraw(), bukan menggambar bitmap, gambar jalur yang disimpan dan saat ini.
// 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. Di touchUp(), tambahkan jalur saat ini ke jalur sebelumnya dan reset jalur saat ini.
// Add the current path to the drawing so far
drawing.addPath(curPath)
// Rewind the current path for the next touch
curPath.reset()
  1. Jalankan aplikasi Anda, dan tentu saja tidak ada perbedaan.

Mendownload kode untuk codelab yang sudah selesai.

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


Atau, Anda dapat mendownload repositori sebagai file Zip, mengekstraknya, dan membukanya di Android Studio.

Download Zip

  • Canvas adalah permukaan gambar 2D yang menyediakan metode untuk menggambar.
  • Canvas dapat dikaitkan dengan instance View yang menampilkannya.
  • Objek Paint menyimpan informasi gaya dan warna tentang cara menggambar geometri (seperti garis, persegi panjang, oval, dan jalur) dan teks.
  • Pola umum untuk menggunakan kanvas adalah dengan membuat tampilan kustom dan mengganti metode onDraw() dan onSizeChanged().
  • Ganti metode onTouchEvent() untuk menangkap sentuhan pengguna dan meresponsnya dengan menggambar sesuatu.
  • Anda dapat menggunakan bitmap tambahan untuk meng-cache informasi untuk gambar yang berubah dari waktu ke waktu. Atau, Anda bisa menyimpan bentuk, atau jalur.

Kursus Udacity:

Dokumentasi developer Android:

Bagian ini mencantumkan kemungkinan tugas pekerjaan rumah untuk siswa yang mengerjakan codelab ini sebagai bagian dari kursus yang dipimpin oleh instruktur. Terserah instruktur untuk melakukan hal berikut:

  • Tugaskan pekerjaan rumah jika diperlukan.
  • Berkomunikasi dengan siswa cara mengirimkan tugas pekerjaan rumah.
  • Beri nilai tugas pekerjaan rumah.

Instruktur dapat menggunakan saran ini sesedikit atau sebanyak yang mereka inginkan, dan harus bebas memberikan pekerjaan rumah lain yang dirasa sesuai.

Jika Anda mengerjakan codelab ini sendiri, silakan gunakan tugas pekerjaan rumah ini untuk menguji pengetahuan Anda.

Jawab pertanyaan berikut

Pertanyaan 1

Manakah dari komponen berikut yang diperlukan untuk menggunakan Canvas? Pilih semua yang sesuai.

Bitmap

Paint

Path

View

Pertanyaan 2

Apa fungsi panggilan ke invalidate() (secara umum)?

▢ Tidak valid dan mulai ulang aplikasi Anda.

▢ Menghapus gambar dari bitmap.

▢ Menunjukkan bahwa kode sebelumnya tidak boleh dijalankan.

▢ Memberi tahu sistem bahwa sistem harus menggambar ulang layar.

Pertanyaan 3

Apa fungsi objek Canvas, Bitmap, dan Paint?

▢ Permukaan gambar 2D, bitmap ditampilkan di layar, informasi gaya visual untuk gambar.

▢ Tampilan permukaan 3D, bitmap untuk menyimpan jalur jalur, informasi gaya visual untuk gambar.

▢ Permukaan gambar 2D, bitmap ditampilkan di layar, gaya visual untuk tampilan tersebut.

▢ Cache untuk informasi gambar, bitmap untuk menggambar, informasi gaya visual untuk gambar.

Untuk link ke codelab lainnya dalam kursus ini, lihat halaman landing codelab Android Lanjutan di Kotlin.