Custom View .... Ya ... kita semua tahu Custom View adalah salah satu topik paling menarik untuk dibahas karena Custom View merupakan salah satu fundamental di Android. Hal ini sangat mempengaruhi aplikasi kita dari segi performance dan look n feel atau tampilan.
Ketika saya mulai belajar mengenai Custom View, saya menemukan banyak informasi yang tersebar di internet mengenai Custom View. Jadi, saya mencoba membuat series khusus Custom View di blog ini agar kita semua bisa belajar dan berlatih beberapa basic concepts dari Custom View.
Oke sebelum kita lanjut, let's brush up some basic terms. ๐๏ธ
Apa itu View
View Class adalah basic block dalam membangun UI Component di Android. sederhananya mungkin bisa dibilang sebagai area persegi panjang yang di gambar di atas layar dan menyediakan beberapa event
yang berbeda (click, focus, dll), property
(mengatur teks pada TextView
misalnya), dan masih banyak lagi.
Widget Class seperti Button
, TextView
, dll juga pada dasarnya adalah Class yang extends
ke View
.
Apa itu ViewGroup Dan Apa Perbedaannya dengan Views?
ViewGroup merupakan Class yang dapat menampung beberapa Views
menjadi satu, sehingga dapat menciptakan UI yang mudah dimengerti oleh user, ViewGroup sendiri merupakan Sub Class dari View
.
Untuk lebih jelasnya, mari kita lihat class2 turunan dari View Class.
Oke setelah melihat gambar tersebut, mari kita coba bedah lebih dalam lagi dengan membahas coding dasar dalam pembuatan Custom View.
Mengenal Constructor dari Views Class
Untuk membuat Custom View, pasti nya kita akan membuat class lalu kita extends
class tersebut ke class Views. Nah maka dari itu, kita perlu mengetahui constructor apa saja yang harus dibuat untuk membuat Views
tersebut.
public View(Context context) {} // constructor
Oke seperti yang kalian lihat, constructor ini hanya membutuhkan parameter Context
. Constructor ini biasanya digunakan saat kita perlu menambahkan View langsung ke Activity
atau Fragment
menggunakan kode kotlin atau java.
public View(Context context, @Nullable AttributeSet attrs) {} // constructor
Yang kedua adalah basic constructor untuk XML. Tanpa ini LayoutInflater
akan crash. parameter kedua (attrs) pada constructor ini akan berisi attribut yang didefinisikan dalam XML (android:text
misalnya). Untuk lebih jelasnya kita akan coba sedikit latihan tentang ini nanti.
// Constructor of view class
public View(Context context, @Nullable AttributeSet attrs,
int defStyleAttr) {
// code
}
public View(Context context, @Nullable AttributeSet attrs,
int defStyleAttr, int defStyleRes){
// code
}
Yang terakhir adalah 2 constructor ini. Constructor ini digunakan untuk menerapkan default style pada semua element UI tanpa harus menentukan dalam setiap file layout nya.
int defStyleAttr
- default style yang diterapkan pada View
(didefinisikan didalam theme.xml) seperti android:background
, color, dll.
int defStyleResource
- default style yang diterapkan pada View
, jika defStyleAttr
tidak digunakan.
Jangan khawatir, kita akan bahas lebih dalam mengenai constructor ini di segment selanjutnya ๐
Oke kita telah membahas teori tentang constructor View Class dan beberapa istilah dasar. Saya kira kita telah membahas teori terlalu banyak, Nah maka dari itu sekarang mari kita coba untuk menulis beberapa kode dan menggunakan constructor pertama View Class untuk membuat Custom View. Let us make our first custom view ๐ฅ.
Membuat Custom View
Oke sebelum mulai, kita perlu memahami 2 hal
- Canvas => Ketika kita ingin menggambar bentuk atau teks ke dalam tampilan pada Android View, kita membutuhkan object Canvas. Secara sederhana, Canvas adalah permukaan gambar 2D logis yang menyediakan method untuk menggambar ke bitmap, mungkin jika kita tarik ke kehidupan sehari2, canvas adalah kertas yang kita gunakan untuk menggambar objek dll.
- Paint => Paint Class di Android menyediakan cara untuk menggambar sesuatu pada canvas. Paint Class memiliki properti seperti colors, styles, dll, tergantung apa yang kita butuhkan untuk menggambar pada canvas.
Setelah memahami 2 hal tersebut, mari kita mulai membuat class dengan nama CircleView.kt
class CircleView (context:Context): View(context){}
Selanjutnya mari kita tambahkan beberapa variable yang dibutuhkan Canvas & Paint Instance, kemudian kita inisialisasi di constructor
private val paint = Paint()
private val centerOfX = 340F // center of circle on X axis
private val centerOfY = 340F // center of circle on Yaxis
private val radius = 140F // radius of circle
init {
paint.color = ContextCompat.getColor(context,android.R.color.holo_green_light)
paint.strokeWidth = 40F
paint.style = Paint.Style.STROKE
}
Sekarang, let us draw something menggunakan method onDraw()
. Kita akan membahas nya lebih detail nanti di segment selanjutnya ๐
override fun onDraw(canvas: Canvas?) {
canvas?.drawCircle(centerOfX,centerOfY,radiusOfCircleView,paint)
super.onDraw(canvas)
}
Dan Custom View pertama kita siap digunakan.
class CircleView(context: Context): View(context) {
private val paint = Paint()
private val centerOfX = 340F // center of circle on X axis
private val centerOfY = 340F // center of circle on Yaxis
private val radius = 140F // radius of circle
init {
paint.color = ContextCompat.getColor(context,android.R.color.holo_green_light)
paint.strokeWidth = 40F
paint.style = Paint.Style.STROKE
}
override fun onDraw(canvas: Canvas?) {
canvas?.drawCircle(centerOfX,centerOfY,radius,paint)
super.onDraw(canvas)
}
}
Mari kita bahas sedikit mengenai class yang sudah kita buat tadi, disini kita sudah membuat class yang extend
ke View
class dengan constructor 1 argument (Context
). Sampai sini kita hanya bisa menggunakan View ini didalam kode java atau kotlin. Jika tidak, maka kita akan mendapatkan exceptions
.
Kita juga telah meng-override
method onDraw()
untuk menggambar pada canvas
menggunakan object Paint
, kita telah menambahkan beberapa properti (radius, warna) dan menggambar lingkaran. Langkah berikutnya, mari kita coba tampilkan View tersebut ke dalam Activity
.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val circleView = CircleView(this)
setContentView(circleView)
}
}
Dan tampilannya akan seperti ini ๐
Sekarang jika kita tambahkan View
ini kedalam XML, kemudian menampilkannya di Activity
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<dev.fathonaji.customviews.CircleView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/teal_200"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
lalu ubah sedikit kode di Activity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// val circleView = CircleView(this)
// setContentView(circleView)
setContentView(R.layout.activity_main)
}
}
Maka kita akan mendapatkan error seperti ini
Apa yang terjadi? mari kita coba telusuri lebih lanjut mengenai error tersebut
Setelah kita telusuri, ternyata kita mendapatkan beberapa point penting, diantaranya:
- InflateException saat menambahkan Custom View
- NoSuchMethodException!! inisialisasi memerlukan context dan AttributeSet.
Ya, dapat kita simpulkan bahwa error tersebut meminta constructor kedua di View kita. Tapi mengapa?
<dev.fathonaji.customviews.CircleView
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
android:layout_width="wrap_content"
dan android:layout_height="wrap_content"
kedua properti ini adalah atribut dari View. Jadi, menambahkan View dalam XML memerlukan implementasi atribut. constructor kedua dari View Class berisi implementasi atribut default
untuk kita. karena tidak ada implementasi atribut, maka kita akan mendapatkan
inflate exception. jika kita ingin menyingkirkan InflateException
di
atas, kita perlu menambahkan constructor view kedua. Maka kode akhir nya akan menjadi
seperti ini:
class CircleView(context: Context, attrs: AttributeSet): View(context,attrs) {
private val paint = Paint()
private val centerOfX = 340F // center of circle on X axis
private val centerOfY = 340F // center of circle on Yaxis
private val radius = 140F // radius of circle
init {
paint.color = ContextCompat.getColor(context,android.R.color.holo_green_light)
paint.strokeWidth = 40F
paint.style = Paint.Style.STROKE
}
override fun onDraw(canvas: Canvas?) {
canvas?.drawCircle(centerOfX,centerOfY,radius,paint)
super.onDraw(canvas)
}
}
Kita akan membahas lebih lanjut mengenai istilah atribut pada artikel berikutnya. Mari kita istirahat sejenak sambil menikmati kopi โ๏ธ, karena kita baru saja membuat Custom View pertama kita ๐.
Sampai bertemu di artikel selanjutnya, Hatur Nuhun & sampai jumpa ๐