Android

Android'de Navigation Drawer Menüsü

Bu yazımdaMayıs 2013’te Android Support Library'ninv4 kütüphanesineeklenen Navigation Drawer'dan bahsedeceğim. Bir çok uygulamada gördüğümüz bu yapıyı web sitelerindeki farklı bölümler arasında gezinmeye yarayan "navigasyon menüler" gibi düşünebiliriz. Resim 1: Örnek bir Na...

Bu yazımda Mayıs 2013’te Android Support Library'nin v4 kütüphanesine eklenen Navigation Drawer'dan bahsedeceğim. Bir çok uygulamada gördüğümüz bu yapıyı web sitelerindeki farklı bölümler arasında gezinmeye yarayan "navigasyon menüler" gibi düşünebiliriz.

Navigation Drawer örneği

Resim 1: Örnek bir Navigation Drawer

Navigation Drawer'ın, DrawerLayout isimli bir layoutu mevcuttur. Yukarıda gördüğünüz görünümü bize sunan bu layouttur. İçinde de FrameLayout bulunmaktadır. FrameLayout'lar üst üste getirilebilme özelliğine sahiptirler. Yani biz ekranda menü kapalıyken görünen yere FrameLayout koyup menüden bir alan seçtiğimizde ona ait Fragment'ı FrameLayout’a yükleyip tek bir Activity üstünden bir çok farklı işlev sunabiliriz. Örnek kod üzerinden anlatıma devam edelim.

[code]<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >


    <FrameLayout
        android:id="@+id/content_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    

    <ListView
        android:id="@+id/drawer_list"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:background="#111"
        android:choiceMode="singleChoice"
        android:divider="@android:color/transparent"
        android:dividerHeight="0dp" />

</android.support.v4.widget.DrawerLayout>[/code]

Bu XML layouta göz attığımızda Support kütüphanesinde bulunan DrawerLayout’u kullandığını görüyoruz. İçerdeki FrameLayout ise dinamik olarak değişecek içerik alanıdır yani bildiğimiz menü kapalıyken ekranda görünen yer. Burasını match_parent değeri ile en-boy olarak ekranı kaplamış hale getiriyoruz.

ListView ise soldan kaydırma yaptığımızda veya ActionBar üzerindeki Navigation Drawer’e ait ufak düğmeye tıkladığımızda ekrana gelen menüye ait ListViewdir.

Dört adet fragment için layout oluşturdum. Bunlar:

  • layout_androidfragment.xml

  • layout_homefragment.xml

  • layout_iosfragment.xml

  • layout_windowsphonefragment.xml

Bu layoutları sadece örnek teşkil etmesi için oluşturdum aslında. Hepsinin içinde birer adet TextView mevcut ve sadece hangi Fragment’i temsil ettiklerine dair bilgi (Bkz: android:text özniteliği) taşıyorlar. Herhangi bir tanesinin içeriği şu şekilde:

[code]<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Anasayfa"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"/>

</RelativeLayout>[/code]

ListView’in satır görünümünü ayarlamak için bir layout oluşturuyoruz. Bu sayede Adapter'ın belirlediğimiz stilde satırı göstermesini sağlayabiliriz.

[code]<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/text1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="?android:attr/activatedBackgroundIndicator"
    android:gravity="center_vertical"
    android:minHeight="?android:attr/listPreferredItemHeightSmall"
    android:paddingLeft="16dp"
    android:paddingRight="16dp"
    android:textAppearance="?android:attr/textAppearanceListItemSmall"
    android:textColor="#fff" />[/code]

Evet buraya kadar layoutlarla olan işlemimiz tamamen son bulmuş oldu. Kod tarafında yapılacak eklemelere göz atalım:

src/ dizinindeki java dosyalarımız:

  • MainActivity
  • FragmentAndroid
  • FragmentIOS
  • FragmentWindowsPhone

Az önce bahsettiğimiz layoutları şimdi MainActivity içinde FragmentManager yardımıyla gösterelim:

src/MainActivity.java
​[code]private DrawerLayout mDrawerLayout;

// Sol Slider Açıldığında Görünecek ListView
private ListView mDrawerList;

// Navigation Drawer nesnesini ActionBar'da gösterir.
private ActionBarDrawerToggle mDrawerToggle;

// ActionBar'ın başlığı dinamik olarak değişecek draweri açıp kapattıkça
private String mTitle = "";
[/code]

MainActivity'nin sınıf kapsamındaki üyelerle ilgili gerekli tanımlamalarımız bu şekilde. Hepsinin neden yapıldığını yorum şeklinde eklediğim kod blokunda görebilirsiniz.

onCreate bloğuna göz atalım:

src/MainActivity.java
[code]@Override
	protected void onCreate(Bundle savedInstanceState) {

	super.onCreate(savedInstanceState);
	setContentView(R.layout.activity_main);
		
	// Content alanına fragment yüklemek için
	FragmentManager fragmentManager = getFragmentManager();
      FragmentTransaction ft = fragmentManager.beginTransaction();
	
      FragmentHome fragmentHome = new FragmentHome();
	ft.add(R.id.content_frame, fragmentHome);
	ft.commit();
		
	mTitle = "Geleceği Yazanlar";
	getActionBar().setTitle(mTitle);

		
	mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);

	mDrawerList = (ListView) findViewById(R.id.drawer_list);

	// iconu ve açılıp kapandığında görünecek texti veriyoruz.
	mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
				R.drawable.ic_drawer, R.string.drawer_open,
				R.string.drawer_close) {

	// drawer kapatıldığında tetiklenen method
	public void onDrawerClosed(View view) {
		getActionBar().setTitle(mTitle);
		invalidateOptionsMenu();
      }

	// drawer açıldığında tetiklenen method
	public void onDrawerOpened(View drawerView) {
		getActionBar().setTitle("Navigation Drawer GY");
		invalidateOptionsMenu();
	}

	};

	// Açılıp kapanmayı dinlemek için register
	mDrawerLayout.setDrawerListener(mDrawerToggle);

	// Navigationdaki Drawer için listview adapteri
	ArrayAdapter adapter = new ArrayAdapter(getBaseContext(), 
				R.layout.drawer_list_item, getResources().getStringArray(R.array.menu));

      // adapteri listviewe set ediyoruz
	mDrawerList.setAdapter(adapter);

	// actionbar home butonunu aktif ediyoruz
	getActionBar().setHomeButtonEnabled(true);

	// navigationu tıklanabilir hale getiriyoruz
	getActionBar().setDisplayHomeAsUpEnabled(true);

	// sol slider açıldığında gelen listviewin tıklama eventi
	mDrawerList.setOnItemClickListener(new OnItemClickListener() {

	@Override
	public void onItemClick(AdapterView parent, View view,int position, long id) {

	// itemleri arraya tekrar aldık
	String[] menuItems = getResources().getStringArray(R.array.menu);

	// dinamik title yapmak için actionbarda tıklananın titlesi görünecek
	mTitle = menuItems[position];
				
      FragmentManager fragmentManager = getFragmentManager();
	FragmentTransaction ft = fragmentManager.beginTransaction();

	// fragmenti contente yerleştirme.
	if(position==0){
		FragmentHome fragmentHome = new FragmentHome();
	      ft.replace(R.id.content_frame, fragmentHome);
	      ft.commit();
	}else if(position==1){
		FragmentAndroid fragmentAndroid = new FragmentAndroid();
		ft.replace(R.id.content_frame, fragmentAndroid);
		ft.commit();
	}else if(position==2){
		FragmentIOS fragmentIOS = new FragmentIOS();
		ft.replace(R.id.content_frame, fragmentIOS);
		ft.commit();
	}else if(position==3){
		FragmentWindowsPhone fragmentWindowsPhone = new FragmentWindowsPhone();
		ft.replace(R.id.content_frame, fragmentWindowsPhone);
					ft.commit();
	}
				
	// draweri kapat
	mDrawerLayout.closeDrawer(mDrawerList);

			}
		});
	}
[/code]

Resim 2: Soldaki Navigation Drawer'da Android öğesine tıkladığınızda sağdaki FragmentAndroid yüklenir.

Kod başta birazcık karmaşık gelebilir. Fakat yapılan işlemleri üstüne yorum satırı koydum ve yine burada ufakça özetlemek istiyorum. Fragment'lar kafanızı karıştırabilir o yüzden Fragment ile ilgili ön bilgi vermek istiyorum. Fragment'lar da Activityler gibi yaşam döngüsüne sahip olan alt Activity parçacıklarıdır. Dinamik olarak çalışma esnasında eklenebilirler silinebilirler ve Activity'lere göre çok daha esnektirler. Bu yüzden büyük ve çok sayfalı projelerde tercih sebebidir. Activity'ler üzerinde koşarlar. Projemiz tamamen Fragment'lar üzerinden yürüyecek. Activity’miz burada sadece taşıyıcı görevi görüyor. onCreate bloğunda direk anasayfayı temsil eden HomeFragment’i FrameLayout’a yükledik. Bu sayede Activity ilk açıldığında direk ekranda layout_homefragment.xml görüntülenmiş olacak. Çünkü content_frame isimli ekranı kaplamış FrameLayout’a HomeFragment’i yükledik. Fragment'lar da tıpkı Activity'ler gibi layout dosyası alabilir ve ekrana onu gösterebilirler.

Kodda bulunan diğer kısım ActionBarDrawerToggle’dır.O kısımda ActionBar’a verdiğimiz simgeyi ekliyor ve ona tıkladığımızda da menü açılmasını sağlıyoruz. Aslında uygulamamızda bir menünün olduğunu kullanıcının anlaması için vardır. Daha sonrada adapter oluşturup elimizde bulunan bir listeyi menüde bulunan ListView’e yükledik. ListView’in herhangi bir alanına tıklandığında içerik alanındaki Fragment'ı güncellemeyi de kod kısmında gördüğünüz şekilde gerçekleştirdim.

[code]@Override
	protected void onPostCreate(Bundle savedInstanceState) {
		super.onPostCreate(savedInstanceState);
		mDrawerToggle.syncState();
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		//draweri sadece swipe ederek açma yerine sol tepedeki butona basarak açmak için
		if (mDrawerToggle.onOptionsItemSelected(item)) {
			return true;
		}
		return super.onOptionsItemSelected(item);
	}

	@Override
	public boolean onPrepareOptionsMenu(Menu menu) {
		boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
		// navigationDrawer açıldığında ayarları gizlemek için
		menu.findItem(R.id.action_settings).setVisible(!drawerOpen);
		return super.onPrepareOptionsMenu(menu);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}
[/code]

Kalan metodlar da bu şekilde. Açıklamaları yine koda yorum olarak ekledim görebilirsiniz.

Herhangi bir Fragment nesnesinin nasıl oluşturduğunuda gösterip yazıya son vermek istiyorum.

[code]public class FragmentHome extends Fragment {

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		View view = inflater.inflate(R.layout.layout_homefragment, container,false);
		return view;
	}
}
[/code]

Kodda gördüğünüz üzere Fragment'ın zorunlu metodu olan onCreateView içerisinde layout, View nesnesine dönüştürülüyor.

Bu yazıda kısaca Android Support Library içinde bulunan Navigation Drawer nesnesini ve dinamik olarak Fragment'lar sayfaya nasıl yüklenir değiştirilir onu gördük. Örnek projeyi Github'a yükledim. İndirip çalıştırmanızı öneririm. Çünkü burada paylaştığım kodlardan ziyade paylaşmadığım resource (resimler, values dosyaları vb.) kısmı da projenin içinde mevcut.

Github adresi: https://github.com/ahmtbrk/navigationdrawer

İyi çalışmalar dilerim.

Yorumlar

omer
14.09.2020 - 03:25

bu tarz menü kullanımında Çıkış buttonu nasıl ekleriz ve java kodlarını nereye yazacağız

Eyup
26.04.2018 - 07:39

menudekı bir item icin acılır kapanır alt menu nasıl yapabiliriz

Mustafa B
03.08.2017 - 12:00

Kolay gelsin.. Bütün herşeyi yaptım ama uygulama başlarken hata veriyor.. Hatayı mainactivity class ta veriyor.. Uygulama durduruldu hatası..

Engin
12.04.2016 - 04:35

Teşekkürler uğraşınız için İnş işe yarar :)

Ahmet Ziya YAVUZ
04.01.2016 - 09:45
Merhaba, sorunuz çok uzun bir süre önce sorulmuş ancak yine de cevaplayayım. "R can not be resolved" problemini ortadan kaldırmak için Android Studio'da Build>>Clean Project ve Rebuild Project işlemlerini yapmanız yeterlidir.
Salih
05.01.2016 - 10:16

peki soldaki menulerden birisini nasıl açılır menu yapabilirim, submmenu olarak kulanabilirim peki ?

hilmiye adabaşı
22.05.2015 - 11:44
package com.example.myfirstapp.myapplication;

import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.support.v7.app.ActionBarDrawerToggle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ListView;


public class MainActivity extends ActionBarActivity {

    private DrawerLayout mDrawerLayout;

    // Sol Slider Açıldığında Görünecek ListView
    private ListView mDrawerList;

    // Navigation Drawer nesnesini ActionBar'da gösterir.
    private ActionBarDrawerToggle mDrawerToggle;

    // ActionBar'ın başlığı dinamik olarak değişecek draweri açıp kapattıkça
    private String mTitle = "";


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

Merhabalar,

Bende projemde Navigation Drawer oluşturmak istedim ve sizin örneğiniz üzerinden ilerlemeye çalıştım. Ancak MainActivity.java kodumda R'lerde CannoT Resolve Symbol R hatası veriyor. Yardımcı olabilir misiniz?

Ahmet Tekin
09.01.2015 - 04:11

Yazınız çok başarılı olmuş benim daha önce bir çalışmamda sizin uygulamanızda ayarlar die gözüken kısım ı kaldırmam gerekti kaldıramadım. yazısın sildim ama üzerine gelip basılı tuttugumda oranın title yazısını gösteriyordu bunu nasıl yapabilirim mümkün mü acaba

Taner
02.12.2014 - 05:45

harika

Zafer Celaloglu
05.11.2014 - 06:55

Merhabalar,

Bende kendi uygulamam da navigation drawer kullaniyorum sizin yaptiginiz sekilde bir implementation yaptim fakat peki ya biz bu menuye sadece fragment yerine ListFragment,FragmentActivity,ListActivity seklinde farkli yapilari kullanma imkanimiz var mi?

(Bu konuyla ilgili stackoverflow vb. Activity de kullanilabilecegi fakat daha dinamik bir yapi icin Fragment oneriliyor ama diger componentlarla ilgili herhangi bir aciklama yok.)

Kendi denemem de ise sadece Fragment ve Activity yi kabul etti diger componentleri kabul etmiyor aslinda bunu sormamim nedeni sadece Fragment veya Activity ye bagli kalmadan daha esnek bir sekilde uygulama gelistirmek istemem menuye ekleme yapacagim zaman illa Fragment yapisina cevirip implemente ediyorum ayni sekilde yapmak istediklerim hep kisitlaniyor.

Safa
13.09.2014 - 04:26

Öncelikle elinize sağlık güzel bir türkçe kaynak olmuş. Bu konuyla ilgili bir sorum var. Slide menüyü açtığımız zaman üstte bulunan ActionBar sabit duruyor.Bu kısmı da kaydırmamız mümkün mü?

Ahmet Burak Demirkoparan
14.09.2014 - 01:14
Merhabalar; Direkmen Navigation Drawer içerisinde bildiğim kadarıyla content'i dışarıya kaydıran bir özellik mevcut değil. https://github.com/NikolaDespotoski/DrawerLayoutToggles bu library'den yararlanabilirsiniz.