Bu yazıda Android uygulama geliştirirken kullandığımız viewlara benzer kendi custom view componentimizi yazmayı anlatacağım. Bu konu hakkında Türkçe kaynak neredeyse hiç yok. Olanlar ise onDraw() fonksiyonu içeren yolu gösteriyorlar. Eğer view içerisine şekil çizmeyecekseniz bu yol gereksiz. Detaylı bir şekilde okuyun kafanızda oturacaktır.
XML Tasarım Çalışma Mantığı
XML tasarımında kullandığımız her view yeni bir nesne aslında. Biz tasarımda android:id=”textview” ya da android:layout_width=”match_parent” gibi onlarca parametreyi bu classların constructor fonksiyonlarına gönderiyoruz. Fonksiyonlar içerisinde de bu parametreler parse edilip kullanılıyor.
Custom View Parametre Tanımlama
Projenizde res/values klasörü altına attrs.xml isimli bir dosya oluşturun. Bu dosya içerisine kendi viewimiz için gereken parametreleri aşağıdaki gibi tanımlayacağız. Formatlara intellisense yardımıyla bakabilirsiniz.
|
1 2 |
<attr name="customText" format="reference" /> <attr name="customTextSize" format="dimension" /> |
Yukarıda parametreleri tanımladıktan sonra aşağıdaki gibi name kısmına kendi class ismimizi yazarak componentimizin bu parametreleri alabileceğini belirtiyoruz.
|
1 2 3 4 |
<declare-styleable name="CustomButton"> <attr name="customText" /> <attr name="customTextSize" /> </declare-styleable> |
Custom View Class Oluşturma
Projenizde bir Java classı oluşturun. Şu şekilde: CustomButton.java. View özelliklerini kullanabilmek için kendi sınıfımızı LinearLayout sınıfından türetiyoruz. Basit olması açısından LinearLayout’u seçtim. Buraya takılmayın. Amacımız Android’in hazır olarak verdiği View sınıfını LinearLayout üzerinden alıp kullanmak.
|
1 2 3 |
public final class CustomButton extends LinearLayout { ... } |
Üç adet constructor oluşturmamız gerekiyor. Bu constructor fonksiyonlar class üzerinden yeni bir nesne oluştuğunda çalışacak. init(), initViews() ve parseAttributes() adında üç adet fonksiyon oluşturun. parseAttributes() adında anlıyacağınız gibi viewe gönderdiğimiz parametreli çekmek için. init() fonksiyonu ise viewi render etmeye yarıyor. initViews() ise inflate ettiğimiz xml dosyasındaki nesneleri tanımladığımız yer.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public final class CustomButton extends LinearLayout { public CustomButton(@NonNull Context context) { super(context); } public CustomButton(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public CustomButton(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } } |
Parametreleri çekerken herhangi bir crash yememek için try-catch içerisinde kullanın. Kullanmazsanız kesinlikle hata alacaksınız.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
public final class CustomButton extends LinearLayout { // Attributes private String customText; private int customTextSize = 999; // Views private TextView customButtonTvText; public CustomButton(@NonNull Context context) { super(context); init(context); } public CustomButton(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); parseAttributes(context, attrs); init(context); } public CustomButton(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); parseAttributes(context, attrs); init(context); } private void parseAttributes(@NonNull Context context, @Nullable AttributeSet attrs) { TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomButton); try { if (typedArray.hasValue(R.styleable.CustomButton_text)) customText = typedArray.getString(R.styleable.CustomButton_customText); if (typedArray.hasValue(R.styleable.CustomButton_textSize)) customTextSize = typedArray.getDimensionPixelSize(R.styleable.CustomButton_customTextSize, 0); } catch (Throwable t) { t.printStackTrace(); } finally { try { typedArray.recycle(); } catch (Throwable t) { t.printStackTrace(); } } } private void initViews() { customButtonTvText = findViewById(R.id.custom_button_tv_text); } private void init(@NonNull Context context) { inflate(context, R.layout.button_custom, CustomButton.this); initViews(); if (customText != null) customButtonTvText.setText(customText); if (customTextSize != 999) customButtonTvText.setTextSize(TypedValue.COMPLEX_UNIT_PX, customTextSize); } public void setText(CharSequence text) { customButtonTvText.setText(text); } } |
En önemli olan yer burası. Gördüğünüz gibi inflate kullanıyoruz. Daha önceden res/layout klasörü altında oluşturduğumuz button_custom.xml tasarımını kopyalamış oluyoruz aslında.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<?xml version="1.0" encoding="utf-8"?> <merge xmlns:android="http://schemas.android.com/apk/res/android"> <TextView android:id="@+id/custom_button_tv_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:ellipsize="end" android:gravity="center" android:singleLine="true" android:textAllCaps="true" android:textColor="@color/white" android:textSize="18sp" /> </merge> |
İşte bu kadar. Çok basit bir şekilde kendi custom view componentimizi oluşturduk. Artık projenizin her yerinde kullanabilirsiniz.
|
1 2 3 4 5 6 |
<com.example.app.CustomButton android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="12dp" app:customText="Tamam" app:customTextSize="18sp" /> |