منوها مؤلفه میانای کاربر رایجی در بسیاری از انواع برنامهها هستند. برای
ارائه تجربه کاربری آشنا و منسجم، از
Menu API برای
ارائه کنشهای کاربر و گزینههای دیگر در فعالیتهایتان استفاده کنید.
این سند نشان میدهد که چگونه سه نوع اصلی منو یا ارائه کنش را در همه نسخههای Android ایجاد کنید:
- منوِ گزینهها و نوار برنامه
- منوِ گزینهها مجموعه اصلی گزینههای منو برای یک
فعالیت است. اینجا جایی است که کنشهایی را که تأثیر کلی بر برنامه دارند، مانند «جستجو»، «نوشتن ایمیل»، و «تنظیمات»، قرار میدهید.
بخش ایجاد منوِ گزینهها را ببینید.
- منوِ بافت و حالت کنش بافتاری
- منوِ بافت منوِ شناوری است
که وقتی کاربر روی عنصری لمس طولانی انجام میدهد ظاهر میشود. این نوار
کنشهایی را ارائه میدهد که بر محتوای انتخابشده یا قاب بافت تأثیر میگذارد.
حالت کنش بافتاری دستورهای اقدامی را که بر محتوای انتخابشده تأثیر میگذارند در نواری در بالای صفحه نمایش میدهد و به کاربر امکان میدهد چندین مورد را انتخاب کند.
بخش ایجاد منوِ بافتی را ببینید.
- منوِ بالاپر
- منوِ بالاپر فهرست عمودی از موارد را نمایش میدهد که به نمایی که منو را فراخوانی میکند متصل است. این منو برای ارائه اقدامات اضافی مرتبط با محتوای خاص یا ارائه گزینههایی برای بخش دوم فرمان مناسب است. کنشهای موجود در منوِ بالاپر مستقیماً بر محتوای مربوطه تأثیر نمیگذارند—کنشهای بافتاری برای این کار هستند. بلکه
منوِ بالاپر برای کنشهای گستردهای است که به مناطق محتوا در
فعالیت شما مربوط میشود.
بخش ایجاد منوِ بالاپر را ببینید.
تعریف منو در XML
برای همه انواع منو، Android قالب XML استانداردی برای تعریف گزینههای منو ارائه میدهد. بهجای ساختن منو در کد فعالیتتان، منو و همه موارد آن را در یک منبع منو XML تعریف کنید. سپس میتوانید منبع منو را در فعالیت یا قطعه خود باد کنید و آن را بهعنوان یک شیء Menu بارگذاری کنید.
استفاده از منبع منو بهدلایل زیر روال مطلوبی است:
- تجسم ساختار منو در XML آسانتر است.
- این کار محتوای منو را از کد رفتاری برنامهتان جدا میکند.
- این ویژگی به شما امکان میدهد بااستفاده از چارچوب منابع برنامه، پیکربندیهای منو جایگزین برای نسخههای مختلف پلاتفرم، اندازههای صفحهنمایش، و پیکربندیهای دیگر ایجاد کنید.
برای تعریف منو، فایل XML در دایرکتوری res/menu/ پروژه خود ایجاد کنید و منو را با عناصر زیر بسازید:
<menu>- یک
Menuرا تعریف میکند که محتوایی برای گزینههای منو است. عنصر<menu>باید گره ریشه فایل باشد و میتواند یک یا چند عنصر<item>و<group>داشته باشد. <item>- یک
MenuItemایجاد میکند، که نشاندهنده یک مورد در منو است. این عنصر میتواند حاوی عنصر<menu>تودرتو برای ایجاد زیرمنو باشد. <group>- یک محفظه اختیاری و نامرئی برای عناصر
<item>. این عنصر به شما امکان میدهد موارد منو را دستهبندی کنید تا ویژگیهای مشترکی داشته باشند، مثلاً حالت فعال و نمایان بودن. برای اطلاعات بیشتر، بخش ایجاد گروه منو را ببینید.
در اینجا منوی نمونهای بهنام game_menu.xml آورده شده است:
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/new_game" android:icon="@drawable/ic_new_game" android:title="@string/new_game" app:showAsAction="ifRoom"/> <item android:id="@+id/help" android:icon="@drawable/ic_help" android:title="@string/help" /> </menu>
عنصر <item> از چندین مشخصه پشتیبانی میکند که میتوانید از آنها برای تعریف ظاهر و رفتار یک مورد استفاده کنید. موارد موجود در منو قبلی
شامل مشخصههای زیر است:
android:id- شناسه منبعی که برای آن مورد منحصربهفرد است و به برنامه امکان میدهد مورد را هنگام انتخاب شدن توسط کاربر تشخیص دهد.
android:icon- ارجاع به یک drawable برای استفاده بهعنوان نماد مورد.
android:title- ارجاع به رشتهای که بهعنوان عنوان مورد استفاده میشود.
android:showAsAction- مشخصات مربوط به زمان و نحوه نمایش این مورد بهعنوان مورد اقدام در نوار برنامه.
اینها مهمترین مشخصههایی هستند که استفاده میکنید، اما مشخصههای بسیار دیگری نیز دردسترس است. برای کسب اطلاعات درباره همه مشخصههای پشتیبانیشده، به سند منبع منو مراجعه کنید.
میتوانید با افزودن عنصر <menu> بهعنوان فرزند <item>، زیرمنویی به هر موردی در هر منویی اضافه کنید.
زیرمنوها زمانی مفید هستند که برنامه شما عملکردهای زیادی داشته باشد که بتوان آنها را در موضوعاتی سازماندهی کرد، مانند موارد موجود در نوار منو برنامه رایانه شخصی—مانند فایل، ویرایش، و مشاهده. مثال زیر را ببینید:
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/file" android:title="@string/file" > <!-- "file" submenu --> <menu> <item android:id="@+id/create_new" android:title="@string/create_new" /> <item android:id="@+id/open" android:title="@string/open" /> </menu> </item> </menu>
برای استفاده از منو در فعالیتتان، منبع منو را _ازهم باز کنید_ و
منبع XML را بااستفاده از
MenuInflater.inflate() به شیء قابلبرنامهریزی تبدیل کنید.
بخشهای زیر نحوه گسترش منو را برای هر نوع منو نشان میدهد.
ایجاد منو گزینهها
منوِ گزینهها، مانند آنچه در شکل ۱ نشان داده شده است، جایی است که کنشها و گزینههای دیگری را که به بافت فعالیت فعلی مربوط هستند، مانند «جستجو»، «نوشتن ایمیل»، و «تنظیمات» اضافه میکنید.
میتوانید موارد منوِ گزینهها را از زیرکلاس
Activity
یا زیرکلاس
Fragment
اعلام کنید. اگر هم فعالیت و هم قطعههای شما مواردی را برای منوِ گزینهها اعلام کنند، این موارد در واسط کاربر ترکیب میشوند. موارد فعالیت ابتدا نشان داده میشوند و سپس موارد هر تکه بهترتیبی که تکهها به فعالیت اضافه شدهاند نشان داده میشوند. درصورت لزوم، میتوانید ترتیب گزینههای منو را با
مشخصه android:orderInCategory در هر
<item> که میخواهید جابهجا کنید تغییر دهید.
برای مشخص کردن منوِ گزینهها برای یک فعالیت،
onCreateOptionsMenu() را لغو کنید.
قطعهها
onCreateOptionsMenu()
برگشت تماس خودشان را ارائه میدهند. در این روش، میتوانید منبع منو را که
در XML تعریف شده است، در Menu ارائهشده در
فراخوانی برگشتی گسترش دهید. این موضوع در مثال زیر نشان داده شده است:
کاتلین
override fun onCreateOptionsMenu(menu: Menu): Boolean { val inflater: MenuInflater = menuInflater inflater.inflate(R.menu.game_menu, menu) return true }
جاوا
@Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.game_menu, menu); return true; }
همچنین میتوانید بااستفاده از
add()
گزینههای منو را اضافه کنید و با
findItem()
گزینهها را بازیابی کنید تا ویژگیهای آنها را با میاناهای برنامهسازی کاربردی MenuItem اصلاح کنید.
مدیریت رویدادهای کلیک
وقتی کاربر موردی را از منوِ گزینهها انتخاب میکند، ازجمله دستورهای اقدام
در نوار برنامه، سیستم
onOptionsItemSelected()
فعالیت شما را فراخوانی میکند. این روش MenuItem انتخابشده را ارسال میکند. میتوانید
مورد را با فراخوانی
getItemId() شناسایی کنید،
که شناسه یکتای مورد منو را برمیگرداند، که با
مشخصه android:id در منبع منو یا با عدد صحیحی که به
روش add() داده شده است تعریف میشود. میتوانید این شناسه را با گزینههای منو شناختهشده مطابقت دهید تا کنش مناسب را انجام دهید.
کاتلین
override fun onOptionsItemSelected(item: MenuItem): Boolean { // Handle item selection. return when (item.itemId) { R.id.new_game -> { newGame() true } R.id.help -> { showHelp() true } else -> super.onOptionsItemSelected(item) } }
جاوا
@Override public boolean onOptionsItemSelected(MenuItem item) { // Handle item selection. switch (item.getItemId()) { case R.id.new_game: newGame(); return true; case R.id.help: showHelp(); return true; default: return super.onOptionsItemSelected(item); } }
وقتی با موفقیت یک گزینه منو را مدیریت میکنید، true را برگردانید. اگر
گزینه منو را مدیریت نمیکنید، پیادهسازی سوپرکلاس
onOptionsItemSelected() را فراخوانی کنید. پیادهسازی پیشفرض
false را برمیگرداند.
اگر فعالیت شما شامل قطعه باشد، سیستم ابتدا
onOptionsItemSelected() را برای فعالیت فراخوانی میکند، سپس برای هر قطعه
بهترتیبی که قطعهها اضافه شدهاند، تا زمانی که یکی true را برگرداند یا
همه قطعهها فراخوانی شوند.
تغییر گزینههای منو در زمان اجرا
پساز اینکه سیستم onCreateOptionsMenu() را فراخوانی کرد،
نمونهای از Menu را که پر کردهاید حفظ میکند و
onCreateOptionsMenu() را دوباره فراخوانی نمیکند، مگراینکه منو نامعتبر شود.
بااینحال، از onCreateOptionsMenu() فقط برای ایجاد وضعیت منو اولیه استفاده کنید و نه برای ایجاد تغییرات درطول چرخه حیات فعالیت.
اگر میخواهید منوِ گزینهها را براساس رویدادهایی که درطول چرخه حیات فعالیت رخ میدهند تغییر دهید، میتوانید این کار را در روش
onPrepareOptionsMenu()
انجام دهید. این روش شیء Menu را همانطور که درحالحاضر وجود دارد به شما منتقل میکند تا بتوانید آن را تغییر دهید، مثلاً با افزودن، حذف، یا غیرفعال کردن موارد.
قطعهها همچنین یک
onPrepareOptionsMenu()
فراخوانی برگشتی ارائه میدهند.
وقتی گزینههای منو در نوار برنامه ارائه میشوند، منوِ گزینهها همیشه باز درنظر گرفته میشود. وقتی رویدادی رخ میدهد و میخواهید منو را بهروز کنید، با
invalidateOptionsMenu()
تماس بگیرید تا درخواست کنید سیستم با onPrepareOptionsMenu() تماس بگیرد.
ایجاد منوِ بافتی
منوِ بافتی کنشهایی را ارائه میدهد که بر مورد یا قاب بافت خاصی در واسط کاربر تأثیر میگذارد. میتوانید برای هر نمایی منوِ زمینهای ارائه دهید، اما این منوها اغلب برای موارد موجود در
RecylerView یا
مجموعههای نمای دیگر استفاده میشوند که در آنها کاربر میتواند کنشهای مستقیم روی هر
مورد انجام دهد.
دو روش برای ارائه کنشهای بافتاری وجود دارد:
- در منوِ بافت شناور. وقتی کاربر روی نمایی که پشتیبانی از منوِ بافت را اعلام میکند لمس طولانی انجام میدهد، منو بهصورت فهرست شناوری از گزینههای منو، شبیه به کادر گفتگو، ظاهر میشود. کاربران میتوانند در هر زمان یک کنش بافتاری روی یک مورد انجام دهند.
- در حالت کنش بافتاری. این حالت پیادهسازی سیستمی
ActionModeاست که نوار کنش بافتاری (یا CAB) را در بالای صفحه با دستورهای اقدام که بر مورد(های) انتخابشده تأثیر میگذارد نمایش میدهد. وقتی این حالت فعال باشد، کاربران میتوانند کنشی را بهطور همزمان روی چند مورد انجام دهند، البته اگر برنامه شما از آن پشتیبانی کند.
توجه: منوِ بافت از میانبرهای مورد و نمادهای مورد پشتیبانی نمیکند.
ایجاد منوِ بافت شناور
برای ارائه منوِ زمینهای شناور، کارهای زیر را انجام دهید:
Viewرا که منوِ بافت با آن مرتبط است با فراخوانیregisterForContextMenu()و ارسالViewبه آن ثبت کنید.اگر فعالیت شما از
RecyclerViewاستفاده میکند و میخواهید هر مورد منوِ بافت یکسانی ارائه دهد، همه موارد را برای منوِ بافت با ارسالRecyclerViewبهregisterForContextMenu()ثبت کنید.- روش
onCreateContextMenu()را درActivityیاFragmentپیادهسازی کنید.وقتی نمای ثبتشده رویداد لمس کردن و نگه داشتن را دریافت میکند، سیستم روش
onCreateContextMenu()شما را فراخوانی میکند. در اینجا گزینههای منو را تعریف میکنید، معمولاً با گسترش دادن منبع منو، مانند مثال زیر:کاتلین
override fun onCreateContextMenu(menu: ContextMenu, v: View, menuInfo: ContextMenu.ContextMenuInfo) { super.onCreateContextMenu(menu, v, menuInfo) val inflater: MenuInflater = menuInflater inflater.inflate(R.menu.context_menu, menu) }
جاوا
@Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.context_menu, menu); }
MenuInflaterبه شما امکان میدهد منوِ زمینهای را از منبع منو گسترش دهید. پارامترهای روش فراخوانی شاملViewکه کاربر انتخاب میکند و شیءContextMenu.ContextMenuInfoاست که اطلاعات بیشتری درباره مورد انتخابشده ارائه میدهد. اگر فعالیت شما چندین نما دارد که هرکدام منوِ بافت متفاوتی ارائه میدهند، میتوانید از این پارامترها برای تعیین اینکه کدام منوِ بافت گسترده شود استفاده کنید. onContextItemSelected()را همانطور که در مثال زیر نشان داده شده است پیادهسازی کنید. وقتی کاربر یکی از گزینههای منو را انتخاب میکند، سیستم این روش را فراخوانی میکند تا بتوانید کنش مناسب را انجام دهید.کاتلین
override fun onContextItemSelected(item: MenuItem): Boolean { val info = item.menuInfo as AdapterView.AdapterContextMenuInfo return when (item.itemId) { R.id.edit -> { editNote(info.id) true } R.id.delete -> { deleteNote(info.id) true } else -> super.onContextItemSelected(item) } }
جاوا
@Override public boolean onContextItemSelected(MenuItem item) { AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo(); switch (item.getItemId()) { case R.id.edit: editNote(info.id); return true; case R.id.delete: deleteNote(info.id); return true; default: return super.onContextItemSelected(item); } }
روش
getItemId()شناسه گزینه منو انتخابشده را جستوجو میکند، که شما آن را به هر گزینه منو در XML بااستفاده از مشخصهandroid:idاختصاص میدهید، همانطور که در تعریف منو در XML نشان داده شده است.وقتی با موفقیت یک گزینه منو را مدیریت میکنید،
trueرا برگردانید. اگر گزینه منو را مدیریت نمیکنید، گزینه منو را به پیادهسازی کلاس برتر منتقل کنید. اگر فعالیت شما شامل قطعات باشد، فعالیت ابتدا این فراخوانی برگشتی را دریافت میکند. با فراخوانی کلاس برتر درصورت عدم رسیدگی، سیستم رویداد را به روش فراخوان برگشتی مربوطه در هر قطعه، یکی پساز دیگری، بهترتیبی که هر قطعه اضافه شده است، ارسال میکند تا زمانی کهtrueیاfalseبرگردانده شود. پیادهسازیهای پیشفرض برایActivityوandroid.app.Fragmentfalseرا برمیگردانند، بنابراین همیشه وقتی مدیریتنشده است، کلاس فوق را فراخوانی کنید.
استفاده از حالت کنش بافتاری
حالت کنش بافتاری پیادهسازی سیستمی
ActionMode است که تعامل کاربر را بهسمت انجام
کنشهای بافتاری متمرکز میکند. وقتی کاربر با انتخاب موردی این حالت را فعال میکند،
نوار کنش بافتاری در بالای صفحه ظاهر میشود تا کنشهایی را که کاربر میتواند
روی موارد انتخابشده انجام دهد ارائه کند. وقتی این حالت فعال باشد،
کاربر میتواند چند مورد را انتخاب کند (اگر برنامهتان از آن پشتیبانی کند)، میتواند انتخاب موارد را لغو کند،
و به پیمایش در فعالیت ادامه دهد. وقتی کاربر همه موارد را لغو انتخاب میکند، روی دکمه «برگشت» ضربه میزند، یا روی کنش تمام در سمت چپ نوار ضربه میزند، حالت کنش غیرفعال میشود و نوار کنش بافتاری ناپدید میشود.
برای نماهایی که کنشهای بافتاری ارائه میدهند، معمولاً وقتی یکی یا هر دو این رویدادها اتفاق میافتد، حالت کنش بافتاری را فراخوانی میکنید:
- کاربر روی نما لمس میکند و نگه میدارد.
- کاربر چارگوش انتخاب یا مؤلفه واسط کاربر مشابهی را در نما انتخاب میکند.
نحوه فراخوانی حالت کنش بافتاری توسط برنامه شما و تعریف رفتار برای هر کنش به طراحی شما بستگی دارد. دو طرح وجود دارد:
- برای کنشهای بافتاری در نماهای دلخواه و جداگانه.
- برای کنشهای بافتاری دستهای روی گروههای موارد در
RecyclerView، به کاربر اجازه میدهد چندین مورد را انتخاب کند و روی همه آنها کنشی انجام دهد.
بخشهای زیر راهاندازی لازم برای سناریو اول را شرح میدهد.
فعال کردن حالت کنش بافتاری برای نماهای تکی
اگر میخواهید حالت کنش بافتاری را فقط زمانی فراخوانی کنید که کاربر نماهای خاصی را انتخاب میکند، کارهای زیر را انجام دهید:
- میانای
ActionMode.Callbackرا همانطور که در مثال زیر نشان داده شده است پیادهسازی کنید. در روشهای فراخوانی آن، میتوانید کنشهای مربوط به نوار کنش بافتاری را مشخص کنید، به رویدادهای کلیک روی دستورهای اقدام پاسخ دهید، و دیگر رویدادهای چرخه حیات را برای حالت کنش مدیریت کنید.کاتلین
private val actionModeCallback = object : ActionMode.Callback { // Called when the action mode is created. startActionMode() is called. override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean { // Inflate a menu resource providing context menu items. val inflater: MenuInflater = mode.menuInflater inflater.inflate(R.menu.context_menu, menu) return true } // Called each time the action mode is shown. Always called after // onCreateActionMode, and might be called multiple times if the mode // is invalidated. override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean { return false // Return false if nothing is done } // Called when the user selects a contextual menu item. override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean { return when (item.itemId) { R.id.menu_share -> { shareCurrentItem() mode.finish() // Action picked, so close the CAB. true } else -> false } } // Called when the user exits the action mode. override fun onDestroyActionMode(mode: ActionMode) { actionMode = null } }
جاوا
private ActionMode.Callback actionModeCallback = new ActionMode.Callback() { // Called when the action mode is created. startActionMode() is called. @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { // Inflate a menu resource providing context menu items. MenuInflater inflater = mode.getMenuInflater(); inflater.inflate(R.menu.context_menu, menu); return true; } // Called each time the action mode is shown. Always called after // onCreateActionMode, and might be called multiple times if the mode // is invalidated. @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { return false; // Return false if nothing is done. } // Called when the user selects a contextual menu item. @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { switch (item.getItemId()) { case R.id.menu_share: shareCurrentItem(); mode.finish(); // Action picked, so close the CAB. return true; default: return false; } } // Called when the user exits the action mode. @Override public void onDestroyActionMode(ActionMode mode) { actionMode = null; } };
این فراخوانیهای برگشتی رویداد تقریباً دقیقاً مشابه فراخوانیهای برگشتی برای منوِ گزینهها هستند، با این تفاوت که هرکدام از اینها شیء
ActionModeمرتبط با رویداد را نیز ارسال میکنند. میتوانید از میاناهای برنامهسازی کاربردیActionModeبرای ایجاد تغییرات مختلف در نوار کنش زمینهای استفاده کنید، مثلاً بازنگری عنوان و عنوان فرعی باsetTitle()وsetSubtitle()، که برای نشان دادن تعداد موارد انتخابشده مفید است.نمونه قبلی متغیر
actionModeرا رویnullتنظیم میکند وقتی حالت کنش ازبین میرود. در مرحله بعد، ببینید چگونه مقداردهی اولیه میشود و چگونه ذخیره کردن متغیر عضو در فعالیت یا قطعه شما میتواند مفید باشد. - وقتی میخواهید نوار را نشان دهید، مثلاً وقتی کاربر روی نما لمس میکند و نگه میدارد،
startActionMode()را فراخوانی کنید.کاتلین
someView.setOnLongClickListener { view -> // Called when the user performs a touch & hold on someView. when (actionMode) { null -> { // Start the CAB using the ActionMode.Callback defined earlier. actionMode = activity?.startActionMode(actionModeCallback) view.isSelected = true true } else -> false } }
جاوا
someView.setOnLongClickListener(new View.OnLongClickListener() { // Called when the user performs a touch & hold on someView. public boolean onLongClick(View view) { if (actionMode != null) { return false; } // Start the CAB using the ActionMode.Callback defined earlier. actionMode = getActivity().startActionMode(actionModeCallback); view.setSelected(true); return true; } });
وقتی
startActionMode()را فراخوانی میکنید، سیستمActionModeایجادشده را برمیگرداند. با ذخیره کردن این در متغیر عضو، میتوانید در پاسخ به رویدادهای دیگر، تغییراتی در نوار کنش بافتاری ایجاد کنید. در نمونه قبلی، ازActionModeاستفاده میشود تا اطمینان حاصل شود که نمونهActionModeدرصورتیکه قبلاً فعال باشد، دوباره ایجاد نمیشود. این کار با بررسی اینکه آیا عضو قبلاز شروع حالت کنش null است یا نه انجام میشود.
ایجاد منوِ بالاپر
PopupMenu
منویی مدال است که به View متصل شده است. اگر فضا وجود داشته باشد، در زیر نمای لنگر ظاهر میشود، درغیراینصورت در بالای نما ظاهر میشود. این کار برای موارد زیر مفید است:
- ارائه منوِ سبک سرریز برای کنشهایی که مربوط به محتوای خاصی هستند، مثل سرصفحههای ایمیل Gmail، که در شکل ۴ نشان داده شده است.
- ارائه بخش دوم جمله فرمان، مثل دکمهای با برچسب افزودن که منوِ بالاپری با گزینههای مختلف افزودن تولید میکند.
- ارائه منویی مشابه
Spinnerکه انتخاب دائمی را حفظ نمیکند.
اگر منو را در XML تعریف کنید، در اینجا نحوه نمایش منوِ بالاپر آورده شده است:
- یک
PopupMenuرا با سازنده آن نمونهسازی کنید، که برنامه فعلیContextوViewرا که منو به آن متصل است میگیرد. - از
MenuInflaterبرای گسترش منبع منو در شیءMenuکه توسطPopupMenu.getMenu()برگردانده شده است استفاده کنید. - تماس با
PopupMenu.show().
برای مثال، در اینجا دکمهای وجود دارد که منوِ بالاپری را نشان میدهد:
<ImageButton android:id="@+id/dropdown_menu" android:layout_width="wrap_content" android:layout_height="wrap_content" android:contentDescription="@string/descr_overflow_button" android:src="@drawable/arrow_drop_down" />
سپس فعالیت میتواند منوِ بالاپر را بهاینصورت نشان دهد:
کاتلین
findViewById<ImageButton>(R.id.dropdown_menu).setOnClickListener { val popup = PopupMenu(this, it) val inflater: MenuInflater = popup.menuInflater inflater.inflate(R.menu.actions, popup.menu) popup.show() }
جاوا
findViewById(R.id.dropdown_menu).setOnClickListener(v -> { PopupMenu popup = new PopupMenu(this, v); popup.getMenuInflater().inflate(R.menu.actions, popup.getMenu()); popup.show(); });
وقتی کاربر موردی را انتخاب میکند یا خارج از ناحیه منو تکضرب میزند، منو بسته میشود. میتوانید بااستفاده از
PopupMenu.OnDismissListener به رویداد بستن گوش دهید.
مدیریت رویدادهای کلیک
برای انجام کنش وقتی کاربر گزینه منو را انتخاب میکند، میانای
PopupMenu.OnMenuItemClickListener
را پیادهسازی کنید و آن را با فراخوانی
setOnMenuItemclickListener()
در PopupMenu خود ثبت کنید.
وقتی کاربر موردی را انتخاب میکند، سیستم
onMenuItemClick()
فراخوانی برگشتی را در واسط شما فراخوانی میکند.
این موضوع در مثال زیر نشان داده شده است:
کاتلین
fun showMenu(v: View) { PopupMenu(this, v).apply { // MainActivity implements OnMenuItemClickListener. setOnMenuItemClickListener(this@MainActivity) inflate(R.menu.actions) show() } } override fun onMenuItemClick(item: MenuItem): Boolean { return when (item.itemId) { R.id.archive -> { archive(item) true } R.id.delete -> { delete(item) true } else -> false } }
جاوا
public void showMenu(View v) { PopupMenu popup = new PopupMenu(this, v); // This activity implements OnMenuItemClickListener. popup.setOnMenuItemClickListener(this); popup.inflate(R.menu.actions); popup.show(); } @Override public boolean onMenuItemClick(MenuItem item) { switch (item.getItemId()) { case R.id.archive: archive(item); return true; case R.id.delete: delete(item); return true; default: return false; } }
ایجاد گروه منو
گروه منو مجموعهای از گزینههای منو است که ویژگیهای خاصی را بهاشتراک میگذارند. با گروه میتوانید کارهای زیر را انجام دهید:
- نمایش یا پنهان کردن همه موارد بااستفاده از
setGroupVisible(). - فعال یا غیرفعال کردن همه موارد بااستفاده از
setGroupEnabled(). - مشخص کنید که آیا همه موارد بااستفاده از
setGroupCheckable()قابلعلامتگذاری هستند یا نه.
میتوانید با قرار دادن عناصر <item> در داخل عنصر <group> در منبع منو یا با مشخص کردن شناسه گروه با روش add() گروه ایجاد کنید.
در اینجا نمونهای از منبع منو که شامل گروه است آورده شده است:
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/menu_save" android:icon="@drawable/menu_save" android:title="@string/menu_save" /> <!-- menu group --> <group android:id="@+id/group_delete"> <item android:id="@+id/menu_archive" android:title="@string/menu_archive" /> <item android:id="@+id/menu_delete" android:title="@string/menu_delete" /> </group> </menu>
مواردی که در گروه هستند در همان سطح مورد اول ظاهر میشوند—هر سه مورد در منو همرده هستند. بااینحال، میتوانید با ارجاع به شناسه گروه و استفاده از روشهای قبلی، ویژگیهای دو مورد موجود در گروه را تغییر دهید. همچنین سیستم هرگز موارد گروهبندیشده را از هم جدا نمیکند. برای مثال، اگر android:showAsAction="ifRoom" را برای هر مورد اعلام کنید، هر دو در نوار اقدام یا هر دو در سرریز اقدام ظاهر میشوند.
استفاده از گزینههای منوِ قابلانتخاب
منو میتواند بهعنوان واسطی برای روشن و خاموش کردن گزینهها، استفاده از چارگوش انتخاب برای گزینههای مستقل، یا دکمههای رادیویی برای گروههای گزینههای ناسازگار با یکدیگر مفید باشد. شکل ۵ زیرمنویی را با گزینههایی نشان میدهد که با دکمههای رادیویی قابلانتخاب هستند.
میتوانید رفتار قابلانتخاب را برای موارد منو بهصورت جداگانه بااستفاده از مشخصه
android:checkable در عنصر <item>
یا برای کل گروه با مشخصه android:checkableBehavior
در عنصر <group> تعریف کنید. برای مثال، همه موارد در
این گروه منو با دکمه رادیویی قابلانتخاب هستند:
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <group android:checkableBehavior="single"> <item android:id="@+id/red" android:title="@string/red" /> <item android:id="@+id/blue" android:title="@string/blue" /> </group> </menu>
مشخصه android:checkableBehavior یکی از موارد زیر را میپذیرد:
single- فقط یک مورد از گروه را میتوان علامت زد، که منجر به دکمههای رادیویی میشود.
all- همه موارد را میتوان علامت زد، که منجر به چارگوشهای انتخاب میشود.
none- هیچ موردی قابلبررسی نیست.
میتوانید بااستفاده از مشخصه
android:checked در عنصر <item>،
وضعیت علامتزده پیشفرض را به موردی اعمال کنید
و آن را در کد با روش
setChecked()
تغییر دهید.
وقتی موردی که میتوان آن را علامت زد انتخاب میشود، سیستم روش فراخوانی برگشتی مربوط به مورد انتخابشده را فراخوانی میکند، مانند onOptionsItemSelected().
اینجا جایی است که وضعیت چارگوش انتخاب را تنظیم میکنید، زیرا چارگوش انتخاب یا دکمه رادیویی
وضعیت خود را بهطور خودکار تغییر نمیدهد. میتوانید وضعیت فعلی
مورد را (همانطور که قبلاز انتخاب کاربر بود) با
isChecked()
پرسوجو کنید و سپس وضعیت علامتگذاریشده را با setChecked() تنظیم کنید. این موضوع در مثال زیر نشان داده شده است:
کاتلین
override fun onOptionsItemSelected(item: MenuItem): Boolean { return when (item.itemId) { R.id.vibrate, R.id.dont_vibrate -> { item.isChecked = !item.isChecked true } else -> super.onOptionsItemSelected(item) } }
جاوا
@Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.vibrate: case R.id.dont_vibrate: if (item.isChecked()) item.setChecked(false); else item.setChecked(true); return true; default: return super.onOptionsItemSelected(item); } }
اگر وضعیت علامتگذاریشده را به این روش تنظیم نکنید، وضعیت قابلمشاهده چارگوش انتخاب یا دکمه رادیویی وقتی کاربر آن را انتخاب میکند تغییر نمیکند. وقتی که وضعیت را تنظیم میکنید، فعالیت وضعیت علامتگذاریشده مورد را حفظ میکند تا وقتی کاربر بعداً منو را باز میکند، وضعیت علامتگذاریشدهای که تنظیم کردهاید قابلمشاهده باشد.
افزودن گزینههای منو براساس قصد
گاهی اوقات میخواهید یک گزینه منو فعالیتی را بااستفاده از
Intent راهاندازی کند،
خواه این فعالیت در برنامه شما باشد یا برنامه دیگری. وقتی
قصدی را که میخواهید استفاده کنید میدانید و گزینه منو خاصی دارید که
قصد را آغاز میکند، میتوانید قصد را با
startActivity()
درطول روش فراخوانی برگشتی مناسب انتخابشده روی گزینه، مانند فراخوانی برگشتی
onOptionsItemSelected()، اجرا کنید.
بااینحال، اگر مطمئن نیستید که دستگاه کاربر حاوی برنامهای است که هدف را مدیریت میکند، افزودن یک مورد منو که آن را فراخوانی میکند میتواند منجر به یک مورد منو غیرفعال شود، زیرا ممکن است هدف به یک فعالیت حل نشود. برای حل این مشکل، Android به شما امکان میدهد وقتی Android فعالیتهایی را در دستگاه پیدا میکند که هدف شما را مدیریت میکنند، بهطور پویا گزینههای منو را به منو اضافه کنید.
برای افزودن گزینههای منو براساس فعالیتهای دردسترس که قصد را میپذیرند، کارهای زیر را انجام دهید:
- قصدی را با دسته
CATEGORY_ALTERNATIVEیاCATEGORY_SELECTED_ALTERNATIVE، یا هر دو، بهعلاوه هرگونه الزامات دیگر تعریف کنید. - تماس با
Menu.addIntentOptions(). سپس Android برنامههایی را که میتوانند هدف را اجرا کنند جستجو میکند و آنها را به منو اضافه میکند.
اگر هیچ برنامهای نصب نشده باشد که هدف را برآورده کند، هیچ موردی به منو اضافه نمیشود.
این موضوع در مثال زیر نشان داده شده است:
کاتلین
override fun onCreateOptionsMenu(menu: Menu): Boolean { super.onCreateOptionsMenu(menu) // Create an Intent that describes the requirements to fulfill, to be // included in the menu. The offering app must include a category value // of Intent.CATEGORY_ALTERNATIVE. val intent = Intent(null, dataUri).apply { addCategory(Intent.CATEGORY_ALTERNATIVE) } // Search and populate the menu with acceptable offering apps. menu.addIntentOptions( R.id.intent_group, // Menu group to which new items are added. 0, // Unique item ID (none). 0, // Order for the items (none). this.componentName, // The current activity name. null, // Specific items to place first (none). intent, // Intent created above that describes the requirements. 0, // Additional flags to control items (none). null) // Array of MenuItems that correlate to specific items (none). return true }
جاوا
@Override public boolean onCreateOptionsMenu(Menu menu){ super.onCreateOptionsMenu(menu); // Create an Intent that describes the requirements to fulfill, to be // included in the menu. The offering app must include a category value // of Intent.CATEGORY_ALTERNATIVE. Intent intent = new Intent(null, dataUri); intent.addCategory(Intent.CATEGORY_ALTERNATIVE); // Search and populate the menu with acceptable offering apps. menu.addIntentOptions( R.id.intent_group, // Menu group to which new items are added. 0, // Unique item ID (none). 0, // Order for the items (none). this.getComponentName(), // The current activity name. null, // Specific items to place first (none). intent, // Intent created above that describes the requirements. 0, // Additional flags to control items (none). null); // Array of MenuItems that correlate to specific items (none). return true; }
برای هر فعالیت یافتشدهای که فیلتر قصدی مطابق با قصد تعریفشده ارائه میدهد، یک گزینه منو اضافه میشود که از مقدار موجود در android:label فیلتر قصد بهعنوان عنوان گزینه منو و از نماد برنامه بهعنوان نماد گزینه منو استفاده میکند. روش addIntentOptions() تعداد موارد منو اضافهشده را برمیگرداند.
اجازه دهید فعالیتتان به منوهای دیگر اضافه شود
میتوانید سرویسهای فعالیتتان را به برنامههای دیگر ارائه دهید تا برنامه شما بتواند در منو برنامههای دیگر گنجانده شود—نقشهایی که قبلاً شرح داده شد معکوس میشود.
برای گنجانده شدن در منوهای برنامههای دیگر، فیلتر هدفی را طبق معمول تعریف کنید،
اما مقادیر CATEGORY_ALTERNATIVE یا
CATEGORY_SELECTED_ALTERNATIVE، یا هر دو را برای دسته فیلتر هدف
دربرگیرد. این موضوع در مثال زیر نشان داده شده است:
<intent-filter label="@string/resize_image"> ... <category android:name="android.intent.category.ALTERNATIVE" /> <category android:name="android.intent.category.SELECTED_ALTERNATIVE" /> ... </intent-filter>
درباره نوشتن فیلترهای قصد در قصدها و فیلترهای قصد بیشتر بخوانید.