Özel görünüm bileşenleri oluşturma

Compose yöntemini deneyin
Jetpack Compose, Android için önerilen kullanıcı arayüzü araç setidir. Compose'da düzenlerle nasıl çalışacağınızı öğrenin.

Android, kullanıcı arayüzünüzü oluşturmak için temel düzen sınıflarına View ve ViewGroup dayalı, gelişmiş ve güçlü bir bileşenli model sunar. Platformda, kullanıcı arayüzünüzü oluşturmak için kullanabileceğiniz çeşitli önceden oluşturulmuş View ve ViewGroup alt sınıflar (sırasıyla widget'lar ve düzenler olarak adlandırılır) bulunur.

Kullanılabilir widget'ların kısmi listesinde Button, TextView, EditText, ListView, CheckBox, RadioButton, Gallery, Spinner ve daha özel amaçlı AutoCompleteTextView, ImageSwitcher ve TextSwitcher yer alır.

Kullanabileceğiniz düzenler arasında LinearLayout, FrameLayout, RelativeLayout ve diğerleri yer alır. Daha fazla örnek için Sık kullanılan düzenler başlıklı makaleyi inceleyin.

Önceden oluşturulmuş widget'lardan veya düzenlerden hiçbiri ihtiyaçlarınızı karşılamıyorsa kendi Viewalt sınıfınızı oluşturabilirsiniz. Mevcut bir widget'ta veya düzende yalnızca küçük ayarlamalar yapmanız gerekiyorsa widget'ı ya da düzeni alt sınıfa ayırabilir ve yöntemlerini geçersiz kılabilirsiniz.

Kendi View alt sınıflarınızı oluşturmak, bir ekran öğesinin görünümü ve işlevi üzerinde hassas kontrol sahibi olmanızı sağlar. Özel görünümlerle elde ettiğiniz kontrol hakkında fikir vermek için bu görünümlerle yapabileceklerinize dair bazı örnekleri aşağıda bulabilirsiniz:

  • Tamamen özel olarak oluşturulmuş bir View türü oluşturabilirsiniz. Örneğin, 2D grafikler kullanılarak oluşturulmuş ve analog elektronik kontrole benzeyen bir "ses kontrolü" düğmesi.
  • Bir grup View bileşeni yeni bir tek bileşende birleştirebilirsiniz. Örneğin, birleşik kutu (açılır liste ve serbest giriş metin alanının birleşimi), çift bölmeli seçici kontrolü (her birinde bir liste bulunan sol ve sağ bölme; hangi öğenin hangi listede olduğunu yeniden atayabilirsiniz) gibi öğeler oluşturabilirsiniz.
  • Bir EditText bileşenin ekranda oluşturulma şeklini geçersiz kılabilirsiniz. Not Defteri örnek uygulamasında, çizgili bir not defteri sayfası oluşturmak için bu özellikten iyi bir şekilde yararlanılır.
  • Tuşlara basma gibi diğer etkinlikleri yakalayabilir ve bunları özel bir şekilde (ör. oyun için) işleyebilirsiniz.

Aşağıdaki bölümlerde, özel görünümlerin nasıl oluşturulacağı ve uygulamanızda nasıl kullanılacağı açıklanmaktadır. Ayrıntılı referans bilgileri için View sınıfına bakın.

Temel yaklaşım

Kendi View bileşenlerinizi oluşturmak için bilmeniz gerekenlere genel bir bakış:

  1. Mevcut bir View sınıfını veya alt sınıfını kendi sınıfınızla genişletin.
  2. Üst sınıftaki bazı yöntemleri geçersiz kılın. Geçersiz kılınacak üst sınıf yöntemleri on ile başlar. Örneğin, onDraw(), onMeasure() ve onKeyDown(). Bu, on veya ListActivity içindeki Activity etkinliklerine benzer. Bu etkinlikleri yaşam döngüsü ve diğer işlevsel kancalar için geçersiz kılarsınız.
  3. Yeni uzantı sınıfınızı kullanın. İşlem tamamlandıktan sonra, yeni uzantı sınıfınızı temel aldığı görünüm yerine kullanabilirsiniz.

Tamamen özelleştirilmiş bileşenler

Tamamen özelleştirilmiş grafik bileşenleri oluşturabilir ve bunları istediğiniz şekilde gösterebilirsiniz. Belki eski bir analog ölçere benzeyen grafik bir VU ölçer veya karaoke makinesiyle şarkı söylerken kelimeler arasında hareket eden bir topun yer aldığı, şarkı söyleme metin görünümü istiyorsunuzdur. Yerleşik bileşenleri ne kadar çok birleştirirseniz birleştirin, bu bileşenlerin yapamayacağı bir şey isteyebilirsiniz.

Neyse ki yalnızca hayal gücünüz, ekranın boyutu ve mevcut işlem gücüyle sınırlı olarak istediğiniz gibi görünen ve çalışan bileşenler oluşturabilirsiniz. Uygulamanızın masaüstü iş istasyonunuzdan önemli ölçüde daha az güce sahip bir cihazda çalışması gerekebileceğini unutmayın.

Tamamen özelleştirilmiş bir bileşen oluşturmak için aşağıdakileri göz önünde bulundurun:

  • Genişletebileceğiniz en genel görünüm View'dir. Bu nedenle, genellikle yeni süper bileşeninizi oluşturmak için bunu genişleterek başlarsınız.
  • XML'den özellikler ve parametreler alabilen bir oluşturucu sağlayabilir ve VU ölçerin rengi ile aralığı veya iğnenin genişliği ve sönümlemesi gibi kendi özelliklerinizi ve parametrelerinizi kullanabilirsiniz.
  • Muhtemelen kendi etkinlik dinleyicilerinizi, özellik erişimcilerinizi ve değiştiricilerinizi oluşturmak ve bileşen sınıfınızda daha karmaşık davranışlar kullanmak istersiniz.
  • onMeasure() değerini geçersiz kılmak istediğinizden neredeyse kesinlikle eminsinizdir ve bileşenin bir şeyler göstermesini istiyorsanız onDraw() değerini de geçersiz kılmanız gerekir. Her ikisi de varsayılan davranışa sahip olsa da varsayılan onDraw() hiçbir şey yapmaz ve varsayılan onMeasure() her zaman 100x100 boyutunu ayarlar. Bu da muhtemelen istemeyeceğiniz bir durumdur.
  • Gerekirse diğer on yöntemlerini de geçersiz kılabilirsiniz.

onDraw() ve onMeasure() işlevlerini genişletme

onDraw() yöntemi, istediğiniz her şeyi uygulayabileceğiniz bir Canvas sunar: 2D grafikler, diğer standart veya özel bileşenler, stilize edilmiş metin ya da aklınıza gelebilecek başka herhangi bir şey.

onMeasure() biraz daha karmaşıktır. onMeasure(), bileşeniniz ile kapsayıcısı arasındaki oluşturma sözleşmesinin kritik bir parçasıdır. onMeasure(), içerdiği parçaların ölçümlerini verimli ve doğru bir şekilde raporlamak için geçersiz kılınmalıdır. Bu durum, ebeveynin sınır koşulları (onMeasure() yöntemine aktarılır) ve genişlik ile yüksekliğin hesaplanmasının ardından setMeasuredDimension() yönteminin ölçülen genişlik ve yükseklikle çağrılması zorunluluğu nedeniyle biraz daha karmaşık hale gelir. Bu yöntemi geçersiz kılınan bir onMeasure() yönteminden çağırmazsanız ölçüm sırasında istisna oluşur.

onMeasure()'nın uygulanması genel olarak şu şekilde yapılır:

  • Geçersiz kılınan onMeasure() yöntemi, genişlik ve yükseklik spesifikasyonlarıyla birlikte çağrılır. Bu spesifikasyonlar, oluşturduğunuz genişlik ve yükseklik ölçümlerindeki kısıtlamalar için gereklilik olarak kabul edilir. widthMeasureSpec ve heightMeasureSpec parametreleri, boyutları temsil eden tam sayı kodlardır. Bu spesifikasyonların gerektirebileceği kısıtlamalarla ilgili tam referansı, View.onMeasure(int, int) bölümündeki referans belgelerinde bulabilirsiniz. Bu referans belgelerinde, ölçüm işleminin tamamı da açıklanmaktadır.
  • Bileşeninizin onMeasure() yöntemi, bileşeni oluşturmak için gereken bir ölçü genişliği ve yüksekliği hesaplar. Bu işlev, belirtilen spesifikasyonları aşabilse de bu spesifikasyonlar dahilinde kalmaya çalışmalıdır. Bu durumda üst öğe, kırpma, kaydırma, istisna oluşturma veya onMeasure() öğesinden farklı ölçüm spesifikasyonlarıyla tekrar denemesini isteme gibi seçeneklerden birini belirleyebilir.
  • Genişlik ve yükseklik hesaplandığında, hesaplanan ölçülerle setMeasuredDimension(int width, int height) yöntemini çağırın. Bunu yapmazsanız istisna oluşur.

Çerçevenin görünümlerde çağırdığı diğer standart yöntemlerin özeti aşağıda verilmiştir:

Kategori Yöntemler Açıklama
içerik üretimi Markalar Görünüm koddan oluşturulduğunda çağrılan bir oluşturucu biçimi ve görünüm bir düzen dosyasından genişletildiğinde çağrılan bir biçim vardır. İkinci form, düzen dosyasında tanımlanan özellikleri ayrıştırır ve uygular.
onFinishInflate() Bir görünüm ve tüm alt öğeleri XML'den şişirildikten sonra çağrılır.
Düzen onMeasure(int, int) Bu görünüm ve tüm alt öğeleri için boyut koşullarını belirlemek üzere çağrılır.
onLayout(boolean, int, int, int, int) Bu görünümün tüm alt öğelerine boyut ve konum ataması gerektiğinde çağrılır.
onSizeChanged(int, int, int, int) Bu görünümün boyutu değiştirildiğinde çağrılır.
Çizim onDraw(Canvas) Görünümün içeriğini oluşturması gerektiğinde çağrılır.
Etkinlik işleme onKeyDown(int, KeyEvent) Bir tuşa basma etkinliği gerçekleştiğinde çağrılır.
onKeyUp(int, KeyEvent) Bir tuşu bırakma etkinliği gerçekleştiğinde çağrılır.
onTrackballEvent(MotionEvent) Bir trackball hareket etkinliği gerçekleştiğinde çağrılır.
onTouchEvent(MotionEvent) Dokunmatik ekran hareket etkinliği gerçekleştiğinde çağrılır.
Odak onFocusChanged(boolean, int, Rect) Görünüm odak kazandığında veya kaybettiğinde çağrılır.
onWindowFocusChanged(boolean) Görünümü içeren pencere odak kazandığında veya odağı kaybettiğinde çağrılır.
Ekleme onAttachedToWindow() Görünüm bir pencereye eklendiğinde çağrılır.
onDetachedFromWindow() Görünüm penceresinden ayrıldığında çağrılır.
onWindowVisibilityChanged(int) Görünümü içeren pencerenin görünürlüğü değiştirildiğinde çağrılır.

Bileşik kontroller

Tamamen özelleştirilmiş bir bileşen oluşturmak istemiyorsanız ancak mevcut kontrollerden oluşan yeniden kullanılabilir bir bileşen oluşturmak istiyorsanız bileşik bileşen (veya bileşik kontrol) oluşturmak en iyi seçenek olabilir. Özetle, bu özellik daha atomik kontrolleri veya görünümleri tek bir şey olarak ele alınabilecek mantıksal bir öğe grubunda bir araya getirir. Örneğin, bir birleşik kutu, tek satırlık bir EditText alan ile eklenmiş bir pop-up liste içeren bitişik bir düğmenin birleşimi olabilir. Kullanıcı düğmeye dokunup listeden bir öğe seçerse EditText alanı doldurulur. Ancak kullanıcılar isterlerse doğrudan EditText alanına da yazabilir.

Android'de bunu yapmak için kullanabileceğiniz iki görünüm daha vardır: Spinner ve AutoCompleteTextView. Bununla birlikte, birleşik kutu için bu konsept iyi bir örnek teşkil eder.

Bileşik bileşen oluşturmak için aşağıdakileri yapın:

  • Activity ile olduğu gibi, kapsanan bileşenleri oluşturmak için bildirimsel (XML tabanlı) yaklaşımı kullanın veya bunları kodunuzdan programatik olarak yerleştirin. Genellikle başlangıç noktası bir tür Layout olur. Bu nedenle, Layout öğesini genişleten bir sınıf oluşturun. Birleşik kutu söz konusu olduğunda, yatay yönlendirmeye sahip bir LinearLayout kullanabilirsiniz. İçine başka düzenler yerleştirebilirsiniz. Böylece bileşik bileşen, isteğe bağlı olarak karmaşık ve yapılandırılmış olabilir.
  • Yeni sınıfın oluşturucusunda, üst sınıfın beklediği tüm parametreleri alın ve bunları önce üst sınıf oluşturucusuna iletin. Ardından, yeni bileşeninizde kullanmak üzere diğer görünümleri ayarlayabilirsiniz. EditText alanını ve pop-up listeyi burada oluşturursunuz. Oluşturucunuzun çekip kullanabileceği XML'ye kendi özelliklerinizi ve parametrelerinizi ekleyebilirsiniz.
  • İsteğe bağlı olarak, kapsanan görünümlerinizin oluşturabileceği etkinlikler için işleyiciler oluşturun. Örneğin, liste öğesi tıklama dinleyicisi için bir dinleyici yöntemi, liste seçimi yapıldığında EditText içeriğini günceller.
  • İsteğe bağlı olarak, erişim yöntemleri ve değiştiricilerle kendi özelliklerinizi oluşturun. Örneğin, EditText değeri başlangıçta bileşende ayarlansın ve gerektiğinde içeriği sorgulansın.
  • İsteğe bağlı olarak onDraw() ve onMeasure() değerlerini geçersiz kılın. Düzenin muhtemelen sorunsuz çalışacak varsayılan davranışı olduğundan, Layout genişletilirken bu genellikle gerekli değildir.
  • İsteğe bağlı olarak, belirli bir tuşa dokunulduğunda birleşik kutunun pop-up listesinden belirli varsayılan değerleri seçmek için on gibi diğer onKeyDown() yöntemlerini geçersiz kılın.

Özel denetim için temel olarak Layout kullanmanın aşağıdaki gibi avantajları vardır:

  • Düzeni, etkinlik ekranında olduğu gibi bildirimli XML dosyalarını kullanarak belirtebilir veya görünümleri programatik olarak oluşturup kodunuzdaki düzene yerleştirebilirsiniz.
  • onDraw() ve onMeasure() yöntemlerinin yanı sıra diğer on yöntemlerin çoğu uygun davranışa sahiptir. Bu nedenle, bunları geçersiz kılmanız gerekmez.
  • İstediğiniz kadar karmaşık bileşik görünümler oluşturabilir ve bunları tek bir bileşenmiş gibi yeniden kullanabilirsiniz.

Mevcut bir görünüm türünü değiştirme

İstediğiniz gibi bir bileşen varsa bu bileşeni genişletebilir ve değiştirmek istediğiniz davranışı geçersiz kılabilirsiniz. Tamamen özelleştirilmiş bir bileşenle yaptığınız her şeyi yapabilirsiniz ancak View hiyerarşisinde daha uzmanlaşmış bir sınıfla başlayarak istediğiniz davranışı ücretsiz olarak elde edebilirsiniz.

Örneğin, NotePad örnek uygulaması, Android platformunu kullanmanın birçok yönünü gösterir. Bunlardan biri, çizgili not defteri oluşturmak için EditText görünümünü genişletmektir. Bu mükemmel bir örnek değildir ve bunu yapmak için kullanılan API'ler değişebilir ancak bu örnek, temel ilkeleri gösterir.

Henüz yapmadıysanız NotePad örneğini Android Studio'ya aktarın veya sağlanan bağlantıyı kullanarak kaynağa göz atın. Özellikle LinedEditText tanımını NoteEditor.java dosyasında inceleyin.

Bu dosyada dikkat etmeniz gereken bazı noktalar:

  1. Tanım

    Sınıf, şu satırla tanımlanır:
    public static class LinedEditText extends EditText

    LinedEditText, NoteEditor etkinliğinde bir iç sınıf olarak tanımlanır ancak NoteEditor sınıfının dışından NoteEditor.LinedEditText olarak erişilebilmesi için herkese açıktır.

    Ayrıca, LinedEditText, static'dir. Yani, üst sınıftaki verilere erişmesini sağlayan "sentez yöntemleri" oluşturmaz. Bu nedenle, NoteEditor ile yakından ilişkili bir şey olmaktan ziyade ayrı bir sınıf gibi davranır. Bu, dış sınıftaki duruma erişmeleri gerekmeyen iç sınıfları oluşturmanın daha temiz bir yoludur. Oluşturulan sınıfın küçük kalmasını sağlar ve diğer sınıflarda kolayca kullanılabilmesine olanak tanır.

    LinedEditText, bu durumda özelleştirilecek görünüm olan EditText'ü genişletir. İşlemi tamamladığınızda yeni sınıf, normal EditText görünümünün yerine kullanılabilir.

  2. Sınıf başlatma

    Her zaman olduğu gibi, önce süper metot çağrılır. Bu, varsayılan bir oluşturucu değildir ancak parametreli bir oluşturucudur. EditText, bir XML düzen dosyasından şişirildiğinde bu parametrelerle oluşturulur. Bu nedenle, oluşturucunun bunları alıp üst sınıf oluşturucusuna da iletmesi gerekir.

  3. Geçersiz kılınan yöntemler

    Bu örnekte yalnızca onDraw() yöntemi geçersiz kılınır. Ancak kendi özel bileşenlerinizi oluştururken diğerlerini de geçersiz kılmanız gerekebilir.

    Bu örnekte, onDraw() yöntemini geçersiz kılmak, EditText görünüm tuvaline mavi çizgiler çizmenize olanak tanır. Tuval, geçersiz kılınan onDraw() yöntemine iletilir. super.onDraw() yöntemi, yöntemi sona ermeden önce çağrılır. Üst sınıf yöntemi çağrılmalıdır. Bu durumda, dahil etmek istediğiniz çizgileri boyadıktan sonra bu işlevi en son kullanın.

  4. Özel bileşen

    Artık özel bileşeniniz var ancak bunu nasıl kullanabilirsiniz? Not defteri örneğinde, özel bileşen doğrudan bildirim temelli düzenden kullanıldığından res/layout klasöründeki note_editor.xml öğesine bakın:

    <view xmlns:android="http://schemas.android.com/apk/res/android"
        class="com.example.android.notepad.NoteEditor$LinedEditText"
        android:id="@+id/note"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/transparent"
        android:padding="5dp"
        android:scrollbars="vertical"
        android:fadingEdge="vertical"
        android:gravity="top"
        android:textSize="22sp"
        android:capitalize="sentences"
    />

    Özel bileşen, XML'de genel bir görünüm olarak oluşturulur ve sınıf, tam paket kullanılarak belirtilir. Tanımladığınız iç sınıf, Java programlama dilinde iç sınıflara başvurmak için standart bir yöntem olan NoteEditor$LinedEditText gösterimi kullanılarak referans alınır.

    Özel görünüm bileşeniniz iç sınıf olarak tanımlanmamışsa görünüm bileşenini XML öğe adıyla bildirebilir ve class özelliğini hariç tutabilirsiniz. Örneğin:

    <com.example.android.notepad.LinedEditText
      id="@+id/note"
      ... />

    LinedEditText sınıfının artık ayrı bir sınıf dosyası olduğuna dikkat edin. Sınıf, NoteEditor sınıfının içine yerleştirildiğinde bu teknik çalışmaz.

    Tanımdaki diğer özellikler ve parametreler, özel bileşen oluşturucusuna aktarılan ve ardından EditText oluşturucusuna aktarılanlardır. Bu nedenle, EditText görünümü için kullandığınız parametrelerle aynıdır. Kendi parametrelerinizi de ekleyebilirsiniz.

Özel bileşenler oluşturmak, ihtiyacınız olduğu kadar karmaşık olabilir.

Daha karmaşık bir bileşen, daha fazla on yöntemi geçersiz kılabilir ve kendi yardımcı yöntemlerini sunarak özelliklerini ve davranışını önemli ölçüde özelleştirebilir. Tek sınır, hayal gücünüz ve bileşenin yapmasını istediğiniz işlemlerdir.