Codelab ini adalah bagian dari kursus Android Lanjutan di Kotlin. Anda akan mendapatkan manfaat maksimal dari kursus ini jika menyelesaikan codelab secara berurutan, tetapi ini tidak bersifat wajib. Semua codelab kursus tercantum di halaman landing codelab Android Lanjutan di Kotlin.
Pengantar
Untuk tujuan codelab ini, kliping adalah cara untuk menentukan area gambar, kanvas, atau bitmap yang digambar atau tidak digambar secara selektif ke layar. Salah satu tujuan pemangkasan adalah untuk mengurangi overdraw. Overdraw terjadi saat piksel di layar digambar lebih dari sekali untuk menampilkan gambar akhir. Saat Anda mengurangi overdraw, Anda meminimalkan jumlah waktu piksel atau area layar digambar, untuk memaksimalkan performa gambar. Anda juga dapat menggunakan pemangkasan untuk menciptakan efek menarik dalam desain dan animasi antarmuka pengguna.
Misalnya, saat Anda menggambar tumpukan kartu yang tumpang-tindih seperti yang ditunjukkan di bawah, daripada menggambar setiap kartu sepenuhnya dari bawah ke atas, biasanya lebih efisien untuk hanya menggambar bagian yang terlihat. "Biasanya", karena operasi kliping juga memiliki biaya, dan secara keseluruhan, sistem Android melakukan banyak pengoptimalan gambar.

Untuk hanya menggambar bagian kartu yang terlihat, Anda menentukan region kliping untuk setiap kartu. Misalnya, dalam diagram di bawah, saat persegi panjang kliping diterapkan pada gambar, hanya bagian di dalam persegi panjang tersebut yang ditampilkan.

Area kliping biasanya berupa persegi panjang, tetapi dapat berupa bentuk atau kombinasi bentuk apa pun, bahkan teks. Anda juga dapat menentukan apakah Anda ingin wilayah di dalam wilayah kliping disertakan atau dikecualikan. Misalnya, Anda dapat membuat wilayah kliping melingkar dan hanya menampilkan apa yang berada di luar lingkaran.
Dalam codelab ini, Anda akan bereksperimen dengan berbagai cara pemangkasan.
Yang harus sudah Anda ketahui
Anda harus memahami:
- Cara membuat aplikasi dengan
Activitydan menjalankannya menggunakan Android Studio. - Cara membuat dan menggambar di
Canvas. - Cara membuat
Viewkustom, dan menggantionDraw()danonSizeChanged().
Yang akan Anda pelajari
- Cara memangkas objek untuk menggambar di
Canvas. - Cara menyimpan dan memulihkan status gambar kanvas.
- Cara menerapkan transformasi ke kanvas dan ke teks.
Yang akan Anda lakukan
- Buat aplikasi yang menggambar bentuk yang dipangkas di layar yang menunjukkan berbagai cara pemangkasan dan hasilnya pada visibilitas bentuk tersebut.
- Anda juga akan menggambar beberapa teks yang diterjemahkan dan dimiringkan.
Aplikasi ClippingExample menunjukkan cara menggunakan dan menggabungkan bentuk untuk menentukan bagian kanvas yang ditampilkan dalam tampilan. Aplikasi akhir Anda akan terlihat seperti screenshot di bawah.

Anda akan membangun aplikasi ini dari awal, jadi Anda harus menyiapkan project, menentukan dimensi dan string, serta mendeklarasikan beberapa variabel.
Langkah 1: Buat project ClippingExample
- Buat project Kotlin bernama
ClippingExampledengan template Empty Activity. Gunakancom.example.androiduntuk awalan nama paket. - Buka
MainActivity.kt. - Dalam metode
onCreate(), ganti tampilan konten default dan tetapkan tampilan konten ke instance baruClippedView. Ini akan menjadi tampilan kustom Anda untuk contoh kliping yang akan Anda buat berikutnya.
setContentView(ClippedView(this))- Di tingkat yang sama dengan
MainActivity.kt, buat file dan class Kotlin baru untuk tampilan kustom bernamaClippedViewyang memperluasView. Berikan tanda tangan yang ditunjukkan di bawah. Semua pekerjaan Anda lainnya akan berada di dalamClippedViewini. Anotasi@JvmOverloadsmenginstruksikan compiler Kotlin untuk membuat kelebihan beban untuk fungsi ini yang menggantikan nilai parameter default.
class ClippedView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
}Langkah 2: Tambahkan dimensi dan resource string
- Tentukan dimensi yang akan Anda gunakan untuk tampilan yang diklip dalam file resource baru di
res/values/dimens.xml. Dimensi default ini dikodekan secara permanen dan disesuaikan agar pas di layar yang cukup kecil.
<?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>Agar aplikasi terlihat bagus di layar yang lebih besar (dan agar detail lebih mudah dilihat), Anda dapat membuat file dimens dengan nilai yang lebih besar yang hanya berlaku untuk layar yang lebih besar.
- Di Android Studio, klik kanan folder values, lalu pilih New > Values resource file.
- Pada dialog New Resource File, beri nama file
dimens. Di Available qualifiers, pilih Smallest Screen Width dan klik tombol >> untuk menambahkannya ke Chosen qualifiers. Masukkan 480 ke dalam kotak Lebar layar terkecil, lalu klik Oke.

- File akan ditampilkan di folder nilai Anda seperti yang ditunjukkan di bawah.

- Jika Anda tidak dapat melihat file, beralihlah ke tampilan Project Files aplikasi. Jalur lengkap file baru adalah seperti yang ditunjukkan di bawah:
ClippingExample/app/src/main/res/values-sw480dp/dimens.xml.

- Ganti konten default file
values-sw480dp/dimens.xmldengan dimensi di bawah.
<?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>- Di
strings.xml, tambahkan string berikut. Objek ini akan digunakan untuk menampilkan teks di kanvas.
<string name="clipping">Clipping</string>
<string name="translated">translated text</string>
<string name="skewed">"Skewed and "</string>Langkah 3: Buat dan inisialisasi objek Paint dan Path
- Beralih kembali ke tampilan Android project Anda.
- Di
ClippedView, tentukan variabelPaintuntuk digambar. Aktifkan anti-aliasing, dan gunakan lebar goresan dan ukuran teks yang ditentukan dalam dimensi, seperti yang ditunjukkan di bawah.
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)
}- Di
ClippedView, buat dan lakukan inisialisasiPathuntuk menyimpan jalur yang telah digambar secara lokal. Imporandroid.graphics.Path.
private val path = Path()Langkah 4: Siapkan bentuk
Di aplikasi ini, Anda menampilkan beberapa baris dan dua kolom bentuk yang dipangkas dengan berbagai cara.
Mereka semua memiliki kesamaan:
- Persegi panjang besar (persegi) yang berfungsi sebagai penampung
- Garis diagonal di seberang persegi panjang besar
- Lingkaran
- String teks pendek

Pada langkah ini, Anda akan menyiapkan dimensi untuk bentuk tersebut dari resource, sehingga Anda hanya perlu mendapatkan dimensi satu kali saat menggunakannya nanti.
- Di
ClippedView, di bawahpath, tambahkan variabel untuk dimensi untuk persegi panjang kliping di sekitar seluruh set bentuk.
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)- Tambahkan variabel untuk inset persegi panjang dan offset persegi panjang kecil.
private val rectInset = resources.getDimension(R.dimen.rectInset)
private val smallRectOffset = resources.getDimension(R.dimen.smallRectOffset)- Tambahkan variabel untuk radius lingkaran. Ini adalah radius lingkaran yang digambar di dalam persegi panjang.
private val circleRadius = resources.getDimension(R.dimen.circleRadius)- Tambahkan offset dan ukuran teks untuk teks yang digambar di dalam persegi panjang.
private val textOffset = resources.getDimension(R.dimen.textOffset)
private val textSize = resources.getDimension(R.dimen.textSize)Langkah 4: Siapkan lokasi baris dan kolom
Bentuk untuk aplikasi ini ditampilkan dalam dua kolom dan empat baris, yang ditentukan oleh nilai dimensi yang disiapkan di atas. Perhitungan untuk ini bukan bagian dari codelab ini, tetapi lihatlah saat Anda menyalin kode yang diberikan pada langkah ini.
- Siapkan koordinat untuk dua kolom.
private val columnOne = rectInset
private val columnTwo = columnOne + rectInset + clipRectRight- Tambahkan koordinat untuk setiap baris, termasuk baris terakhir untuk teks yang diubah.
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)- Jalankan aplikasi Anda. Aplikasi akan terbuka dengan layar putih kosong di bawah nama aplikasi.

Di onDraw(), Anda memanggil metode untuk menggambar tujuh persegi panjang yang berbeda seperti yang ditunjukkan pada screenshot aplikasi di bawah. Semua persegi panjang digambar dengan cara yang sama; satu-satunya perbedaan adalah wilayah kliping dan lokasinya yang ditentukan di layar.

Algoritma yang digunakan untuk menggambar persegi panjang berfungsi seperti yang ditunjukkan dalam diagram dan penjelasan di bawah. Singkatnya, Anda menggambar serangkaian persegi panjang dengan memindahkan titik asal Canvas. Secara konseptual, hal ini terdiri dari langkah-langkah berikut:

(1) Pertama, Anda menerjemahkan Canvas ke tempat Anda ingin menggambar persegi panjang. Artinya, alih-alih menghitung tempat persegi panjang berikutnya dan semua bentuk lainnya perlu digambar, Anda memindahkan asal Canvas, yaitu sistem koordinatnya.
(2) Kemudian, Anda menggambar persegi panjang di titik asal kanvas yang baru. Artinya, Anda menggambar bentuk di lokasi yang sama dalam sistem koordinat yang diterjemahkan. Cara ini jauh lebih sederhana dan sedikit lebih efisien.
(3) Terakhir, Anda memulihkan Canvas ke Origin aslinya.
Berikut algoritma yang akan Anda terapkan:
- Di
onDraw(), panggil fungsi untuk mengisiCanvasdengan warna latar belakang abu-abu dan menggambar bentuk aslinya. - Panggil fungsi untuk setiap persegi panjang yang diklip dan teks yang akan digambar.
Untuk setiap persegi panjang atau teks:
- Simpan status
Canvassaat ini agar Anda dapat mereset ke status awal tersebut. - Terjemahkan
Originkanvas ke lokasi tempat Anda ingin menggambar. - Menerapkan bentuk dan jalur kliping.
- Gambar persegi panjang atau teks.
- Memulihkan status
Canvas.
Langkah: Mengganti onDraw()
- Ganti
onDraw()seperti yang ditunjukkan dalam kode di bawah. Anda memanggil fungsi untuk setiap bentuk yang Anda gambar, yang akan Anda terapkan nanti.
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)
}- Buat stub untuk setiap fungsi gambar sehingga kode akan terus dikompilasi. Anda dapat menyalin kode di bawah.
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){
}Aplikasi menggambar persegi panjang dan bentuk yang sama tujuh kali, pertama tanpa pemangkasan, lalu enam kali dengan berbagai jalur pemangkasan yang diterapkan. Metode drawClippedRectangle() memisahkan kode untuk menggambar satu persegi panjang, seperti yang ditunjukkan di bawah.

Langkah 1: Buat metode drawClippedRectangle()
- Buat metode
drawClippedRectangle()yang menggunakan argumencanvasberjenisCanvas.
private fun drawClippedRectangle(canvas: Canvas) {
}- Dalam metode
drawClippedRectangle(), tetapkan batas persegi panjang kliping untuk seluruh bentuk. Terapkan persegi panjang pemangkasan yang membatasi gambar hanya pada persegi.
canvas.clipRect(
clipRectLeft,clipRectTop,
clipRectRight,clipRectBottom
)Metode Canvas.clipRect(...) mengurangi area layar yang dapat ditulis oleh operasi gambar di masa mendatang. Metode ini menetapkan batas pemangkasan menjadi irisan spasial dari persegi panjang pemangkasan saat ini dan persegi panjang yang diteruskan ke clipRect(). Ada banyak varian metode clipRect() yang menerima berbagai bentuk untuk wilayah dan memungkinkan berbagai operasi pada persegi panjang kliping.
- Isi
canvasdengan warna putih. Ya. Seluruh kanvas, karena Anda tidak menggambar persegi panjang, Anda melakukan kliping. Karena persegi panjang pemangkasan, hanya area yang ditentukan oleh persegi panjang pemangkasan yang diisi, sehingga membuat persegi panjang putih. Bagian permukaan lainnya tetap berwarna abu-abu.
canvas.drawColor(Color.WHITE)- Ubah warna menjadi merah dan gambar garis diagonal di dalam persegi panjang kliping.
paint.color = Color.RED
canvas.drawLine(
clipRectLeft,clipRectTop,
clipRectRight,clipRectBottom,paint
)- Tetapkan warna ke hijau dan gambar lingkaran di dalam persegi panjang kliping.
paint.color = Color.GREEN
canvas.drawCircle(
circleRadius,clipRectBottom - circleRadius,
circleRadius,paint
)- Setel warna menjadi biru dan gambar teks yang sejajar dengan tepi kanan persegi panjang kliping. Gunakan
canvas.drawText()untuk menggambar teks.
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
)Langkah 2: Terapkan metode drawBackAndUnclippedRectangle()
- Untuk melihat cara kerja metode
drawClippedRectangle(), gambar persegi panjang pertama yang tidak terklip dengan menerapkan metodedrawBackAndUnclippedRectangle()seperti yang ditunjukkan di bawah. Simpancanvas, terjemahkan ke posisi baris dan kolom pertama, gambar dengan memanggildrawClippedRectangle(), lalu pulihkancanvaske status sebelumnya.
private fun drawBackAndUnclippedRectangle(canvas: Canvas){
canvas.drawColor(Color.GRAY)
canvas.save()
canvas.translate(columnOne,rowOne)
drawClippedRectangle(canvas)
canvas.restore()
}- Jalankan aplikasi Anda. Anda akan melihat persegi panjang putih pertama dengan lingkaran, garis merah, dan teksnya di latar belakang abu-abu.

Dalam contoh metode kliping berikut, Anda menerapkan berbagai kombinasi wilayah kliping untuk mendapatkan efek grafis dan mempelajari cara menggabungkan wilayah kliping untuk membuat bentuk apa pun yang Anda butuhkan.
Setiap metode ini mengikuti pola yang sama.
- Menyimpan status kanvas saat ini:
canvas.save()
Konteks aktivitas mempertahankan tumpukan status gambar. Status gambar terdiri dari matriks transformasi saat ini dan wilayah kliping saat ini. Anda dapat menyimpan status saat ini, melakukan tindakan yang mengubah status gambar (seperti menerjemahkan atau memutar kanvas), lalu memulihkan status gambar yang disimpan. (Catatan: Ini seperti perintah "stash" di git!).
Jika gambar Anda menyertakan transformasi, menggabungkan dan mengurungkan transformasi dengan membalikkan transformasi tersebut rentan terhadap error. Misalnya, jika Anda menerjemahkan, meregangkan, lalu memutar, prosesnya akan menjadi rumit dengan cepat. Sebagai gantinya, simpan status kanvas, terapkan transformasi, gambar, lalu pulihkan status sebelumnya.
Misalnya, Anda dapat menentukan wilayah kliping, dan menyimpan status tersebut. Kemudian terjemahkan kanvas, tambahkan wilayah kliping, dan putar. Setelah menggambar, Anda dapat memulihkan status kliping asli, dan Anda dapat melanjutkan untuk melakukan transformasi terjemahan dan kemiringan yang berbeda, seperti yang ditunjukkan dalam diagram.

- Terjemahkan asal kanvas ke koordinat baris/kolom:
canvas.translate()
Jauh lebih mudah untuk memindahkan asal kanvas dan menggambar hal yang sama dalam sistem koordinat baru daripada memindahkan semua elemen untuk digambar. (Tips: Anda dapat menggunakan teknik yang sama untuk memutar elemen.)
- Terapkan transformasi ke
path, jika ada. - Terapkan kliping:
canvas.clipPath(path) - Menggambar bentuk:
drawClippedRectangle() or drawText() - Memulihkan status kanvas sebelumnya:
canvas.restore()
Langkah 1: Terapkan drawDifferenceClippingExample(canvas)
Tambahkan kode untuk menggambar persegi panjang kedua, yang menggunakan perbedaan antara dua persegi panjang kliping untuk membuat efek bingkai foto.

Gunakan kode di bawah yang melakukan hal berikut:
- Simpan kanvas.
- Terjemahkan asal kanvas ke ruang terbuka di baris pertama, kolom kedua, di sebelah kanan persegi panjang pertama.
- Terapkan dua persegi panjang kliping. Operator
DIFFERENCEmengurangi persegi panjang kedua dari persegi panjang pertama.
- Panggil metode
drawClippedRectangle()untuk menggambar kanvas yang diubah. - Memulihkan status kanvas.
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()
}- Jalankan aplikasi Anda dan seharusnya akan terlihat seperti ini.

Langkah 2: Terapkan drawCircularClippingExample(canvas)
Selanjutnya, tambahkan kode untuk menggambar persegi panjang yang menggunakan wilayah kliping melingkar yang dibuat dari jalur melingkar, yang pada dasarnya menghapus (tidak menggambar) lingkaran dan dengan demikian menampilkan latar belakang abu-abu.

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()
}Langkah 3: Terapkan drawIntersectionClippingExample(canvas)
Selanjutnya, tambahkan kode untuk menggambar persimpangan dua persegi panjang kliping di baris dan kolom kedua.


Perhatikan bahwa tampilan wilayah ini akan bervariasi, bergantung pada resolusi layar Anda. Bereksperimenlah dengan dimensi smallRectOffset untuk mengubah ukuran area yang terlihat. Nilai smallRectOffset yang lebih kecil akan menghasilkan area yang lebih besar di layar.
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()
}
Langkah 4: Terapkan drawCombinedClippingExample(canvas)
Selanjutnya, gabungkan bentuk, lingkaran dan persegi panjang, lalu gambar jalur apa pun untuk menentukan area pemangkasan.

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()
}
Langkah 5: Terapkan drawRoundedRectangleClippingExample(canvas)
Selanjutnya, tambahkan persegi panjang berlekuk yang merupakan bentuk kliping yang umum digunakan.

- Di tingkat teratas, buat dan inisialisasi variabel persegi panjang.
RectFadalah class yang menyimpan koordinat persegi panjang dalam floating point.
private var rectF = RectF(
rectInset,
rectInset,
clipRectRight - rectInset,
clipRectBottom - rectInset
)- Implementasikan fungsi
drawRoundedRectangleClippingExample(). FungsiaddRoundRect()menggunakan persegi panjang, nilai untuk nilai x dan y dari radius sudut, serta arah untuk memutar kontur persegi panjang bulat.Path.Directionmenentukan orientasi bentuk tertutup (misalnya, persegi panjang, oval) saat ditambahkan ke jalur.CCWadalah singkatan dari berlawanan arah jarum jam.
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()
}
Langkah 6: Terapkan drawOutsideClippingExample(canvas)
Potong bagian luar di sekitar persegi panjang dengan menggandakan inset persegi panjang pemotongan.

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()
}
Langkah 7: Terapkan drawTranslatedTextExample(canvas)
Menggambar teks tidak jauh berbeda dengan bentuk lainnya, dan Anda dapat menerapkan transformasi pada teks. Misalnya, Anda dapat menerjemahkan teks dengan menerjemahkan kanvas dan menggambar teks.

- Implementasikan fungsi di bawah.
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()
}- Jalankan aplikasi Anda untuk melihat teks yang diterjemahkan.

Langkah 8: Terapkan drawSkewedTextExample(canvas)
Anda juga dapat memiringkan teks. Artinya, mendistorsikannya dengan berbagai cara.

- Buat fungsi di bawah ini di
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()
}- Jalankan aplikasi Anda untuk melihat teks miring yang digambar sebelum teks terjemahan.

Metode quickReject() Canvas memungkinkan Anda memeriksa apakah persegi panjang atau jalur tertentu akan berada sepenuhnya di luar wilayah yang saat ini terlihat, setelah semua transformasi diterapkan.
Metode quickReject() sangat berguna saat Anda membuat gambar yang lebih kompleks dan perlu melakukannya secepat mungkin. Dengan quickReject(), Anda dapat memutuskan secara efisien objek mana yang tidak perlu digambar sama sekali, dan tidak perlu menulis logika persimpangan Anda sendiri.
- Metode
quickReject()menampilkantruejika persegi panjang atau jalur tidak akan terlihat sama sekali di layar. Untuk tumpang-tindih sebagian, Anda tetap harus melakukan pemeriksaan sendiri. EdgeTypeadalahAA(Anti-aliasing: Perlakukan tepi dengan membulatkan, karena mungkin di-anti-aliasing) atauBW(Hitam-Putih: Perlakukan tepi hanya dengan membulatkan ke batas piksel terdekat) hanya untuk membulatkan ke piksel terdekat.
Ada beberapa versi quickReject(), dan Anda juga dapat menemukannya dalam dokumentasi.
| quickReject |
| quickReject |
| quickReject |
Dalam latihan ini, Anda akan menggambar baris baru, di bawah teks, dan di dalam clipRect, seperti sebelumnya.
- Anda pertama-tama memanggil
quickReject()dengan persegi panjanginClipRectangle, yang tumpang-tindih denganclipRect. Jadi,quickReject()menampilkan salah (false),clipRectdiisi denganBLACK, dan persegi panjanginClipRectangledigambar.

- Kemudian, ubah kode dan panggil
quickReject(), dengannotInClipRectangle.quickReject()sekarang menampilkan nilai benar,clipRectdiisi denganWHITE, dannotInClipRectangletidak digambar.

Jika Anda memiliki gambar yang rumit, Anda dapat dengan cepat mengetahui bentuk mana yang sepenuhnya berada di luar wilayah kliping, dan bentuk mana yang mungkin harus Anda hitung dan gambar lebih lanjut, karena sebagian atau seluruhnya berada di dalam wilayah kliping.
Langkah: Bereksperimen dengan quickReject()
- Di level teratas, buat variabel untuk koordinat y baris tambahan.
private val rejectRow = rowFour + rectInset + 2*clipRectBottom- Tambahkan fungsi
drawQuickRejectExample()berikut keClippedView. Baca kode tersebut, karena berisi semua yang perlu Anda ketahui untuk menggunakanquickReject().
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()
}- Di
onDraw(), hapus tanda komentar pada pemanggilandrawQuickRejectExample(). - Jalankan aplikasi Anda, dan Anda akan melihat persegi panjang hitam, yang merupakan area kliping yang diisi, dan bagian
inClipRectangle, karena kedua persegi panjang tersebut tumpang-tindih, sehinggaquickReject()menampilkanfalsedaninClipRectangledigambar.

- Di
drawQuickRejectExample(), ubah kode untuk menjalankanquickReject()terhadapnotInClipRectangle.. SekarangquickReject()menampilkantruedan area kliping diisi dengan warna putih.

Download kode untuk codelab yang sudah selesai.
$ git clone https://github.com/googlecodelabs/android-kotlin-drawing-clipping
Atau, Anda dapat mendownload repositori sebagai file ZIP, mengekstraknya, dan membukanya di Android Studio.
Contextaktivitas mempertahankan status yang mempertahankan transformasi dan wilayah kliping untukCanvas.- Gunakan
canvas.save()dancanvas.restore()untuk menggambar dan kembali ke kondisi asli kanvas Anda. - Untuk menggambar beberapa bentuk pada kanvas, Anda dapat menghitung lokasinya, atau memindahkan (mentranslasikan) titik asal permukaan gambar. Yang terakhir dapat mempermudah pembuatan metode utilitas untuk urutan gambar berulang.
- Area kliping dapat berupa bentuk, kombinasi bentuk, atau jalur apa pun.
- Anda dapat menambahkan, mengurangi, dan menyatukan wilayah kliping untuk mendapatkan wilayah yang Anda butuhkan.
- Anda dapat menerapkan transformasi pada teks dengan mentransformasi kanvas.
- Metode
quickReject()Canvasmemungkinkan Anda memeriksa apakah persegi panjang atau jalur tertentu akan berada sepenuhnya di luar wilayah yang saat ini terlihat.
Kursus Udacity:
Dokumentasi developer Android:
- Class
Canvas - Class
Bitmap - Class
View - Class
Paint - Konfigurasi
Bitmap.config - Operator
Region.Op - Class
Path - Class
Canvas - Class
Bitmap - Class
View - Class
Paint - Konfigurasi
Bitmap.config - Operator
Region.Op - Class
Path - Alat grafis
android.graphics - Konfigurasi
Bitmap.ConfigCanvas - Kanvas dan Drawable
- Apa fungsi canvas.translate()
- Memahami save() dan restore() untuk konteks Canvas
- kliping
- overdraw.
@JvmOverloads
Lihat juga serangkaian artikel Arsitektur Grafis untuk penjelasan mendalam tentang cara framework Android menggambar ke layar.
Bagian ini mencantumkan kemungkinan tugas pekerjaan rumah untuk siswa yang mengerjakan codelab ini sebagai bagian dari kursus yang dipimpin oleh instruktur. Instruktur menentukan hal berikut:
- Memberikan pekerjaan rumah jika diperlukan.
- Memberi tahu siswa cara mengirimkan tugas pekerjaan rumah.
- Memberi nilai tugas pekerjaan rumah.
Instruktur bisa menggunakan saran ini sesuai kebutuhan, dan bebas menugaskan pekerjaan rumah lain yang dirasa cocok.
Jika Anda menyelesaikan codelab ini sendiri, gunakan tugas pekerjaan rumah ini untuk menguji pengetahuan Anda.
Jawab pertanyaan-pertanyaan berikut
Pertanyaan 1
Metode apa yang Anda panggil untuk mengecualikan bentuk agar tidak digambar secara efisien?
▢ excludeFromDrawing()
▢ quickReject()
▢ onDraw()
▢ clipRect()
Pertanyaan 2
Canvas.save() dan Canvas.restore() menyimpan dan memulihkan informasi apa?
▢ Warna, lebar garis, dll.
▢ Hanya transformasi saat ini
▢ Transformasi saat ini dan wilayah kliping
▢ Hanya wilayah kliping saat ini
Pertanyaan 3
Paint.Align menentukan:
▢ Cara menyelaraskan bentuk gambar berikut
▢ Sisi asal tempat teks diambil
▢ Di mana kliping disejajarkan dalam region kliping
▢ Sisi teks mana yang akan diratakan dengan titik asal
Untuk mengetahui link ke codelab lain dalam kursus ini, lihat halaman landing codelab Android Lanjutan di Kotlin.