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.
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.
10.09.2014
Yorumlar
menudekı bir item icin acılır kapanır alt menu nasıl yapabiliriz
Kolay gelsin.. Bütün herşeyi yaptım ama uygulama başlarken hata veriyor.. Hatayı mainactivity class ta veriyor.. Uygulama durduruldu hatası..
Teşekkürler uğraşınız için İnş işe yarar :)
peki soldaki menulerden birisini nasıl açılır menu yapabilirim, submmenu olarak kulanabilirim peki ?
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?
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
harika
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.
Ö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ü?
bu tarz menü kullanımında Çıkış buttonu nasıl ekleriz ve java kodlarını nereye yazacağız