Selamlar, bir günlük aranın ardından kaldığımız yerden devam ediyoruz. Geçen yazıda menümüzü oluşturup çalışır hale getirdik. Şimdi biraz daha geliştirip hem menü öğelerine iconlar hem de menüye sayfalar ekleyeceğiz. Hiç vakit kaybetmeden kodlamaya başlayalım.
İlk olarak menüde kullacağımız icon setini internetten indirelim. Bunun için flaticon sitesini kullanabilirsiniz. Ben dört tane icon indirdim. Ekran boyutlarına göre bunları formatlayabilirsiniz ancak ben şu an için bununla uğraşmayacağım. Şimdi indirdiğimiz iconları res –> drawable klasörünün altına atalım.
Bu resimleri tek bir kaynak toplu olarak çekebiliriz. Şimdi yapacağım bir yöntem, başka şekillerde de çekebilirsiniz. strings.xml dosyasını açalım ve içerisine aşağıdaki kodları yerleştirelim. Ayrıca menü öğelerinin isimlerini de değiştirdim.
strings.xml
<string-array name="slidemenu_item"> <item>Facebook</item> <item>Twitter</item> <item>Google Plus</item> <item>Instagram</item> </string-array> <array name="icons"> <item name="facebook">@drawable/facebook</item> <item name="twitter">@drawable/twitter</item> <item name="google">@drawable/google</item> <item name="instagram">@drawable/instagram</item> </array>
Şimdi de daha önce kullandığımız SlideMenuItem model sınıfını güncellememiz gerekiyor. Aşağıdaki gibi bu sınıfı güncelleyelim. int tipinde bir icon değişkeni ile resmin id sini tutacağız.
SlideMenuItem.java
package com.gkhnl.slidingmenuinandroid; public class SlideMenuItem { private String title; private int icon; public SlideMenuItem() { } public SlideMenuItem(String title, int icon) { this.title = title; this.icon = icon; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public int getIcon() { return icon; } public void setIcon(int icon) { this.icon = icon; } }
Iconlarımızı strings.xml dosyasından çekip bir dizi de tutmamız gerekiyor. Bunun için TypedArray sınıfını kullanacağız.
TypedArray icons;
Daha sonra strings.xml dosyasından çekip bu diziye aktarıyoruz.
icons = getResources().obtainTypedArray(R.array.icons);
Iconları tasarımımıza da eklemek gerekiyor. slidemenu_item.xml dosyamızı aşağıdaki gibi güncelliyoruz.
<?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"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_vertical" android:orientation="horizontal" android:paddingBottom="10dp" android:paddingLeft="16dp" android:paddingRight="16dp" android:paddingTop="10dp"> <ImageView android:id="@+id/img_icon" android:layout_width="40dp" android:layout_height="40dp" android:src="@drawable/facebook" /> <TextView android:id="@+id/txt_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="16dp" android:text="AAA" android:textColor="@color/title" android:textSize="16sp" /> </LinearLayout> </LinearLayout>
Son olarak adapter dosyamızı da güncellersek icon ekleme işlemi tamamlanmış olacak. getView() metodunu aşağıdaki gibi güncelliyoruz. Tabi img_icon değişkenimizi eklemeyi de unutmayın.
private ImageView img_icon;
@Override public View getView(int position, View view, ViewGroup viewGroup) { // Her list item için custom tasarım yüklüyor if (view == null) { view = LayoutInflater.from(ctx).inflate(R.layout.slidemenu_item, null); // Yeni tasarım içindeki title textine ulaşıp, veriyi set ediyor txt_title = (TextView) view.findViewById(R.id.txt_title); img_icon = (ImageView) view.findViewById(R.id.img_icon); txt_title.setText(items.get(position).getTitle()); img_icon.setImageResource(items.get(position).getIcon()); return view; } return null; }
Artık çalıştırabiliriz. Eğer her şeyi doğru şekilde tamamladıysanız menümüz bu halde gözükecektir.
Buraya kadar gayet güzel bir şekilde menümüzü geliştirdik. Şimdi biraz da işlev katalım. Öncelikle burada kullancağımız yapı Fragment ve eğer nasıl bir yapı olduğunu bilmiyorsanız şuraya bir göz atmanız gerekebilir.
İşe activity_main.xml dosyamızı değiştirerek başlayalım. Dosyamızı aşağıdaki gibi güncelleyelim.
activity_main_xml
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/drawerLayout" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.gkhnl.slidingmenuinandroid.MainActivity"> <FrameLayout android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent"/> <ListView android:id="@+id/lw_Menu" android:layout_width="250dp" android:layout_height="match_parent" android:layout_gravity="left|start" android:background="@color/list_back" /> </android.support.v4.widget.DrawerLayout>
FrameLayout bileşeni bizlere fragment sayfalarımızı taşımamızı sağlayacak. Bu taşıyıcı sayesinde içindeki sayfaları istediğimiz gibi değiştirebileceğiz. Şimdi de fragment larımızı oluşturalım. Burada IDE’den yardım alarak kolayca oluşturabiliriz. İkinci ekranda Include checkbox ları işaretlemeyin.
Android Studio bizlere hem fragment kodlarını hemde layout dosyasını hazırlıyor. Ben bunlardan dört tane oluşturdum. pages klasörünün altında toplayarak okunaklı ve kullanışlı olmasını sağladım.
Her fragment layout dosyasını aşağıdaki gibi güncelledim. Siz de bu şekilde hangi sayfaya tıkladığınızı kontrol edebilirsiniz.
<LinearLayout 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="com.gkhnl.slidingmenuinandroid.pages.FacebookFragment"> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:text="Facebook Page" android:textColor="@color/background_material_dark" android:textSize="28sp" /> </LinearLayout>
Fragmentlar hazır olduğuna göre artık menüye bağlayabiliriz. displayPage() isimli bir metod oluşturdum. Bu metotta fragment sayfaları oluşturup görüntüleme işlemlerini yapabiliriz.
private void displayPage(int position) { Fragment fragment = null; switch (position) { case 0: fragment = new FacebookFragment(); fragment_name = "FacebookFragment"; break; case 1: fragment = new TwitterFragment(); fragment_name = "TwitterFragment"; break; case 2: fragment = new GoogleFragment(); fragment_name = "GoogleFragment"; break; case 3: fragment = new InstagramFragment(); fragment_name = "InstagramFragment"; default: break; } if(fragment != null){ // Fragment transaction nesnesi ile fragment ekranları arasında geçiş sağlıyor FragmentManager fragmentManager = getSupportFragmentManager(); android.support.v4.app.FragmentTransaction transaction = fragmentManager.beginTransaction(); transaction.replace(R.id.container, fragment).addToBackStack(fragment_name).commit(); // Stack te bulunan fragment sayısını alıyor int count = getSupportFragmentManager().getBackStackEntryCount(); if(count!=0) { // Son fragment alınıyor FragmentManager.BackStackEntry backStackEntry = getSupportFragmentManager().getBackStackEntryAt(count - 1); // Son fragment ile seçilen fragment aynı ise eski fragment siliniyor if (backStackEntry.getName().contains(fragment_name)) { getSupportFragmentManager().popBackStack(); } } } }
Kodlara tek tek bakalım. Öncelikle Fragment değişkeni oluşturduk ve tıklanılan öğrenin position değerine göre nesneye dönüştürdük. getSupportFragmentManager() metodu bize fragment üzerinde ekleme, silme, değiştirme vb. işlemleri yapma imkanı veriyor. FragmentTransaction nesnesi ile fragment üzerinde işlem başlatıyoruz. replace() metodu ile var olan ile yeni fragment sayfasını yer değiştiriyor. addToBackStack() ise her fragment geçişi yaptığımızda bir önceki sayfası kayıtta tutup ona dönebilmemizi sağlıyor. Burada fragment_name isimli değişken fragment sayfalarımızı kayıt ederken kullandığımız bir etiket. Her yeni fragment geçişinde yeni fragment bir öncekinin üstüne biniyor. Bu şekilde üst üste bir yığınak oluşuyor. Eğer geri tuşuna basarsanız son giren ilk çıkar prensibi ile aynı sıranın tersinde geri döneceksiniz.
Buraya kadar herşey tamam ama diyelim ki aynı menü öğesine üst üste 2-3 kere tıkladınız. Örneğin FacebookFragment sayfasına 4 kere tıkladınız. Bu şekilde yine aynı fragment üst üste sıralanmaya başlayacak. Geri tuşuna bastığınızda aynı sayfaya döneceği için geri tuşunun işlemediğini zannedeceksiniz. Ta ki tüm stack boşalana kadar.
Bunu kontrol ederek önelemek mümkün. Aşağıdaki kod bloğu bunu sağlıyor.
// Stack te bulunan fragment sayısını alıyor int count = getSupportFragmentManager().getBackStackEntryCount(); if(count!=0) { // Son fragment alınıyor FragmentManager.BackStackEntry backStackEntry = getSupportFragmentManager().getBackStackEntryAt(count - 1); // Son fragment ile seçilen fragment aynı ise eski fragment siliniyor if (backStackEntry.getName().contains(fragment_name)) { getSupportFragmentManager().popBackStack(); } }
Tek tek kodlara bakalım. Ekelenen fragment sayısını alarak son eklenen fragment sayfamızın ne olduğunu öğreniyoruz.
FragmentManager.BackStackEntry backStackEntry = getSupportFragmentManager().getBackStackEntryAt(count - 1);
Daha sonra son fragment ile yeni geçiş yaptığımız sayfanın aynı olup olmadığını kontrol ediyoruz. Ve eğer aynı ise yeni fragment sayfasını yığınımıza ekliyor ancak bir önceki geldiği fragment ı siliyor. Bunu popBackStack() metodu ile sağlıyoruz.
if (backStackEntry.getName().contains(fragment_name)) { getSupportFragmentManager().popBackStack(); }
Eğer farkettiyseniz geri tuşuna son bastığınızda en son fragment kayboluyor. Bir boşluk ardından tekrar bastığınızda uygulamadan çıkıyor. Bunu kontrol ettirerek son fragment kaybolduğunda uygulamamızı kapattırabiliriz. onBackPressed() metodunu override ederek, son fragment ile birlikte uygulamadan çıkmasını sağlıyoruz.
@Override public void onBackPressed() { // fragment sayısı bir ise uygulamadan çıkıyor if(getSupportFragmentManager().getBackStackEntryCount() != 1) super.onBackPressed(); else { finish(); System.exit(0); } }
Biliyorsunuz ki her yeni menü öğesine tıkladığımızda ActionBar başlığımız değişiyor. Peki ya geri tuşuna bastığımızda bu gerçekleşiyor mu ? Hayır. Bunu nasıl düzeltiriz peki. Oldukça basit ilk olarak MainActivity içine aşağıdaki metodu ekliyoruz.
@Override public void setTitle(CharSequence title) { getSupportActionBar().setTitle(title); }
Bu metodu zaten kullanıyoruz. Ancak override etmemize gerek yoktu. Bir önceki yazıdan hatırlarsınız. Ancak bunu fragment sayfalarının da kullanmasını istiyoruz. Bunun için her sayfaya onAttach() metodunu ekliyoruz. Bu metod Activity içerisindeki bir metodu kolayca eklenen fragment ın da kullanmasını sağlıyor. onCreateView() içerisinde başlığı set ediyoruz. Bu sayede her oluşturulduğunda başlık değişmiş olacak.
FacebookFragment.java
package com.gkhnl.slidingmenuinandroid.pages; import android.app.Activity; import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.gkhnl.slidingmenuinandroid.MainActivity; import com.gkhnl.slidingmenuinandroid.R; public class FacebookFragment extends Fragment { Activity titleChange; public FacebookFragment() { // Required empty public constructor } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment titleChange.setTitle("Facebook"); return inflater.inflate(R.layout.fragment_facebook, container, false); } // Activity metodunu fragment içinde kullanmak içi attach işlemi yapıyoruz @Override public void onAttach(Activity activity) { super.onAttach(activity); titleChange = (MainActivity) activity; } }
Artık sona geldik. Tüm MainActivity sınıfımızı da paylaşalım.
MainActivity.java
package com.gkhnl.slidingmenuinandroid; import android.content.res.TypedArray; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBarActivity; import android.support.v7.app.ActionBarDrawerToggle; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.ListView; import com.gkhnl.slidingmenuinandroid.pages.FacebookFragment; import com.gkhnl.slidingmenuinandroid.pages.GoogleFragment; import com.gkhnl.slidingmenuinandroid.pages.InstagramFragment; import com.gkhnl.slidingmenuinandroid.pages.TwitterFragment; import java.util.ArrayList; import java.util.List; public class MainActivity extends ActionBarActivity { DrawerLayout drawerLayout; ActionBarDrawerToggle toggle; ListView lw_SlideMenu; SlideMenuAdapter adapter; List<SlideMenuItem> items; String[] titles; TypedArray icons; CharSequence actionBarTitle, appTitle; String fragment_name = ""; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); lw_SlideMenu = (ListView) findViewById(R.id.lw_Menu); drawerLayout = (DrawerLayout) findViewById(R.id.drawerLayout); // Menü başlıklarını kaynak dosyasından çekiyor titles = getResources().getStringArray(R.array.slidemenu_item); // icons dizimizi kaynak dosyadan çekiyoruz icons = getResources().obtainTypedArray(R.array.icons); // Ram i şişirmemek için resimleri yeniden yükler icons.recycle(); items = new ArrayList<SlideMenuItem>(); items.add(new SlideMenuItem(titles[0], icons.getResourceId(0, 0))); items.add(new SlideMenuItem(titles[1], icons.getResourceId(1, 0))); items.add(new SlideMenuItem(titles[2], icons.getResourceId(2, 0))); items.add(new SlideMenuItem(titles[3], icons.getResourceId(3,0))); // Açılışta uygulama ismini alıyor appTitle = getSupportActionBar().getTitle(); actionBarTitle = items.get(0).getTitle(); // Menüdeki her list item a click veriyor lw_SlideMenu.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { displayPage(i); // Her item a tıklanıldığında actionBar daki görünen başlığı değiştiriyor actionBarTitle = items.get(i).getTitle(); // menü tıklamadan sonra kapanıyor drawerLayout.closeDrawer(lw_SlideMenu); } }); adapter = new SlideMenuAdapter(items, getApplicationContext()); lw_SlideMenu.setAdapter(adapter); // Toggle butonuna click veriyoruz, home butonu gibi davranmasını sağlıyor. getSupportActionBar().setHomeButtonEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true); // toggle nesnesi oluşturuyoruz. toggle = new ActionBarDrawerToggle(this, drawerLayout, R.string.opened, R.string.closed) { @Override public void onDrawerOpened(View drawerView) { getSupportActionBar().setTitle(appTitle); } @Override public void onDrawerClosed(View drawerView) { getSupportActionBar().setTitle(actionBarTitle); } }; // toggle açılıp kapanmasına göre, toggle iconu değiştiriyor. toggle.syncState(); // menü açılıp kapanmasını dinliyoruz. drawerLayout.setDrawerListener(toggle); // Açılışta facebook ekranı gelecek displayPage(0); } private void displayPage(int position) { Fragment fragment = null; switch (position) { case 0: fragment = new FacebookFragment(); fragment_name = "FacebookFragment"; break; case 1: fragment = new TwitterFragment(); fragment_name = "TwitterFragment"; break; case 2: fragment = new GoogleFragment(); fragment_name = "GoogleFragment"; break; case 3: fragment = new InstagramFragment(); fragment_name = "InstagramFragment"; default: break; } if(fragment != null){ // Fragment transaction nesnesi ile fragment ekranları arasında geçiş sağlıyor FragmentManager fragmentManager = getSupportFragmentManager(); android.support.v4.app.FragmentTransaction transaction = fragmentManager.beginTransaction(); transaction.replace(R.id.container, fragment).addToBackStack(fragment_name).commit(); // Stack te bulunan fragment sayısını alıyor int count = getSupportFragmentManager().getBackStackEntryCount(); if(count!=0) { // Son fragment alınıyor FragmentManager.BackStackEntry backStackEntry = getSupportFragmentManager().getBackStackEntryAt(count - 1); // Son fragment ile seçilen fragment aynı ise eski fragment siliniyor if (backStackEntry.getName().contains(fragment_name)) { getSupportFragmentManager().popBackStack(); } } } } @Override public void onBackPressed() { // fragment sayısı bir ise uygulamadan çıkıyor if(getSupportFragmentManager().getBackStackEntryCount() != 1) super.onBackPressed(); else { finish(); System.exit(0); } } @Override public void setTitle(CharSequence title) { getSupportActionBar().setTitle(title); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); // toggle icona tıklanıldığında menünün açılmasını sağlıyor if (toggle.onOptionsItemSelected(item)) { return true; } if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } }
Ekran Görüntüleri
Projeyi doğru şekilde kodlarsak karşılaşacağımız ekran bunlar olacak.
Kaynak Kodlar
Projenin tümüne GitHub dan ulaşabilirisiniz.
Bir sonraki yazıda görüşmek üzere 🙂
Önceki Yazı |
Sonraki Yazı |
Android Navigation Drawer ile Slide Menü – 1 |
Android Navigation Drawer ile Slide Menü – 3 |
[…] Android Navigation Drawer ile Slide Menü – 2 […]
Yazı için teşekkürler. Benim sorum olacak,
NavigationDrawer Activity ile default menu oluşturdum yukarıdaki gibi. Fakat, iki adet fragmentim var, birinci fragmentteki işlem tamamlanınca diğer fragmene gidiyor. Sorun şu ki, diger fragmente geçtiğinde, menudeki arkaplan renki eski fragmentin olduğu bölgede duruyor. yani, menüye göre fragment1’deyim, fakat açık olan fragment2. İstediğim şu ki, fragment2’ye geçerken, menudeki fragment2’nin yazi arka plan rengini koyu yapmam gerekiyor ki nerede olduğum belli olsun.
Merhaba bir sorum olacak,
Uygulamama kodları ekledim tasarımı yaptım çalışıyor fakat listview deki butonlara yani fragmentlerime tıkladığımda o sayfalar açılmıyor. Bunun nedeni ne olabilir. Yardımcı olabilirseniz sevinirim.