Android

Android Navigation Drawer ile Slide Menü – 2

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.

drawable

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.

slide menü icon

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.

Fragment

Fragment2

 

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.

FragmentsHer 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.

fragment

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. fragment2

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.

Google Plus Facebook Page

 

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

2 Yorum

  • 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.

Yorum Yap