Android – ListView ve Custom Adapter Kullanımı

android-wallpaper

Bir önceki yazımda artık kod örnekleri üzerinden devam edeceğimizi söylemiştik. Bir sonraki yazım, bir Web API‘dan GET methodu ile JSON formatında veri çekip, bunu parse edip ListView içinde göstermek üzerine olacak. Bundan dolayı bu yazımda başta ListView olmak üzere diğer View‘lar ve Layout‘lara deyinip ListView‘da nasıl veri göstereceğimizden bahsedeceğim.

Layout’lar

LinearLayout: İçine yerleştirilen View’ların yatay veya dikey olarak hizalanmasını sağlar.

TableLayout: İçine yerleştirilen View’ların tıpkı HTML’deki gibi tr/td mantığıyla yerleştirmemize olanak tanır. Bu olanağı TableRow layout’u ile sağlar.

GridLayout: İçine yerleştirilen View’ların satır ve sütün numarası verilerek yerleştirilmesidir. Burada dikkat edilmesi gereken içindeki View’lara verdiğiniz maksimum satır ve sütun büyüklüğünde GridLayout’da satır ve sütun tanımlaması yapmaktır.

RelativeLayout: İçine yerleştirilen View’ların layout’a göre veya birbirlerine göre konumlanmalarına sağlar. Bir nevi View’lar arasında ilişki kurar. Boyut, kenar boşlukları gibi uzunlukları kapsar.

Bir Layout için gerekli 3 attribute tanımlaması vardır. Bunlardan birincisi XML Namespace‘dir. XML Namespace (xmlns) en üstte bulunan (parent) layout’ta yapılır ise altlarda yapılmasına gerek yoktur. Bu XML’de meydana gelebilecek karışıklıkları engellemek içindir. Zira aynı attribute’un iki namespace’de de yer alması durumunda bu namespace’lere isim vermek gerekir. Namespace tanımlarken verilen URL adresi ise buradaki kalıba uygun biçimdedir veya bu adresteki veriye, kişiye veya kuruluşa özel yazılmıştır anlamındadır. Android‘de bu yazımızda biz “android” ve “tool” namespace’lerini kullanıyoruz. “android” ve “tool” namespace’larinin tanımlarını şu şekilde yapıyoruz:

xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"

Main Activity’mizde yer alan RelativeLayout‘un tanımlamasını da yukarıda bilgilerden yola çıkarak aşağıdaki gibi yapabiliriz, fakat bu zaten Android Studio’da boş layout dosyalarında hazır gelir.

<RelativeLayout
 xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 tools:context=".MainActivity"

<!-- Layout veya View'larda Attribute tanımlamaları burada yapılır --> >

</RelativeLayout>

View’larda ise isimlerinden anlaşılacağı üzere metin için TexView, buton için Button, resim için ImageView, resim butonu için ImageButton, internet sayfası görüntülemek için WebView, View’ların başlıcalarıdır.

ListView

Aslın konumuz olan ListView‘a gelirsek, adından anlaşılacağı üzere bu View’da bir şeyleri liste halinde gösterebiliyoruz.

ListView, herhangi bir java sınıfından objeleri listeleyebilir. Tek önemli olan bu objelerin bir Adapter aracılığıyla ListView‘a tanıtılması. Adapter, gerekli olan bilgileri ListView’ın her satırında gösterecektir. Adapter sadece ListView‘da kullanılmaz. AdapterView sınıfını extend eden yani AdapterView sınfının çocucğu olan (child) olan her şeyde kullanılabilir.

Adapter

Adapter, verileri bir layout dosyasına uygun olarak yani bir modele uygun biçimde View‘ın içinde göstermemizi sağlayan adaptördür. BaseAdapter sınıfını extend eder. Android, varsayılan adaptör desteği sunar. Yani kendi adaptör sınıfımızı ve o sınıfa uygun layout’u yazmaya gerek kalmadan varsayılan olarak metin (String) dizisini ListView’a atamayı sağlayan “ArrayAdapter“i kullanabiliriz.

Custom Adapter

Custom Adapter, ListView’da sadece metin değil daha farklı tipte veriyi daha farklı şekilde göstermemizi sağlayan bir yapıdır. Custom Adapter için bir layout dosyası ve bir de Custom Adapter sınıfı gereklidir. Layout dosyası, ListView’daki her satırın görünümünü ve componentlerini belirlemektedir. Custom Adapter, varsayılan adaptörleri veya BaseAdapter sınfını extend ederek türetilir.

Gerekli tanımlamaları yaptıktan sonra artık bunları kullanacağımız örnek programımıza geçelim. Örnek programımızda, ListView’da  kişilerin adları, telefonu ve resimlerini göstereceğimiz bir yapı kuracağız. Kişilerimizi bir liste olarak oluşturup, bunu ListView’da göstereceğiz. Bu kişileri elimizde liste olarak tutup (oluşturup) bunları ListView’da göstereceğimiz için ArrayAdapter’i extend eden PersonAdapter sınfımız ve bu ListView’ın her satırını belirleyecek olan Layout dosyamız olacaktır. Önce Layout dosyasını oluşturalım.

Projeye Layout Dosyası Ekleme

Creating Layout

Sol tarafta bulunan Project menüsünden res (Resources) altında bulunan layout klasörüne sağ tık yapın (1) . New menüsüne tıklayın (2). Layout resource file‘ı seçin (3).

Add Layout

Layout dosyasının adını girin (1). İpucu olarak belirtmek gerekirse isimlendirmelerde belirli standardınız olsun. Yani ,örnek olarak eğer ListView’da kullanacağınız bir layout ise “layout_listview_itemtemplate” tarzında bir isim anlaşılırlığı artıracaktır, veya eğer bir ListView’a ID veriyorsanız listview yerine listview_persons tarzında bir isimlendirmeyi tercih edebilirsiniz. Layout’da varsayılan olarak gelecek layout tipini seçiniz. Bunu daha sonradan değiştirebiliriz. Çok önemli olmamakla birlikte işimizi kolaylaştırmaktadır. Layout’un alt tarafında boşta kalan alanlar , ListView’ın satırlarına atanırken  otomatik olarak gözükmeyecektir.

Custom Adapter İçin Layout Oluşturma

Layout dosyasını oluşturduk. Şimdi içini dolduralım. Bizim 2 tane metin alanına (TextView) ve 1 tane resim alanına (ImageView) ihtiyacımız var. Bunları istersek layout’u açtıktan sonraki ekranda desing (tasarım) sekmesinden, istersek de text (xml kod) sekmesinden ekleyebiliriz. Öncelikle layout tipimiz RelativeLayout. Bunun nedeni componentlerin (bileşenler) boyutlarını ve konumlarını birbirine bağlayacağım ve biri değişirse birbirlerini değiştirmesini sağlayacağım. ImageView‘ı  yani kişi resmini sola yerleştiriyorum ve  sabit bir yükseklik-genişlik veriyorum. Yükseklik ve genişlik olarak 75dp veriyorum.

<ImageView
 android:layout_width="75dp"
 android:layout_height="75dp"
 android:id="@+id/imageView_personpic" />

ImageView‘ın soluna ve tepeden ImageView‘la aynı mesefade isim için bir TextView yerleştiriyorum. ImageView‘a bağlamamın nedeni eğer ImageView’ın konumu üstten bir şekilde değiştirse TextView’ın da o kadar aşağıya veya yukarıya kayması içindir. Metin boyutunu 25dp‘ye ayarlıyorum. Soldan 10dp‘lik bir boşluk bırakıyorum ki ImageView yani kişi resmi ile arasında biraz boşluk olsun.

 <TextView
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:text=" "
 android:id="@+id/textView_personname"
 android:layout_toEndOf="@+id/imageView_personpic"
 android:textSize="25dp"
 android:layout_alignParentTop="true"
 android:layout_toRightOf="@+id/imageView_personpic"
 android:layout_marginLeft="10dp" />

İsim TextView‘ının altında adres için bir TextView daha ekliyorum. Onunda sol, sağ ve üst konumunu isim TextView’ına bağlıyorum ki aynı hizada gözüksünler. Metin boyutu olarak da 20dp veriyorum.

<TextView
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:text=" "
 android:id="@+id/textView_address"
 android:layout_below="@+id/textView_personname"
 android:layout_alignLeft="@+id/textView_personname"
 android:layout_alignStart="@+id/textView_personname"
 android:textSize="20dp"
 android:layout_alignBottom="@+id/imageView_personpic"
 android:layout_marginTop="5dp" />

Layout dosyasını tamamladığımıza göre şimdi PersonAdapter sınıfımıza geçebiliriz.

Projeye Sınıf Eklemek 

Adding Class

java klasörü altında bulunan com.metehantoksoy.customadapter şeklinde olan klasöre sağ tıklayın (1). New menüsü (2) altında Java Class‘ı seçin (3).

createclass2

Ardından sınıfa ismini verin (1) ve tipini seçin (2). Bu yöntemle sadece sınıf değil InterfaceEnum gibi tipleri de ekleyebilirsiniz. İsimlendirmede yine yukarıda dediğim şeyleri hatırlayabilirsiniz.

PersonAdapter Sınıfının Kodlanması

Boş bir sınıf olarak PersonAdapter açıldı ve aşağıdaki gibi bir kod ile karşılaştınız.

public class PersonAdapter {
}

Şimdi bu sınıfı Person tipinde ArrayAdapter sınıfına extend edelim.

public class PersonAdapter extends ArrayAdapter<Person> {
}

Burada bazı methodları yazmadığımız için hata aldık. Bu varsayılan kurucu methodudur. Yani bunun anlamı ArrayAdapter sınıfı boş(varsayılan) kurucu methodu desteklemiyor, ArrayAdapter sınından bize uygun kurucuyu PersonAdapter sınıfımıza yazıyoruz.

  public PersonAdapter(Context context, int resource, List<Person> items) {
      super(context, resource, items);
 }

Daha sonra, ListView’da objelerin eklenmesini ve gözükmesini sağlayacak getView() methodunu yazmaya başlayalım. Methodun ilk olarak boş halini parametreleri ile yazalım.

@Override
public View getView(int position, View convertView, ViewGroup parent) {

}

ListView için hazırlamış olduğumuz layout dosyasından bir View oluşturulup, bu fonksiyona convertView değişkeniyle parametre geçilmiş. Fakat eğer View oluşturulmamışsa oluşturmamız gerekir çünkü ImageView ve TextView‘larımıza ulaşırken bu View‘ı kullanacağız.

View v = convertView;
if (v == null) {
     LayoutInflater vi;
     vi = LayoutInflater.from(getContext());
     v = vi.inflate(R.layout.layout_listview_itemtemplate, null);
}

Daha sonra, adaptörümüzün kurucusunda verdiğimiz Person tipindeki List’teden şu anki sıradaki nesneyi getiriyoruz. Üst sınıfta bizim parametre olarak verdiğimiz List tipindeki liste “private” olarak tutulduğu için ve bu ArrayAdapter sınıfını extend ettiğimiz için bu private değişkene erişemeyeceğimiz için, bu iş için yapılmış getItem() methoduyla sıradaki nesnemizi listemizden getiriyoruz. Böylece onun değerlerine erişip o satırdaki ImageView ve TextView’lara atayabileceğiz.

Person p = getItem(position);

Eğer bu nesne boş değilse artık gerekli yerlere atama yapabiliriz.  Ve sonunda o döngüde yaratılan View’ı geri döndürerek kodu bitiriyoruz.

if (p != null) {
     ImageView personImage = (ImageView)v.findViewById(R.id.imageView_personpic);
     TextView personName = (TextView)v.findViewById(R.id.textView_personname);
     TextView personAdress = (TextView)v.findViewById(R.id.textView_address);
 
     if(personImage != null && personName != null && personAdress != null){
         personAdress.setText(p.getAddress());
         personName.setText(p.getName());
         personImage.setImageResource(p.getPictureResourceID());
     }
}
 return v;

Bu method yani getView() methodu, listedeki her obje için baştan çalışır, bunun nedeni her obje, bir layout’ta gösterilip bu layout’un ListView’a satır olarak eklenmesidir. Bundan dolayı her defasında listemizdeki tek Person objesi için çalışıyor ve objenin değerlerini layout’a yazıyor.

Person Sınıfının Kodlanması

Bir Person (Kişi) sınıfının içerisinde Name (İsim), Address (Adres) ve kişinin resminin drawable id’sini tuttuğumuz PicResID’den oluşmaktadır.

public class Person {
     private String Name;
     private String Address;
     private int PicResID;
     public Person(String name, String address){
         Name = name;
         Address = address;
     }
     public Person(String name, String address,int imageID){
         Name = name;
         Address = address;
         PicResID = imageID;
     }
     public String getName() {
         return Name;
     }
     public String getAddress() {
         return Address;
     }
     public int getPictureResourceID() {
         return PicResID;
     }
}

Custom Adapter Kullanılarak ListView’da Objelerin Gösterilmesi

Şimdi ana akvitimizde (MainActivity) program açılır açılmaz listemizin oluşması için onCreate() methodu içerisinde setContentView() method çağrısından sonra Person tipinde bir ArrayList oluşturup 2 yeni Person ekleyelim.

ArrayList<Person> persons = new ArrayList<Person>();
persons.add(new Person("Ahmet Uzun","ISTANBUL",R.drawable.ahmet_uzun));
persons.add(new Person("Ayşe Kanmaz","ANKARA",R.drawable.ayse_kanmaz));

Bu listemizi kullanarak PersonAdapter tipinde bir ArrayAdapter objesi oluşturup bu ListView’ımıza setAdapter() methodu ile atayalım.

PersonAdapter personAdapter = new PersonAdapter(this,R.layout.layout_listview_itemtemplate,persons);

ListView listviewPerson = (ListView)findViewById(R.id.listView_persons);
if(listviewPerson != null){
     listviewPerson.setAdapter(personAdapter);
}

İşte bu kadar. Artık custom bir ListView’ımızı ve onun şablon modeli olan bir layout dosyası ve sınıfımız mevcut. Bundan sonrası sizin hayal gücünüzde. Şehiri kullanıcı ile aynı olan satırlardaki adres TextView’inin  rengini yeşil yapabilir, farklı fontlar atayabilir veya daha  bir çok şey yapabilirsiniz. Kodları çalıştırdığınızda aşağıdaki gibi bir ekran görüntüsü elde edeceksiniz.

screenshot_2015-01-17-02-34-051

Projeyi bütün olarak GitHub üzerinden bu linkten erişebilirsiniz. Bir sonraki yazımızda görüşmek üzere 🙂

Reklamlar

Android – ListView ve Custom Adapter Kullanımı” üzerine 11 yorum

  1. Geri bildirim: Android – Detaylarıyla Custom Font Kullanımı | Metehan Toksoy
  2. peki mesela bastıgımda başka class’a gitmesini istiyorum bunun için ne yapmam gerekir?
    extends i List Activity olanda @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
    // TODO Auto-generated method stub
    super.onListItemClick(l, v, position, id); bunu kullanıyordum.

  3. Merhaba;
    Sekmelerden oluşan bir uygulamam var ve bu sekmelerden birisinde listview var. Uygulama ilk açıldığında listviewdeki herşey normal. Ancak sekme değiştirip tekrar listview bulunan sekmeye geri döndüğümde, listview elemanları karışmış ve çoğalmış görünüyor. Bu durumu nasıl aşabilirim ?
    Teşekkür Ederim..

Bir Cevap Yazın

Aşağıya bilgilerinizi girin veya oturum açmak için bir simgeye tıklayın:

WordPress.com Logosu

WordPress.com hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Google+ fotoğrafı

Google+ hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Twitter resmi

Twitter hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Facebook fotoğrafı

Facebook hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

w

Connecting to %s