Custom View ile Emoji Çizdirmek

Ömer Ateş
6 min readDec 20, 2020

--

Photo by Tengyart on Unsplash

Android platformunda klasik bir uygulama için ihtiyacımızı karşılayan birçok view sınıfı vardır. Bazı durumlarda ihtiyaçlarımızı özelleştiren bileşenler oluşturmak isteriz. Bu gibi durumları aşağıda sıralayabiliriz :

  • Modern kullanıcı arayüz tasarım veya animasyonlar
  • Farklı türde veri tiplerini gösterme
  • Bazı performans optimizasyonları
  • Esneklik ve tekrar kullanılabilirlik

Bu yazıda custom view oluşturmayı bir örnek üzerinden açıklamaya çalışacağım. Örneğimizde kullanıcının seçimleri doğrultusunda bir emojiyi üzgün ve gülümseyen emoji tiplerini çizdireceğiz.

Bu sayede:

  • Bir view sınıfı nasıl genişletilir?
  • Temelde şekil çizimleri nasıl yapılır ?
  • Xml tarafında çizdiğimiz component nasıl dahil edilir?

Bunları anlatmaya çalışacağım.

Custom View Nedir

Bir veri türünü UI da göstermek için birden fazla component sınıf bulunmaktadır . Örneğin: Button, Textview, Layout vb. Bazı durumlarda UI da farklı bir kullanıcı etkileşimi isterseniz bu durumda temel de kullandığınız sınıfları genişletmeniz gerekecektir.

Uygulama geliştirirken sıkça kullandığımız component olan butonu ele alalım. Farz edelim ki buton diye bir componentimiz yok ve sıfırdan oluşturacağız diyelim. Bu durumda tasarım, click eventları ya da diğer özellikleri de oluşturmamız gerecektir. İşte tam burada textview componenti devreye girmektedir. Textview de var olan istediğimiz özellikleri genişleterek kendi butonumuzu geliştirebiliriz. Android Sdk nın da yaptığı zaten budur:

Haydi başlayaşım 😊

FaceEmoji isminde bir class oluşturup view classını extend edelim.

Bu adımda view classının altı çizili olduğunu görürsünüz. Üzerine geldiğimizde bize “This type has a constructor, and thus must be initialized here” diye uyarı görürüz. Bu uyarının nedeni view classının en az bir constuctora sahip olması gerektiğidir.

Android View class Constuctorları

  1. constructor(context: Context): Yeni bir view oluşturmak için activity de contexte ihtiyaç duyar.
  2. constructor(context: Context, attrs: AttributeSet): Xml de yeni bir view örneği oluşturmak için.
  3. constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int): Belirlediğimiz bir temanın özelliğiyle xml de bir örnek oluşturmak için.
  4. constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int): Tema özelliklerinden veya style kaynağından xml de bir örnek oluşturmak için.

Yukarıdaki constuctorların hepsini kullanmak zorunda değiliz. Uygulamamızda yalnızca birini primary constructor olarak şöyle kullanacağız:

Şimdi ise custom view sınıfımızı xml görünümüne ekleyelim:

Artık custom bir componentiniz var 😍 Uygulamayı çalıştırdığınızda hiçbir görüntü alamayacaksınız çünkü henüz özelleştirme yapmadık. Şimdi emoji çizdirmeye başlayabiliriz.

Canvas Üzerine Çizim

Extend ettiğimiz view sınıfından tüm nesnelerin çizimi içinonDrawfonksiyonunu çağırıyoruz.

Emojideki nesneleri hepsini onDraw içerisine yazmak yerine her bir nesne için ilgili fonksiyonları oluşturup canvas parametresini veriyoruz.

Background Çizme

Aşağıda yazacağımız kodlar drawFaceBackground() fonksiyonu içerisinde olacaktır.

Burada neler oluyor ❓

  1. Emoji background rengini belirtip. FILL ile içerisini boyamasını istiyoruz.
  2. Emojinin yarıçapını hesapladığımız yerdir. İçerideki nesneleri bulduğumuz yarıçapa göre konumlandıracağız.
  3. drawCircle ile çizimin xy koordinatları, yarıçap uzunluğu ve style özelliklerini vererek bir daire çiziyoruz.
  4. View çizimleri yukarıdan aşağı doğru işlenmektedir. Burada arkaplanı çizdikten sonra border çizimi yapıyoruz. İçeri doldurmak için FILL kullanmıştık. Border için ise burada STROKE kullanıyoruz.
  5. Border çizimi arkaplan çiziminin üzerine olucağından daha küçük yarıçap uzunluğu vererek drawCircle ile çizimi sağlıyoruz.

Şimdi uygulamayı çalıştırdığınızda karşınıza aşağıdaki görüntü çıkacaktır.

Göz Çizme

Aşağıda yazacağımız kodlar drawEyes() fonksiyonu içerisinde olacaktır.

Burada neler oluyor ❓

  1. Göz rengini public tanımladığımız eyesColor olarak değiştiriyoruz ve style olarak çizimin içerisini doldurmasını istiyoruz.

2. RectF nesnesi kare dikdörtgen gibi 4 köşeli şekilleri çizmek için içerisinde 4 nokta bulunduran yapıdır. View boyutu oranında `(32%, 23%, 43%, 50%) değerlerini veriyoruz. Ardından drawOval() ile belirtilen ölçülerde oval çizim yaptırıyoruz. RectF hakkında daha fazla bilgi için buraya tıklayınız.

3. Bir önceki adımlarını tekrar diğer göz içinde yapıyoruz. Sadece değerleri değiştirerek.

Uygulamayı çalıştırdığınızda fal taşı gözleri görüyor olmalısınız 😳

Ağız Çizimi

Aşağıda yazacağımız kodlar drawMouth() fonksiyonu içerisinde olacaktır.

Burada neler oluyor ❓

  1. Path() belirlediğimiz noktalardan üzerinden bir yol çizilmek istendiğinde kullanılır. İlk adımda yolun başlangıç noktasını moveTo() fonksiyonuna (x0,y0) değerleri verilerek yapılır.
  2. quadTo() Başlangıç noktasını referans alarak (x2,y2) koordinatlarına kadar yol çizilir.
  3. (x2,y2) den (x3,y3) noktasına kadar bir eğri çizilir.
  4. Çizdiğimiz yolun içerisinin FILL ile boyanacağını söylüyoruz.
  5. En son, yolları canvas üzerine çiziyoruz.

Uygulamayı çalıştırdığınız da gülümseyen bir ağız gözükecektir 😅

Emojiyi Responsive Hale Getirme

Şimdiye kadar yaptığımız boyutlandırmaların tümü sabit bir size değişkeni üzerinden götürmüştük. Bazı durumlarda cihaz genişlik ve yükseliğine göre dinamik boyutlandırma yapmak isteriz ya da emoji viewini xml kısmında genişliği azaltıldığında emojinin tüm boyutları oranlı olarak azaltımasını isteyebiliriz. Bu case ler sonucunda imdadımıza view classından override ettiğimiz onMeasure fonksiyonu koşmaktadır.

Android onMeasure fonksiyonunda sayfa açıldığında görünümün genişlik ve yüksekliği hesaplanıp bize döndürür.

onMeasure içerisine size değişkenine dinamik boyut atamak için aşağıdaki kodları yazıyoruz.

  1. Parametre olarak verilen genişlik ve yüksekliği min fonskiyonu ile hangi değer küçükse onu baz alarak size değişkenine atıyoruz.
  2. size değişkenindeki değerimizi view da görünür kılmak, saklamak için setMeasured(size,size) fonskiyonunu çağırmalıyız.

Uygulamayı çalıştırdığınız da cihaz ekranına oranlı şekilde emojinin yerleştiğini göreceksiniz.

Custom Xml attributeleri Oluşturalım

Custom oluşturduğumuz emoji viewi için xml tarafından dinamik değişebilir yapmak için birtakım attributeler oluşturuyoruz. res values attrs.xml dosyası oluşturup aşağıda kodları yazıyoruz.

Burada neler oluyor ❓

  1. declare-styleable ile verdiğimi FaceEmoji sınıfımız için birtakım style ögelerini oluşturacağımız belirtiyoruz.
  2. Değişecek özellikleri belirttiğimiz yerdir. name ile birer id veriyoruz ve her biri için istediğimiz format türünü belirtiyoruz.

Şimdiki senaryomuzda 2 tane daha emoji oluşturacağız. Bir gülen emoji bir de mutsuz emoji olacak. Kullanıcı hangi emojiye tıklarsa asıl emojimiz de o duruma sahip olacaktır.

Ardından projeyi çalıştırdığınızda aşağıdaki görüntüyü elde edersiniz.

Oluşan iki emoji, xml kısmında verdiğimiz değerlerin hiçbirini uygulamadı çünkü view içerisinde onDraw da çizilebilmesi için ilgili özellikleri view içerisinde tanıtmalıyız. FaceEmoji sınıfını aşağıdaki kodlar ile güncelleyelim.

Güncellediğimiz yerler ne iş yapıyor ❓

  1. Değişen iki durum için sabit ifadeleri HAPPY ve SAD ile değişkenleriyle belirledik.
  2. Kullanıcı hiçbir özellik seçimi yapmaz ise hangi default değerlerin olacağını tanımladık.
  3. Kullanıcının hangi yüz ifadesine tıkladığını anlamak için happiniesState değişkeni tanımladık.
  4. Seçilen durum karşısında invalidate() ile sıfırdan onDraw içerisinde çizilmesini sağladık.
  5. Emoji view ilk çizildiğinde çalışacak initiçerisine bir setupAttributes fonksiyonu tanımladık.
  6. attrs.xml de tanımladığımız özellikleri bir dizi içerisine çağırıyoruz.
  7. typeArray içerisine aldığımız özellikleri belirttiğimiz ilgili değişkenlere atıyoruz.
  8. Belirttiğimiz özellikler bellekte kullanılmadığında bekletmemek için garbage collection ile temizleriz. Bunu recycle() fonksiyonu ile gerçekliyoruz.

Uygulamayı tekrar çalıştırdığınızda özelliklerin aktif olduğunuz görebilirsiniz.

2 Emoji de hala gülümsüyor. Bu durumda çizeceğimiz ağız yollarını aşağıdaki gibi güncelleyeceğiz.

Burada Ne yaptık ❓

  1. Her çizimde tüm çizdiğimiz emojileri sıfırlamamak, sadece o an çizilen emojiyi sıfırlamak için path classının reset() fonksiyonunu kullandık.
  2. Kullanıcının seçtiği duruma göre çizilen ağız yapısı koodinatlarını belirttik.

Uygulamayı tekrar çalıştırdığımızda tüm özelliklerin aktif olduğunu görebiliriz.

Son Adım ! Neredeyse Bitti 😊

2 durum butonuna click eventı vererek emoji değişimi tetikliyoruz:

Not: Geçen haftalarda Google’ın duyurmasıyla kotlin synthetics import deprecated olmuştur. Öneri olarak ViewBinding kullanabilirsiniz.

İşte bu kadar 😇 Sizde yaptığımız örnekteki gibi custom view olarak emoji dünyanızı oluşturabilirsiniz.

Projenin kaynak koduna buradan ulaşabilirsiniz. Vakit ayırıp okuduğunuz için teşekkür ederim. Beğendiğiniz takdirde alkışlarsanız sevinirim ❤️

Bu yazı raywenderlich web sitesindeki örnek uygulamadan çevrilmiştir.

--

--