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

"Oluştur" 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, View ve ViewGroup temel düzen sınıflarını temel alan gelişmiş ve güçlü bileşenlere ayrılmış bir model sunar. Platformda, kullanıcı arayüzünüzü oluşturmak için kullanabileceğiniz, sırasıyla widget ve düzen adı verilen çeşitli önceden oluşturulmuş View ve ViewGroup alt sınıfları bulunur.

Kullanılabilir widget'ların kısmi listesinde Button, TextView, EditText, ListView, CheckBox, RadioButton, Gallery, Spinner ile daha özel amaca yönelik olan AutoCompleteTextView, ImageSwitcher ve TextSwitcher bulunmaktadır.

Kullanılabilen düzenler arasında LinearLayout, FrameLayout, RelativeLayout ve diğerleri yer alır. Daha fazla örnek için Genel düzenler bölümüne bakın.

Önceden oluşturulmuş widget'lardan veya düzenlerden hiçbiri ihtiyaçlarınızı karşılamıyorsa kendi View alt sınıfınızı oluşturabilirsiniz. Mevcut bir widget'ta veya düzende yalnızca küçük ayarlamalar yapmanız gerekiyorsa widget'ı veya düzeni alt gruplara 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. Aşağıda, özel görünümlerle elde edebileceğiniz denetim hakkında bir fikir vermek için bu görünümlerle yapabileceklerinize ilişkin bazı örnekler verilmiştir:

  • Tamamen özel olarak oluşturulmuş bir View türü oluşturabilirsiniz. Örneğin, 2D grafiklerle oluşturulan, analog elektronik kontrole benzeyen "ses kontrol düğmesi" oluşturabilirsiniz.
  • View bileşen grubunu yeni tek bir bileşende birleştirebilirsiniz. Örneğin bir birleşik kutu (pop-up liste ve ücretsiz giriş metin alanının kombinasyonu), çift bölmeli seçici kontrolü (her birinde hangi öğenin hangi listede yer aldığını yeniden atayabileceğiniz bir liste içeren sol ve sağ bölme) gibi bir şey yapabilirsiniz.
  • Bir EditText bileşeninin ekranda oluşturulma şeklini geçersiz kılabilirsiniz. NotePad örnek uygulaması, satırlı bir not defteri sayfası oluşturmak için bu yöntemi iyi bir efekt uygulamak için kullanır.
  • Tuşlara basma gibi diğer etkinlikleri yakalayabilir ve bunları, oyun gibi özel bir şekilde işleyebilirsiniz.

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

Temel yaklaşım

Aşağıda, kendi View bileşenlerinizi oluşturmak için bilmeniz gerekenlere dair genel bir bakış bulabilirsiniz:

  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 yöntemlerden bazılarını geçersiz kılın. Geçersiz kılma üst sınıf yöntemleri on ile başlar (ör. onDraw(), onMeasure() ve onKeyDown()). Bu, yaşam döngüsü ve diğer işlev kancaları için geçersiz kıldığınız Activity veya ListActivity içindeki on etkinliklerine benzer.
  3. Yeni uzantı sınıfınızı kullanın. Tamamlandıktan sonra, temel alınan görünümün yerine yeni uzantı sınıfınızı kullanabilirsiniz.

Tamamen özelleştirilmiş bileşenler

İstediğiniz gibi görünen tamamen özelleştirilmiş grafik bileşenleri oluşturabilirsiniz. Belki eski bir analog göstergeye benzeyen grafiksel bir VU ölçüm cihazı veya karaoke makinesiyle birlikte şarkı söylerken zıplayan bir topun kelimelerle birlikte hareket ettiği, şarkıya eşlik etme özellikli bir metin görünümü isteyebilirsiniz. Yerleşik bileşenlerin yapamayacağı bir şeyi nasıl bir araya getirirseniz kullanın.

Neyse ki, uygulamanızın masaüstü iş istasyonunuzdan çok daha az güç tüketen bir şey üzerinde çalışması gerekebileceğini aklınızda bulundurarak, sadece hayal gücünüz, ekranın boyutu ve mevcut işlem gücüyle sınırlı, istediğiniz gibi görünen ve davranan bileşenler oluşturabilirsiniz.

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 görünümüdür. Bu nedenle, yeni süper bileşeninizi oluşturmak için genellikle bu görünümü genişleterek başlarsınız.
  • XML'den özellik ve parametreler alabilen bir oluşturucu sağlayabilir ve VU sayacın rengi ve aralığı veya iğnenin genişliği ve sönümlemesi gibi kendi özellik ve parametrelerinizi kullanabilirsiniz.
  • Bileşen sınıfınızda daha sofistike davranışların yanı sıra kendi etkinlik işleyicilerinizi, mülk erişimcilerinizi ve değiştiricilerinizi oluşturmak muhtemelen isteyebilirsiniz.
  • Neredeyse kesinlikle onMeasure() politikasını geçersiz kılmak istersiniz ve ayrıca, bileşenin bir şey 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 boyutu muhtemelen pek kullanmak istemezsiniz.
  • Ayrıca, diğer on yöntemlerini de gerektiği gibi geçersiz kılabilirsiniz.

onDraw() ve onMeasure() işlevini genişletin

onDraw() yöntemi, 2D grafikler, diğer standart veya özel bileşenler, stil özellikli metin ya da aklınıza gelebilecek diğer her şeyi uygulayabileceğiniz bir Canvas sağlar.

onMeasure() biraz daha karmaşık. onMeasure(), bileşeniniz ile kapsayıcısı arasındaki oluşturma sözleşmesinin önemli bir parçasıdır. onMeasure(), içerdiği bölümlerin ölçümlerinin verimli ve doğru bir şekilde raporlanabilmesi için geçersiz kılınmalıdır. Bu işlem, üst öğenin sınır gereksinimleri (onMeasure() yöntemine aktarılır) ve hesaplandıktan sonra ölçülen genişlik ve yükseklikle setMeasuredDimension() yönteminin çağrılması nedeniyle biraz daha karmaşık hale gelir. Bu yöntemi geçersiz kılınmış bir onMeasure() yönteminden çağırmazsanız ölçüm zamanında bir istisna oluşturulur.

Genel olarak onMeasure() uygulaması aşağıdaki gibi görünür:

  • Geçersiz kılınan onMeasure() yöntemi, oluşturduğunuz genişlik ve yükseklik ölçümleriyle ilgili kısıtlamalara yönelik gereksinimler olarak kabul edilen genişlik ve yükseklik spesifikasyonlarıyla birlikte çağrılır. widthMeasureSpec ve heightMeasureSpec parametreleri, boyutları temsil eden tam sayı kodlarıdır. Bu spesifikasyonların gerektirebileceği kısıtlamaların türüne tam bir referans için View.onMeasure(int, int) altındaki referans belgelerine bakın. Bu referans belgeleri de ölçüm işleminin tamamını açıklar.
  • Bileşeninizin onMeasure() yöntemi, bileşeni oluşturmak için gereken bir ölçüm genişliği ve yüksekliği hesaplar. Sınırlamaları aşabilse de aktarılan spesifikasyonlara uymaya çalışmalıdır. Bu durumda ebeveyn, kırpma, kaydırma, istisna oluşturma veya onMeasure() kullanıcısının farklı ölçüm teknikleriyle tekrar denemesini isteme gibi işlemler yapmayı seçebilir.
  • Genişlik ve yükseklik hesaplandığında, hesaplanan ölçümlerle setMeasuredDimension(int width, int height) yöntemini çağırın. Bu işlemin sağlanmaması istisnai bir durumla sonuçlanır.

Çerçevenin görünümlerde gerektirdiği diğer standart yöntemlerin bir özetini burada bulabilirsiniz:

Kategori Yöntemler Açıklama
içerik üretimi Markalar Görünüm koddan oluşturulduğunda çağrılan oluşturucunun bir biçimi ve görünüm bir düzen dosyasından şişirildiğinde çağrılan bir form vardır. İkinci form, düzen dosyasında tanımlanan özellikleri ayrıştırır ve uygular.
onFinishInflate() Bir görünümden 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 gereksinimlerini belirlemek üzere çağrıldı.
onLayout(boolean, int, int, int, int) Bu görünümün tüm alt öğelerine bir 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ş etkinliği gerçekleştiğinde çağrılır.
onKeyUp(int, KeyEvent) Bir tuş etkinliği gerçekleştiğinde çağrılır.
onTrackballEvent(MotionEvent) Bir iztopu hareket etkinliği gerçekleştiğinde çağrılır.
onTouchEvent(MotionEvent) Dokunmatik ekran hareketiyle ilgili bir etkinlik gerçekleştiğinde çağrılır.
Odak onFocusChanged(boolean, int, Rect) Görüntü odağı toplandığında veya kaybettiğinde çağrılır.
onWindowFocusChanged(boolean) Görünümü içeren pencere odaklandığında veya kaybolduğunda çağrılır.
Ekleniyor 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 yerine mevcut bir grup denetimden oluşan yeniden kullanılabilir bir bileşen oluşturmak istiyorsanız birleşik bileşen (veya bileşik kontrol) oluşturmak en iyi seçenek olabilir. Özetlemek gerekirse bu, bir dizi atomik kontrolü veya görünümü, tek bir şey olarak değerlendirilebilecek mantıksal bir öğe grubunda bir araya getirir. Örneğin, birleşik kutu, tek satırlık bir EditText alanı ile pop-up listesi ekli bitişik bir düğmenin kombinasyonu olabilir. Kullanıcı düğmeye dokunup listeden bir şey seçerse EditText alanı doldurulur. Ancak kullanıcı, tercih etmesi durumunda doğrudan EditText bölümüne bir şey yazabilir.

Android'de bunu yapmak için kullanılabilen iki görünüm daha vardır: Spinner ve AutoCompleteTextView. Ne olursa olsun, bu birleşik kutu kavramı iyi bir örnektir.

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

  • Activity ürününde olduğu gibi, içerdiği bileşenleri oluşturmak için bildirim temelli (XML tabanlı) yaklaşımı kullanın veya bileşenleri kodunuzdan programatik olarak iç içe yerleştirin. Normal başlangıç noktası bir tür Layout olduğu için Layout uzantısına sahip bir sınıf oluşturun. Karma kutularda yatay yönlü bir LinearLayout kullanabilirsiniz. Bileşik bileşen rastgele karmaşık ve yapılandırılmış olabilir. Böylece, içine diğer düzenleri iç içe yerleştirebilirsiniz.
  • Yeni sınıfın oluşturucusunda, üst sınıfın beklediği parametreleri alın ve önce üst sınıf oluşturucuya iletin. Ardından, yeni bileşeninizde kullanmak üzere diğer görünümleri ayarlayabilirsiniz. EditText alanını ve pop-up listesini burada oluşturursunuz. Oluşturucunuzun alıp kullanabileceği XML'e kendi özelliklerinizi ve parametrelerinizi ekleyebilirsiniz.
  • İsterseniz, içerilen görünümlerinizin oluşturabileceği etkinlikler için işleyiciler oluşturabilirsiniz. Bir liste seçimi yapılırsa EditText içeriğini güncellemek için liste öğesi tıklama işleyicisi için bir işleyici yöntemi buna örnek olarak gösterilebilir.
  • Dilerseniz erişimciler ve değiştiricilerle kendi mülklerinizi oluşturabilirsiniz. Örneğin, EditText değerinin başlangıçta bileşende ayarlanmasına izin verin ve gerektiğinde içeriğini sorgulayın.
  • İsteğe bağlı olarak, onDraw() ve onMeasure() değerlerini geçersiz kılın. Düzen muhtemelen düzgün çalışan varsayılan davranışa sahip olduğundan bu işlem genellikle Layout genişletilirken gerekli değildir.
  • İsteğe bağlı olarak, diğer on yöntemlerini (ör. onKeyDown()) geçersiz kılın. Örneğin, belirli bir tuşa dokunulduğunda birleşik kutunun pop-up listesinden belirli varsayılan değerler seçin.

Özel kontrol için temel olarak Layout kullanmanın avantajları vardır. Örneğin:

  • Düzeni, etkinlik ekranında olduğu gibi bildirim temelli XML dosyalarını kullanarak belirtebilir veya programatik olarak görünümler oluşturup bunları kodunuzdaki düzene yerleştirebilirsiniz.
  • onDraw() ve onMeasure() yöntemleri ile diğer on yöntemlerinin çoğu uygun davranışa sahip olduğu için bunları geçersiz kılmanız gerekmez.
  • Hızlıca rastgele karmaşık bileşik görünümler oluşturabilir ve bunları tek bir bileşen gibi yeniden kullanabilirsiniz.

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

İstediğinize benzer bir bileşen varsa o 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 özel bir sınıfla başlayarak, istediğiniz şeyi ücretsiz olarak yapan bazı davranışları elde edebilirsiniz.

Örneğin, NotePad örnek uygulaması, Android platformunu kullanmanın birçok yönünü gösterir. Bunların arasında EditText görünümünü genişleterek çizgili not defteri oluşturuyoruz. Bu mükemmel bir örnek değildir ve bunu yapmaya yönelik API'ler değişebilir ama bu süreçte ilkeleri ortaya koymuştur.

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

Bu dosyada dikkat edilmesi gereken bazı noktalar şunlardır:

  1. Tanım

    Sınıf aşağıdaki satırla tanımlanır:
    public static class LinedEditText extends EditText

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

    Ayrıca LinedEditText, static değeridir. Yani üst sınıftaki verilere erişmesine izin veren "sentetik yöntemler" oluşturmaz. Bu, NoteEditor ile yakından ilgili değil, ayrı bir sınıf olarak davrandığı anlamına gelir. Bu, dış sınıftan durum erişimine ihtiyaç duymayan iç sınıflar oluşturmak için daha temiz bir yöntemdir. Oluşturulan sınıfı küçük tutar ve diğer sınıflardan kolayca kullanılabilmesini sağlar.

    LinedEditText, bu durumda özelleştirilebilecek görünüm olan EditText öğesini genişletir. Bitirdiğinizde yeni sınıf, normal EditText görünümünün yerini alabilir.

  2. Sınıf başlatma

    Her zaman olduğu gibi, ilk olarak süper çağrılır. Bu, varsayılan bir oluşturucu değildir ancak parametreleştirilmiş bir yapıdır. EditText, bir XML düzen dosyasından şişirildiğinde bu parametrelerle oluşturulur. Dolayısıyla, oluşturucunun bunları alması ve üst sınıf oluşturucuya da iletmesi gerekir.

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

    Bu örnek yalnızca onDraw() yöntemini geçersiz kılar ancak kendi özel bileşenlerinizi oluştururken diğerlerini geçersiz kılmanız gerekebilir.

    Bu örnek için onDraw() yöntemini geçersiz kılarak EditText görünümü tuvalindeki mavi çizgileri boyayabilirsiniz. Tuval, geçersiz kılınan onDraw() yöntemine geçirilir. super.onDraw() yöntemi, yöntem sona ermeden önce çağrılır. Üst sınıf yöntemi çağrılmalıdır. Bu durumda, eklemek istediğiniz çizgileri boyadıktan sonra kodu en sonunda çağırın.

  4. Özel bileşen

    Artık özel bileşeniniz var, ancak nasıl kullanabilirsiniz? NotePad örneğinde özel bileşen doğrudan bildirim temelli düzenden kullanılır. Bu nedenle 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ıfa, Java programlama dilinde iç sınıfları belirtmenin standart bir yolu olan NoteEditor$LinedEditText gösterimi kullanılarak referans verilir.

    Ö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 tanımlayıp 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 özellik ve parametreler, özel bileşen oluşturucuya iletilen ve daha sonra EditText oluşturucuya geçirilenlerdir. Dolayısıyla, bunlar bir EditText görünümü için kullandığınız parametrelerle aynı olur. Kendi parametrelerinizi de ekleyebilirsiniz.

Özel bileşenler oluşturmak, yalnızca ihtiyacınız kadar karmaşıktır.

Daha gelişmiş bir bileşen daha da fazla on yöntemini geçersiz kılıp 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 ne yapması gerektiğidir.