Merhabalar,
Bu aralar işten dolayı yoğun olduğumdan ders paylaşamadım fakat bugün size özelleştirilmiş kayan menü nasıl yapılır onu anlatacağım. İnternet de görmüş olduğunuz çoğu örnekte kayan menülerin içinde ya yazı yada yazı ile birlikte image görürsünüz yani listview içinde elemanlar ve onlara bağlı olarak resimler vardır. Sliding Menu ye neden ihtiyaç duyarız kısaca ondan bahsederek dersimize devam edelim. Sliding Menu yapı olarak karmaşık gözükse de bir çok işlemimizi kolaylaştıran içeriğe sahiptir peki nedir bu kolaylaştıran yapı;
— istediğimiz menülere anında erişebilme özelliği ,
— seçenekler arasında yer değiştirip bir seçenek den diğerine geçebilme özelliği,
— istediğimiz sayfayı istediğimiz anda açabilme özelliği,
— Activity lere göre daha performanslı ve daha esnek bir yapıda olma özelliğin ( Fragment lardan dolayı )
Yukarıda görmüş olduğunuz etkenlerden dolayı böyle bir yapıyı kullanmak uygulamamızda avantajlı bir ortam oluşturmamıza yardımcı olur. Android Support Library nin v4 kütüphanesine eklenen Navigation Drawer yardımı ile yapımızı oluşturduk. Uygulamada kullandığım bu yapının DrawerLayout adlı bir layoutu vardır bu yapı sayesinde soldan kaydırarak getirdiğimiz modulun ana kısmını oluşturmuş oluruz. Bu yapının içinde ise FrameLayout var peki ne işe yarıyor bakalım; menü kapalıyken görünen alana bu yapıyı koyduğumuzda ve menü den istediğimiz alana tıkladığımız an o alana ait Fragment yapısını FrameLayout a yüklememize yardımcı olur. Bu yapıyı kullanabilmek için de bir Activity e ihtiyacımız var nedeni ise Fragment ların işlemlerini gerçekleştirebilmesi için her zaman Activity e ihtiyaç duymasıdır.
Şimdi bu yapıyı incelemeye başlayalım. Aşağıdaki xml dosyamıza baktığımızda Android Support Kütüphanesinde bulunan Drawer Layout yapısını kullandığımızı görüyoruz. İçinde yukarıda bahsettiğim gibi dinamik olarak değişecek olan alanın kontrolünü sağlayacak olan Frame Layout yapısını da görüyoruz. Drawer Layout yapımızın içinde oluşturmuş olduğum id si relativeLayout_slider_menu olan Relative Layout un ne işe yaradığını son kısımda anlatacağım.
activity_main.xml
<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" /> <RelativeLayout android:id="@+id/relativeLayout_slider_menu" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_gravity="start" > <include layout="@layout/slider_menu_layout"/> </RelativeLayout> </android.support.v4.widget.DrawerLayout>
Oluşturmuş olduğum menünün iç yapısını kısaca anlatacağım okurken gözünüzde canlanabilmesi için zaten kaynak kodlarını indirdiğiniz zaman ne yapmaya çalıştığımı göreceksiniz. Klasik sliding menü yapısından farklı olarak menü nün üst kısmına Login sayfasını ekledim onun altında menü deki seçeneklere ulaşabilmek için ListView yapısını ve en altta da iki adet buton yerleştirdim.
ListView in yapısını belirlemek içinde bir layout (custom_drawer_item.xml) oluşturdum. ListView içinde TextView tipinde seçeneklerimiz olacak bunun dışında kaynak kodlarını incelediğinizde göreceksiniz ImageView ile birlikte bu yapıyı kullanabiliriz fakat ben o kısmı oluşturmadım comment içinde olduğunu göreceksiniz. İstediğiniz yapıda bir ListView oluşturabilirsiniz zaten, ListView in rowlarında yer alacak component ları belirlemek size kalmış ben sadece örnek olmasını bakımından böyle bir yapı oluşturdum.
custom_drawer_item.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" > <LinearLayout android:id="@+id/itemLayout" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:orientation="vertical" android:layout_marginTop="0dp" android:background="?android:attr/activatedBackgroundIndicator" > <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_marginTop="5dp" android:layout_marginBottom="10dp" > <TextView android:id="@+id/drawer_itemName" android:layout_width="0dp" android:layout_height="match_parent" android:textColor="#000000" android:layout_weight="1" android:layout_marginLeft="20dp" android:textAppearance="?android:attr/textAppearanceSmall" /> </LinearLayout> </LinearLayout> </RelativeLayout>
ListView için Adapter da kullanacağımız görsel kısımı da hazırladığımıza göre şimdi ListView e tıkladığımız anda açılacak olan Fragment larımızı yaratalım. ListView in içini doldurabilmek için hazırlamış olduğum Adapter (CustomDrawerAdapter) kaynak kodlarının içinde yer almakta bu dersin amacı Custom Sliding Menu nasıl yapılır onu öğrenmek olduğundan, ListView ile ilgili detayları burada göstermek istemedim.
ListView içinde yer alan elemanlardan Home,Android,IOS ve WindowsPhone için açılan sayfalarımı Fragment yardımcı ile oluşturdum diğer elemanlar içinde sayfa oluşturma mantığı aynı şekilde olacak bu yüzden dersimizde yalnızca Home kısmını göstereceğim. Onun kodlarına ve görselde oluşturduğumuz layout a bakalım.
FragmentHome.java
package com.mobilhanem.slidingmenu; import android.app.Fragment; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; /** * Created by Alper on 1.2.2015. */ public class FragmentHome extends Fragment { ImageView ivIcon; TextView tvItemName; public static final String IMAGE_RESOURCE_ID = "iconResourceID"; public static final String ITEM_NAME = "itemName"; public FragmentHome() { } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(com.mobilhanem.slidingmenu.R.layout.fragment_layout_home, container,false); //ivIcon = (ImageView) view.findViewById(R.id.frag1_icon); tvItemName = (TextView) view.findViewById(com.mobilhanem.slidingmenu.R.id.txt_home); tvItemName.setText(getArguments().getString(ITEM_NAME)); //ivIcon.setImageDrawable(view.getResources().getDrawable(getArguments().getInt(IMAGE_RESOURCE_ID))); return view; } }
Yukarıda gördüğümüz gibi FragmentHome adındaki classımızı Fragment dan türettik böylece onun bütün özelliklerini ve yapısını kullanabilir hale geldik. View ile de yaratmış olduğumuz fragment_layout_home adını verdiğiniz görselliği almış olduk. İçinde bir TextView yer almakta kodları da incelerseniz eğer ListView içinde yer alan her bir elemana tıkladığımız anda bir Fragment açılmakta ve Fragment larımıza Bundle methodu yardımı ile tıkladığımız yerin ismini vererek açılan ilgili sayfada gösterdik. FragmentHome ile ilgili olan layout ise aşağıda yer almaktadır.
fragment_layout_home.xml
<?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:background="#008080"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceLarge" android:text="Large Text" android:id="@+id/txt_home" android:layout_centerVertical="true" android:layout_centerHorizontal="true" /> </RelativeLayout>
Şimdi gelelim MainActivity classımıza aslında bir çok önemli olay burada tetikleniyor Sliding Menu yapısal olarak Fragmentlar üzerine kurulduğu olduğu için çalışırken de bir Activity üzerinden çalışması gerektiğini söylemiştik ana classımızın içinde yer alan kodlara bir göz atalım.
onCreate methodunun içinde gerekli kodlar yer almakta işlevleri neler şimdi onları açıklayacağım sizlere. dataList adını verdiğimiz bir List oluşturduk içinde yer alacak verileride DrawerItem dan alıyoruz içine tek tek elemanları add methodu ile attık. CustomDrawerAdapter adında bir özel adapter oluşturduk bu da ListView i doldurmak için gerekli olan yapı ve bu yapıya dataList methodunu yollayarak method içinde gerekli olan düzenlemeleri yaptık. setAdapter methodu ile de ListView imizin içini oluşturmuş olduk.Menü açılıp, ListView içinden bir eleman seçildiğinde çağrılan fonksiyonumuz SelectItem() , bu fonksiyona seçmiş olduğumuz yerin pozisyonunu gönderiyoruz ve seçtilen pozisyona göre de switch-case yapısında hangisine denk geliyorsa , onunla ilgili Fragment ı yaratıyoruz. getFragmentManager() methodu ile seçilmiş olan fragment ı alıp Transaction ile bu olayı başlatıyoruz. En başta anlatmış olduğum Frame Layout yapısını kullanarak da bu frame içinde yer değişikliği yaparak seçilmiş olan fragmentı bu alana yerleştiriyoruz.
Daha sonradan drawerı kapatmamız gerekiyor şimdi gelelim en önemli yere; yukarıda activity_main.xml in içinde yer alan yapıda Frame Layoutumuzun dışında bir de Relative Layout yarattım. İşte sliding menu yü istediğimiz gibi şekillendirmeye yarayan yapı aslında bu kısım. Id sini relativeLayout_slider_menu olarak verdiğim bu yapının içinde başka bir layout u include ettiğimi göreceksiniz. İşte include etmiş olduğum yapıda bir layout dan oluşmakta ve istediğim düzenlemeyi o kısımda gerçekleştirmekteyim. Include etmiş olduğum bu yapıya bakalım; görsel olarak yukarıda anlattığım yapıyı burada oluşturdum.
1nci LinearLayout un içinde include etmiş olduğum id si headerlayout olan bir yapı var bu soldan çekdiğimizde gözükecek olan menünü en üst kısmını oluşturuyor o yapıyı ayrı bir yerde oluşturup burada kullandım. Parça parça oluştursanız sizde benim yaptığım gibi xml de yer alan yapınız karışıklığa uğramamış olur. headerlayout da Login kısmının görselliğini oluşturdum.
2nci LinearLayout un içinde ise iki adet buton yer almakta isimleri Control-1 ve Control-2 bu yapıyı bu kısımda oluşturdum çünkü sadece iki adet buton yerleştirdik en alt kısıma (Butonların event özelliği vermedim sadece farklı bir yapı oluşturmayı göstermek için görsellik anlamında yarattım )
3ncu LinearLayout un içinde ise id si left_drawer olarak yarattığımız bir ListView bulunmakta ( xml de gerekli kodlamaları göreceksiniz bu yapı yukarıda anlatmış olduğum LinearLayoutların arasında )
Internetdeki diğer örnekleri incelediyseniz eğer göreceksiniz drawer da işlemler bittikten sonra drawerı kapatırken ListView i içine alarak kapatmış oluyor nedeni ise menü yü açtığımız da içinde bir tek ListView in yer alması fakat bu uygulamada Custom bir yapı oluşturduğumuz için kapatmamız gereken android bileşeni ListView değil id sini relativeLayout_slider_menu olarak verdiğimiz yapıdır nedeni ise oluşturmuş olduğumuz yapı bunun içindedir bu yüzden bu view ı kapatmamız gerekmektedir. Aksi halde, uygulamayı çalıştırdığımız anda çökecektir. Uygulamanın kaynak kodlarını indirip incelerseniz anlatmak istediklerimi daha iyi anlayacaksınız. Bu yapıyı en başta oluşturduk ve işlemler bittikten sonrada kapattık. Bu adımı sakın unutmayın yoksa çok başınız ağrır.
mDrawerView = (RelativeLayout)findViewById(R.id.relativeLayout_slider_menu); (onCreate kısmında yaratıyoruz )
mDrawerLayout.closeDrawer(mDrawerView); ( SelectItem() fonksiyonu içinde kapatıyoruz )
Son bir uyarı daha drawer içinde oluşturduğumuz custom sliding menu yapısının soldan sağa doğru gelmesini istiyorsak eğer id si relativeLayout_slider_menu olan yapının xml dosyasında bu kodu eklemeyi de unutmuyoruz.
android:layout_gravity=”start”
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent"> <LinearLayout android:orientation="horizontal" android:layout_width="fill_parent" android:layout_alignParentTop="true" android:layout_height="wrap_content" android:id="@+id/linearLayout3"> <include layout="@layout/headerlayout"/> </LinearLayout> <LinearLayout android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:id="@+id/linearLayout4"> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/controlButtonOne" android:background="@drawable/custom_button_controlone_selector" android:text="@string/control_button" android:textSize="10dp" android:textColor="#fff" android:layout_weight="1" /> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/control_button_two" android:textSize="10dp" android:id="@+id/controlButtonTwo" android:background="@drawable/custom_button_controltwo_selector" android:textColor="#fff" android:layout_weight="1" /> </LinearLayout> <LinearLayout android:id="@+id/linearLayout_listview" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_below="@+id/linearLayout3" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_above="@+id/linearLayout4"> <ListView android:id="@+id/left_drawer" android:layout_width="fill_parent" android:layout_height="fill_parent" android:choiceMode="singleChoice" android:divider="@android:color/transparent" android:dividerHeight="10dp" android:background="#DCDCDC"/> </LinearLayout> </RelativeLayout>
package com.mobilhanem.slidingmenu; import java.util.ArrayList; import java.util.List; import android.os.Bundle; import android.app.Activity; import android.app.Fragment; import android.app.FragmentManager; import android.content.res.Configuration; import android.support.v4.app.ActionBarDrawerToggle; import android.support.v4.view.GravityCompat; import android.support.v4.widget.DrawerLayout; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.Button; import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.Toast; /** * Created by Alper on 1.2.2015. */ public class MainActivity extends Activity { private DrawerLayout mDrawerLayout; private RelativeLayout mDrawerView; private ListView mDrawerList; private ActionBarDrawerToggle mDrawerToggle; private CharSequence mDrawerTitle; private CharSequence mTitle; CustomDrawerAdapter adapter; private Button button_signIn; List<DrawerItem> dataList; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(com.mobilhanem.slidingmenu.R.layout.activity_main); // Initializing dataList = new ArrayList<DrawerItem>(); mTitle = mDrawerTitle = getTitle(); mDrawerLayout = (DrawerLayout) findViewById(com.mobilhanem.slidingmenu.R.id.drawer_layout); mDrawerList = (ListView) findViewById(com.mobilhanem.slidingmenu.R.id.left_drawer); mDrawerLayout.setDrawerShadow(com.mobilhanem.slidingmenu.R.drawable.drawer_shadow, GravityCompat.START); mDrawerView = (RelativeLayout)findViewById(com.mobilhanem.slidingmenu.R.id.relativeLayout_slider_menu); button_signIn = (Button)findViewById(com.mobilhanem.slidingmenu.R.id.button_signIn); button_signIn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(getApplicationContext(),"Login Buton Tıklandı!!",Toast.LENGTH_LONG).show(); } }); // Add Drawer Item to dataList dataList.add(new DrawerItem("ANASAYFA")); dataList.add(new DrawerItem("ANDROID")); dataList.add(new DrawerItem("IOS")); dataList.add(new DrawerItem("WINDOWS PHONE")); dataList.add(new DrawerItem("SYMBIAN")); dataList.add(new DrawerItem("BLACKBERRY")); dataList.add(new DrawerItem("WINDOWS MOBILE")); dataList.add(new DrawerItem("BADA")); dataList.add(new DrawerItem("MAEMO")); dataList.add(new DrawerItem("TIZEN")); dataList.add(new DrawerItem("AYARLAR")); dataList.add(new DrawerItem("YARDIM")); adapter = new CustomDrawerAdapter(this, com.mobilhanem.slidingmenu.R.layout.custom_drawer_item, dataList); mDrawerList.setAdapter(adapter); mDrawerList.setOnItemClickListener(new DrawerItemClickListener()); getActionBar().setDisplayHomeAsUpEnabled(true); getActionBar().setHomeButtonEnabled(true); mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, com.mobilhanem.slidingmenu.R.drawable.ic_drawer, com.mobilhanem.slidingmenu.R.string.drawer_open, com.mobilhanem.slidingmenu.R.string.drawer_close) { public void onDrawerClosed(View view) { getActionBar().setTitle(mDrawerTitle); invalidateOptionsMenu(); // creates call to // onPrepareOptionsMenu() } public void onDrawerOpened(View drawerView) { getActionBar().setTitle(mDrawerTitle); invalidateOptionsMenu(); // creates call to // onPrepareOptionsMenu() } }; mDrawerLayout.setDrawerListener(mDrawerToggle); if (savedInstanceState == null) { SelectItem(0); } } public void SelectItem(int possition) { Fragment fragment = null; Bundle args = new Bundle(); switch (possition) { case 0: fragment = new FragmentHome(); args.putString(FragmentHome.ITEM_NAME, dataList.get(possition).getItemName()); break; case 1: fragment = new FragmentAndroid(); args.putString(FragmentAndroid.ITEM_NAME, dataList.get(possition).getItemName()); break; case 2: fragment = new FragmentIOS(); args.putString(FragmentIOS.ITEM_NAME, dataList.get(possition).getItemName()); break; case 3: fragment = new FragmentWindowsPhone(); args.putString(FragmentWindowsPhone.ITEM_NAME, dataList.get(possition).getItemName()); break; case 4: fragment = new FragmentAndroid(); //args.putString(FragmentTwo.ITEM_NAME, dataList.get(possition).getItemName()); break; case 5: fragment = new FragmentIOS(); //args.putString(FragmentThree.ITEM_NAME, dataList.get(possition).getItemName()); break; case 6: fragment = new FragmentHome(); //args.putString(FragmentOne.ITEM_NAME, dataList.get(possition).getItemName()); break; case 7: fragment = new FragmentAndroid(); //args.putString(FragmentTwo.ITEM_NAME, dataList.get(possition).getItemName()); break; case 8: fragment = new FragmentIOS(); //args.putString(FragmentThree.ITEM_NAME, dataList.get(possition).getItemName()); break; case 9: fragment = new FragmentHome(); //args.putString(FragmentOne.ITEM_NAME, dataList.get(possition).getItemName()); break; case 10: fragment = new FragmentAndroid(); //args.putString(FragmentTwo.ITEM_NAME, dataList.get(possition).getItemName()); break; case 11: fragment = new FragmentIOS(); //args.putString(FragmentThree.ITEM_NAME, dataList.get(possition).getItemName()); break; case 12: fragment = new FragmentHome(); //args.putString(FragmentOne.ITEM_NAME, dataList.get(possition).getItemName()); break; default: break; } fragment.setArguments(args); FragmentManager frgManager = getFragmentManager(); frgManager.beginTransaction().replace(com.mobilhanem.slidingmenu.R.id.content_frame, fragment) .commit(); mDrawerList.setItemChecked(possition, true); setTitle(dataList.get(possition).getItemName()); //mDrawerLayout.closeDrawer(mDrawerList); mDrawerLayout.closeDrawer(mDrawerView); } @Override public void setTitle(CharSequence title) { mTitle = title; getActionBar().setTitle(mTitle); } @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); // Sync the toggle state after onRestoreInstanceState has occurred. mDrawerToggle.syncState(); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); // Pass any configuration change to the drawer toggles mDrawerToggle.onConfigurationChanged(newConfig); } @Override public boolean onOptionsItemSelected(MenuItem item) { // The action bar home/up action should open or close the drawer. // ActionBarDrawerToggle will take care of this. if (mDrawerToggle.onOptionsItemSelected(item)) { return true; } return false; } private class DrawerItemClickListener implements ListView.OnItemClickListener { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { SelectItem(position); } } }
Evet arkadaşlar, gördüğünüz gibi Custom Sliding Menu yapısını sizlere anlatmaya çalıştım. Kaynak kodu indirip uygulamayı çalıştırdığınız anda anlatmak istediklerimi daha iyi anlayacaksınız bir çok xml dosyası ve yapı olduğu için hepsini buraya koymak istemedim ana hatları ile önemli yerler üzerinde durmaya çalıştım , 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. Diğer dersimde görüşmek üzere kendinize iyi bakın 😉
Tüm Android Ders, Proje ve Kaynak Kodlar için tıklayınız.