Android Açılıp Kapanabilen ListView Anlatımı (Expandable ListView)

Merhaba arkadaşlar,  Bu dersimizde Expandable ListView i anlatacağım. ListView türünden meydana gelen fakat ona göre biraz karmaşık bir yapıya sahip olan bu android bileşeni ile alt alta verileri listeleme yapabileceğimiz gibi bunları belirli başlıklar altında gösterebiliriz. Kısaca mantığını açıklayacak olursam, ana bir başlık altında listeleyeceğimiz elemanlarımız olacaktır. Ana başlığımızı parent olarak kabul edersek, elemanlarımızda ilgili parent lara bağlı olan veriler olacaktır.  Her listview’in içini doldurmamız ve istediğimiz tarzda hazırlamamız için bir bir Adapter gereklidir bu durum Expandable ListvView içinde geçerlidir. Bu yüzden ana classımız dışında bir de Adapter oluşturacağız.

Biraz önce bahsettiğim gibi iki çeşit bileşen kullanmamız gerecek birini parent olarak düşüneceğiz ve şimdi oluşturacağız. Bu parent bileşeni için layout xml (listview_header.xml) kısmını yaratalım. Bunu daha iyi anlamak için şöyle açıklayalım; ana başlık olarak başlığın tipini oluşturup, başlık kısmınında arka plan rengini aşağıdaki kod ile oluşturmuş olacağız. Her bir başlığımızı parent olarak nitelendirdik bunu daha iyi kavrayabilmeniz için söyledim çünkü her bir ailenin (parent) ın çocukları (child) olduğunu düşünürsek bu yapının mantığını daha iyi anlamış oluruz. (Linked List bileşenini bilenler için bir çağırışım yapmış olabilir bu konu, mantık olarak benzer, içerik olarak tabiki de farklıdır )

listview_header.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="#ffff00" >
  
    <TextView
        android:id="@+id/txt_parent"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Medium Text"
        android:textColor="#000000"
        android:textAppearance="?android:attr/textAppearanceMedium" />

</LinearLayout>

listview_header.xml oluşturduktan sonra şimdi ise listview_child.xml layout kısmını oluşturalım. Parent larımıza bağlı olan değişkenlerimiz de yazı yani TextView ler yer almasını istiyoruz. Bunun oluşturulması ise gayet basit aşağıdaki kodu incelersek göreceğiz.

listview_child.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/txt_items"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:focusableInTouchMode="false"
        android:text="Medium Text"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:textColor="#000000" />

</LinearLayout>

Şimdi de Main sınıfının layout xml ine bakalım. Burda android bileşenlerinden id sini expand_listview yaptığımız ExpandableListView i yerleştirelim.

activity_main.xml

<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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.com.project.expandablelistview.MainActivity" >

    <ExpandableListView
        android:id="@+id/expand_listview"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/arkaplannew" >

    </ExpandableListView>

</RelativeLayout>

ExpandableListView bileşenini de ekledikten sonra şimdi içini doldurmak için oluşturmamız gereken adapter ımızı yaratalım.

Adapterımızı BaseExpandableListAdapter tipinden türetmek için extends ediyoruz. Böylece unimplemented methods karşımıza çıkacaktır bu sınıftan türetmeye çalıştığımızda methodumuzu kullanabilmemiz için hazır fonksiyonları tanımlamamız gerekecektir. Bu methodları ekle dediğimiz zaman da otomatik olarak bu fonksiyonlar kod kısmımıza eklenecektir.

public class ExpandListViewAdapter extends BaseExpandableListAdapter{

	public List<String> list_parent;
	public HashMap<String, List<String>> list_child;
	public Context context;
	public TextView txt;
	public TextView txt_child;
	public LayoutInflater inflater;
	@Override
	public int getGroupCount() {
		
		return list_parent.size();
	}
	
	public ExpandListViewAdapter(Context context, List<String> list_parent,HashMap<String, List<String>> list_child)
	{
		this.context = context;
		this.list_parent = list_parent;
		this.list_child = list_child;
	}

	@Override
	public int getChildrenCount(int groupPosition) {
		
		return list_child.get(list_parent.get(groupPosition)).size();
	}

	@Override
	public Object getGroup(int groupPosition) {
		
		return list_parent.get(groupPosition);
	}

	@Override
	public Object getChild(int groupPosition, int childPosition) {
		
		return list_child.get(list_parent.get(groupPosition)).get(childPosition);
		
	}

	@Override
	public long getGroupId(int groupPosition) {
		
		return groupPosition;
	}

	@Override
	public long getChildId(int groupPosition, int childPosition) {
		
		return childPosition;
	}

	@Override
	public boolean hasStableIds() {
		
		return false;
	}

	@Override
	public View getGroupView(int groupPosition, boolean isExpanded,
			View view, ViewGroup parent) {
		String title_name = (String)getGroup(groupPosition);
		
		if(view == null)
		{
			inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
			view = inflater.inflate(R.layout.listview_header,null);
		}
		
		txt = (TextView)view.findViewById(R.id.txt_parent);
		txt.setText(title_name);
		
		return view;
	}

	@Override
	public View getChildView(int groupPosition, int childPosition,
			boolean isLastChild, View view, ViewGroup parent) {
   // kaçıncı pozisyonda ise başlığımızın elemanı onun ismini alarak string e atıyoruz
		String txt_child_name = (String)getChild(groupPosition, childPosition);
		if(view==null)
		{
			inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
			view = inflater.inflate(R.layout.listview_child, null);
 // fonksiyon adından da anlaşılacağı gibi parent a bağlı elemanlarının layoutunu inflate ediyoruz böylece o görüntüye ulaşmış oluyoruz
		}
		if(getGroup(groupPosition).toString().equals("GALATASARAY"))
		{
              // Eğer başlığımızın ismi GALATASARAY ise elemanlarının yer aldığı arka plan rengini kırmızı yapıyoruz
			view.setBackgroundColor(Color.RED);
		}
		else if(getGroup(groupPosition).toString().equals("FENERBAHCE"))
		{
             // Eğer başlığımızın ismi FENERBAHCE ise elemanlarının yer aldığı arka plan rengini mavi yapıyoruz
			view.setBackgroundColor(Color.BLUE);
		}
         // listview_child ulaştığımıza göre içindeki bileşeni de kullanabiliyoruz daha sonradan view olarak return ediyoruz
		txt_child = (TextView)view.findViewById(R.id.txt_items);
		txt_child.setText(txt_child_name);
		return view;
	}

	@Override
	public boolean isChildSelectable(int groupPosition, int childPosition) {
		
		return true;  // expandablelistview de tıklama yapabilmek için true olmak zorunda
	}
	
	

}

Yukarıdaki kodun içinde gerekli açıklamaları yapmaya çalıştım. Hangi parentımıza bağlı kaç tane elemanımız var getChildren methodu ile anında bulabiliriz. getChildView ve getGroupView methodları parentlarımız ile birlikte childlarımız için önceden oluşturmuş olduğumuz layout kısmına ulaşmamızı ve görsel olarak ExpandableListView bileşenini şekillendirmemize yardımcı olur. Adapter kısmını da hallettiğimize göre MainActivity sınıfımıza bakalım.

public class MainActivity extends Activity {

	public List<String> list_parent;
	public ExpandListViewAdapter expand_adapter;
	public HashMap<String, List<String>> list_child;
	public ExpandableListView expandlist_view;
	public List<String> gs_list; 
	public List<String> fb_list;
	public int last_position = -1;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		expandlist_view = (ExpandableListView)findViewById(R.id.expand_listview);
		
		Hazırla(); // expandablelistview içeriğini hazırlamak için
		
		// Adapter sınıfımızı oluşturmak için başlıklardan oluşan listimizi ve onlara bağlı olan elemanlarımızı oluşturmak için HaspMap türünü yolluyoruz
		expand_adapter = new ExpandListViewAdapter(getApplicationContext(), list_parent, list_child);
		expandlist_view.setAdapter(expand_adapter);  // oluşturduğumuz adapter sınıfını set ediyoruz
		expandlist_view.setClickable(true);
		
		expandlist_view.setOnChildClickListener(new OnChildClickListener() {
			
			@Override
			public boolean onChildClick(ExpandableListView parent, View v,
					int groupPosition, int childPosition, long id) {
				
			String child_name = (String)expand_adapter.getChild(groupPosition, childPosition);
			//Toast.makeText(getApplicationContext(),"hey" + child_name, Toast.LENGTH_LONG).show();
			
			AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
			builder.setMessage(child_name)
			       .setTitle("Mobilhanem Expandablelistview")
			       .setCancelable(false)
			       .setPositiveButton("TAMAM", new DialogInterface.OnClickListener() {
			           public void onClick(DialogInterface dialog, int id) {
			                
			           }
			       });
			AlertDialog alert = builder.create();
			alert.show();
			
				
				return false;
			}
		});
		
		
		/*
		expandlist_view.setOnGroupExpandListener(new OnGroupExpandListener() {
			
			@Override
			public void onGroupExpand(int groupPosition) {
				
				if(last_position != -1 && last_position != groupPosition)
				{
					expandlist_view.collapseGroup(last_position);
				}
				last_position = groupPosition;
				
			}
		});
		*/
		
	}
	public void Hazırla()
	{
		list_parent = new ArrayList<String>();  // başlıklarımızı listemelek için oluşturduk
		list_child = new HashMap<String, List<String>>(); // başlıklara bağlı elemenları tutmak için oluşturduk
		
		list_parent.add("GALATASARAY");  // ilk başlığı giriyoruz
		list_parent.add("FENERBAHCE");   // ikinci başlığı giriyoruz
		
		gs_list = new ArrayList<String>();  // ilk başlık için alt elemanları tanımlıyoruz
		gs_list.add("Muslera");
		gs_list.add("Sabri");
		gs_list.add("Chejdou");
		gs_list.add("Semih Kaya");
		gs_list.add("Telles");
		gs_list.add("Selçuk İnan");
		gs_list.add("Felipe Melo");
		gs_list.add("Hamit");
		gs_list.add("Weslej Sneijder");
		gs_list.add("Bruma");
		gs_list.add("Burak Yılmaz");
		
		fb_list = new ArrayList<String>(); // ikinci başlık için alt elemanları tanımlıyoruz
		fb_list.add("Volkan Demirel");
		fb_list.add("Gökhan Gönül");
		fb_list.add("Bekir");
		fb_list.add("Caner Erkin");
		fb_list.add("Mehmet Topal");
		fb_list.add("Emre");
		fb_list.add("Alper Potuk");
		fb_list.add("Mehmet Topuz");
		fb_list.add("Diego");
		fb_list.add("Sow");
		fb_list.add("Emenike");
		
		list_child.put(list_parent.get(0),gs_list); // ilk başlığımızı ve onların elemanlarını HashMap sınıfında tutuyoruz 
		list_child.put(list_parent.get(1), fb_list); // ikinci başlığımızı ve onların elemanlarını HashMap sınıfında tutuyoruz
		
		
	}

	
}

MainActivity sınıfımız için açıklamaları yine kod kısmında yapmaya çalıştım. ExpandableListView imizi oluştururkan Adapter sınıfını kullanarak içini dolduruyoruz. Hazırla fonksiyonu Adapterımızda kullanacağımız HashMap ve List imizi hazırlamamıza yardımcı oluyor kod a bakarsak gerekli açıklamaları göreceksiniz.

Adapterı set ettikten sonra parent larımızın elemanlarına ulaşmak yani child lara ulaşmak için ExpandableListView imize setOnChildClickListener özelliğini veriyoruz. Hangi child a tıklıyorsak onun içindeki değeri Alert Dialog yapımızı oluşturarak mesaj kısmında gösteriyoruz. Tıklama olayında ise,  adapterımızın getChild fonksiyonuna ulaşarak groupPosition ve childPosition parametrelerini vererek tıklamış olduğumuz child a doğru bir şekilde ulaşmış olduk daha sonra onu String e cast ederek child_name değişkeninin içine attık. Alert Dialog kullanarak da child_name değerini kullanıcıya gösterdik.

Not: Tıkladığımız child a ulaşabilmek için Adapterımızın içinde yer alan isChildSelectable fonksiyonun true return etmesi gerektiğine dikkat edelim. Eğer tıkladığınızda child lara ulaşamıyorsanız muhtemelen bu fonksiyonda return false demektir.

ExpandableListView bileşenine setOnGroupExpandListener özelliğini verdiğimizde ise tıklama olayında gerçekleşebilecek işlemleri yapabilmemize yardımcı olur kod lara baktığınızda yorum içine aldığım yeri açıp incelerseniz eğer her bir parent a tıkladığım an diğer parent açık ise kapanmasını sağlar. Zaten yorumları kaldırmadan çalıştırdığınız an ise, hangi parent a tıklıyorsak o açılır konuma geçer ve parent lar birbirinden etkilenmezler.

Evet gördüğünüz gibi ExpandableListView bileşenini sizlere anlatmaya çalıştım. Kaynak kodu indirip uygulamayı çalıştırdığınız anda ise Galatasaray ve Fenerbahçe’nin ilk 11 lerini göreceksiniz 🙂 bu kavramı böyle bir uygulama yaparak anlatmak istedim umarım faydalı olmuştur. Konu hakkında soru ve önerilerinizi çekinmeden yorum bırakabilirsiniz. Bol Android’li günler sizin olsun :)

Sizlerden ricamız facebook.com/mobilhanem sayfamızı beğenmenizdir. Birdahaki dersimize kadar kendinize iyi bakın.

Tüm Android Ders, Proje ve Kaynak Kodlar için tıklayınız.

0

Alper Beyler

Yüksek Lisans: Çankaya Üniversitesi / Bilgisayar Mühendisliği
Lisans: Çankaya Üniversitesi / Bilgisayar Mühendisliği (4/3.30) (2010-2014)
Lisans : Viyana Teknik Üniversitesi / Bilgisayar Bilimleri (2013)

24 Yorum

  • Hocam iyi akşamlar…
    Bu açılabilir liste de listeden herhangi bir elemana tıklayınca başlığı ve içeriği göstermesini nasıl sağlarız acaba…

    mesela Muslera nın üzerine tıklayınca Muslera nın hakkında bilgi verecek… Doğum tarihi yaşı gibi bilgileri

    • yukarıdaki yapıyı incelersen eğer listview_child.xml layoutunu göreceksin orada sadece TextView kullanıldığım için sadece yazılar ortaya çıkıyor onu özelleştirmen gerekiyor LinearLayout’un ( horizontal ) içine atarsın TextView ile EditText i böylece yazıların yanında Edittext ler oluşur. Sadece “muslera” nın yanında olmasını istiyorsanda adapter kısmında ilk elemana göre düzenlersin anlattığım şekilde

  • Merhabalar altI üstü bir açılıp kapanabilir menu yapcaz kodlar da çok uzun üstelik sınav da burdan sorumluyum nasıl olcak bilmiyorum . Kodlara bakıyorum kodlar bana kisacasi atın beni denizlere ?????

    • Merhabalar, kodları incelemeye çalışınca mantığını anlamaya çalışın listview yapısına iyi bir şekilde hakimseniz expandeble listview i anlamanız daha kolay olacaktır., ayrıca bütün kod yapısını baştan sona yaz demeyecektir heralde hocanız demi 🙂

  • acilir pencerinin alt ögelerine button click yapip baska bir activity sayfasina gitme sansimiz varmidir acaba?

  • meraba firebase üzerinde exapdable listview yapısını kullanıyorum ama benim yapım bi parent kismi ve sadece child icin gecerli alt menununde altını yapabilecegim bi kaynak yardımcı olur musunuz lütfen

  • Merhaba, öncelikle çok teşekkürler, harika bir anlatım olmuş. Benim yapmaya çalıştığım şey bir expandable içinde başka bir tanesi daha açılsın ve içiçe açılabilen itemlerın . ben bunu nasıl sağlayabilirim?:)

Haftalık Bülten

Mobilhanem'de yayınlanan dersleri haftalık mail almak ister misiniz?