منوی کشویی یا همان Navigation Drawer یکی از امکاناتی است که اکثر توسعهدهندگان اندروید آن را در پروژههای خود پیاده سازی میکنند. هرچند روشهای مختلفی برای پیادهسازی navigation drawer وجود دارد ولی در این مطلب میخواهم یکی از آسانترین و سریعترین روشهای پیاده سازی منوی کشویی را آموزش دهم.
در این مطلب ما به کمک کتابخانه MaterialDrawer اقدام به ساخت navigation drawer برای اپ خود میکنیم.
در گام نخست در فایل build.gradle پروژه خود در قسمت dependencies کدهای زیر را وارد کنید:
compile('com.mikepenz:materialdrawer:4.4.4@aar') { transitive = true }
بعد از ایجاد تغییرات در این فایل، پروژه شما sync میشود. بعد از این مرحله اگر مشکلی نبود سراغ گام بعدی میرویم.
نکته: اگر پروژه شما قدیمی باشد و از targetSdkVersion و همچنین compileSdkVersion پایین استفاده کنید gradle از شما پیغام خطا میگیرد. پس درنظر داشته باشید که باید پروژه با آخرین نسخه sdk کامپایل شود. همچنین باید appcompat-v7 و support-v4 هم به آخرین نسخه تغییر کند. بنابراین در این مرحله شاید لازم باشد sdk خود را بهروزرسانی کنید!
(در زمان نوشتن این مطلب targetSdkVersion و compileSdkVersion روی نسخه ۲۳ و appcompat-v7 و support-v4 هر دو روی نسخه 23.1.0 تنظیم شدهاند.)
نکته ۲: اگر بهدلیل محدودیتها نمیتوانید به صورت مستقیم sdk را بهروزرسانی کنید، میتوانید از این لینک استفاده کنید. بعد از دانلود هر فایل باید آن را در قسمت مناسب در پوشه sdk خود کپی کنید
در گام دوم کدهای زیر را در اکتیویتی که میخواهید منو را نمایش دهید وارد کنید (معمولا MainActivity) و همچنین import مناسب را در پروژه انجام دهید.
new DrawerBuilder().withActivity(this).build();
و تمام! به همین راحتی منوی کشویی شما ساخته شد!
اما در این مرحله منوی ما خالیست و هیچ محتوایی ندارد پس لازم است که یک سری کارها انجام دهیم و منوی کشویی را به شکل دلخواه تغییر دهیم و گزینههای منو را اضافه کنیم.
در ادامه کدهای drawer خودمان را تغییر میدهیم که بتوانیم راحتتر با آن کار کنیم.
در ابتدا یک آبجکت از drawer میسازیم:
Drawer drawer = null;
قسمتی که منو را build کردیم به این صورت تغییر میدهیم:
drawer = new DrawerBuilder().withActivity(this).build();
تا اینجای کار چیزی تغییر نکرد. بعد از اجرای پروژه همان نمای قبلی را مشاهده میکنیم.
اما استاندارد این است که در Toolbar یک علامت منو (علامت سه خط زیر هم) قرار بگیرد تا کاربر بداند در برنامه منو وجود دارد و با تپ کردن آن منو باز شود. (من در پروژههایم از Toolbar استفاده میکنم به شما هم توصیه میکنم از toolbar استفاده کنید. در این آموزش هم بر این مبنا جلو میرویم.)
پس قبل از بیلد کردن منو (.build) کد زیر را وارد میکنیم: (در اینجا toolbar همان آبجکتی است که در هنگام ساخت تولبار آن را ایجاد کردیم و از قبل در پروژه ما وجود داشته و ما فقط آن را به drawer پاس دادیم)
.withToolbar(toolbar)
حالا علامت منو هم به تولبار اضافه شد و با تپ کردن آن منو باز میشود.
اما اپهای ما فارسی هستند و روش صحیح این است که منو از سمت راست باز شود. برای این منظور از کد زیر استفاده میکنیم:
.withDrawerGravity(GravityCompat.END)
نکته: در نسخههای پایین اندروید، راستبهچپ به درستی پشتیبانی نمیشود و توصیه میشود که در این مواقع یکبار بررسی کنید که نسخه اندروید دستگاه کاربر چیست و متناسب با آن منو را راست یا چپ نمایش دهید. مثال:
int drawerGravity = Gravity.END; if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN) { drawerGravity = Gravity.START; }
در کدهای بالا بررسی کردم اگر نسخه api اندروید دستگاه کاربر کمتر یا مساوی 16 بود، مقدار gravity را برابر start (چپ) قرار دادم. یعنی در دستگاههای با نسخه پایینتر یا مساوی ۱۶ (JB) منو سمت چپ و اگر غیر این بود end (راست) نشان داده میشود. با این کار منو و علامت منو در یک طرف خواهند بود.
اما میرسیم به مهمترین مسئله، یعنی اضافه کردن گزینههای منو. برای اضافه کردن آیتمها از addDrawerItems استفاده میکنیم. کدهای ما بعد از اضافه کردن گزینهها به شکل زیر درمیآیند که به توضیح هرکدام خواهم پرداخت:
.addDrawerItems( new SectionDrawerItem().withName("دفترچه").withTextColor(ContextCompat.getColor(this, R.color.md_grey_500)).withDivider(false), new SecondaryDrawerItem().withName("تنظیمات").withIcon(R.drawable.ic_settings).withSelectable(false), new SectionDrawerItem().withName("موارد دیگر").withTextColor(ContextCompat.getColor(this, R.color.md_grey_500)), new SecondaryDrawerItem().withName("حمایت از برنامه").withIcon(R.drawable.ic_support).withSelectable(false), new SecondaryDrawerItem().withName("ارتباط").withIcon(R.drawable.ic_contact).withSelectable(false), new SecondaryDrawerItem().withName("درباره").withIcon(R.drawable.ic_about).withSelectable(false), new SecondaryDrawerItem().withName("بازخورد").withIcon(R.drawable.ic_feedback).withSelectable(false), new SecondaryDrawerItem().withName("ارتقا به نسخه پیشرفته").withIcon(R.drawable.ic_purchase).withSelectable(false).withIdentifier(8) )
ما چند نوع drawer item داریم.
PrimaryDrawerItem
SecondaryDrawerItem
SectionDrawerItem
اسم هرکدام نشاندهنده خاصیت آن است. منوی ما دو قسمت اصلی دارد که SectionDrawerItem نشان دهنده همین قسمتهاست. در این منو ما PrimaryDrawerItem نداریم و فقط از SecondaryDrawerItem استفاده کردیم. ترتیب نمایش آیتمهای منو مانند ترتیب قرار گرفتن کدهاست. یعنی ابتدا عنوان قسمت یا گروه میآید (SectionDrawerItem) و زیر آن گزینه مربوط به همان قسمت (SecondaryDrawerItem).
کارکرد گزینههای withName و WithIcon و withTextColor مشخص هستند.
به صورت پیشفرض بالای SectionDrawerItem خطی قرار میگیرد که هر گروه را از هم جدا کند. چون گروه اول ما در بالا قرار دارد پس لازم نیست خطی بالای آن باشد، پس بهوسیله withDivider تعیین کردیم که بالای گروه اول خط نباشد و خط فقط بالای گروه دوم ما (موارد دیگر) قرار گیرد.
گزینه withSelectable تعیین میکند که با انتخاب هر آیتم، رنگ پسزمینه آن تغییر کند یا خیر که ما در این پروژه به این خاصیت نیاز ندارید و آن را غیرفعال کردیم.
به وسیله گزینه withIdentifier هم به آیتم یک id دادیم و بهوسیله آن میتوانید بعدا به آن آیتم دسترسی داشته باشیم. (مثل دسترسی و حذف این آیتم در آینده)
در اینجا منوی ما شکل ظاهری خود را گرفت اما با تپ کردن روی هرکدام اتفاقی نمیافتد و باید برای آیتمهای منو وظیفه تعیین کنیم.
از کدهای زیر برای کنترل خاصیت onClick روی آیتمها استفاده میکنیم:
.withOnDrawerItemClickListener(new Drawer.OnDrawerItemClickListener() { @Override public boolean onItemClick(View view, int position, IDrawerItem drawerItem) { switch (position) { case 2: // Settings break; case 4: // Support app break; case 5: // Contact break; case 6: // About break; case 7: // Feedback break; case 8: // Purchase break; default: break; } return true; } })
با Switch روی Position آیتمها مشخص میکنیم که هر آیتم به کدام اکتیویتی متصل شود.
و در نهایت شکل کلی کدهای Navigation Drawer ما به این صورت خواهد بود:
drawer = new DrawerBuilder() .withActivity(this) .withToolbar(toolbar) .withDrawerGravity(drawerGravity) .withShowDrawerOnFirstLaunch(true) .addDrawerItems( new SectionDrawerItem().withName("دفترچه").withTextColor(ContextCompat.getColor(this, R.color.md_grey_500)).withDivider(false), new SecondaryDrawerItem().withName("تنظیمات").withIcon(R.drawable.ic_settings).withSelectable(false), new SectionDrawerItem().withName("موارد دیگر").withTextColor(ContextCompat.getColor(this, R.color.md_grey_500)), new SecondaryDrawerItem().withName("حمایت از برنامه").withIcon(R.drawable.ic_support).withSelectable(false), new SecondaryDrawerItem().withName("ارتباط").withIcon(R.drawable.ic_contact).withSelectable(false), new SecondaryDrawerItem().withName("درباره").withIcon(R.drawable.ic_about).withSelectable(false), new SecondaryDrawerItem().withName("بازخورد").withIcon(R.drawable.ic_feedback).withSelectable(false), new SecondaryDrawerItem().withName("ارتقا به نسخه پیشرفته").withIcon(R.drawable.ic_purchase).withSelectable(false).withIdentifier(8) ) .withOnDrawerItemClickListener(new Drawer.OnDrawerItemClickListener() { @Override public boolean onItemClick(View view, int position, IDrawerItem drawerItem) { switch (position) { case 2: // Settings break; case 4: // Support app break; case 5: // Contact break; case 6: // About break; case 7: // Feedback break; case 8: // Purchase break; default: break; } return true; } }) .build()
کتابخانه MaterialDrawer قابلیتهای فراوانی دارد و ساخت منوی کشویی را راحت کرده است. در استفاده از کلاسهای این کتابخانه محدودیت وجود ندارد و شما میتوانید کلاسهای آن را extend کنید و به دلخواه به کار ببرید.
از قابلیتهای این کتابخانه ساپورت از api 10، راهاندازی سریع، کاربری آسان، ساپورت RTL، قابلیت Customize کردن فراوان و… است. با گشت و گذار در مستندات آن در گیتهاب میتوانید بیشتر در مورد آن یاد بگیرید.
موفق باشید.
دیدگاهتان را بنویسید