I'm using the ActionBar menu as:
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/menu_search"
android:actionViewClass="com.abc.AppSearchView"
android:icon="#drawable/ic_menu_search"
android:showAsAction="always|collapseActionView" />
</menu>
Then I inflate it and :
public override bool OnCreateOptionsMenu (IMenu menu)
{
MenuInflater.Inflate (Resource.Menu.actionMenu, menu);
_actionBarMenu = menu;
// Get the SearchView and set the searchable configuration
var searchManager = (SearchManager)GetSystemService (SearchService);
var searchMenuItem = menu.FindItem (Resource.Id.menu_search);
var searchView = (AppSearchView)searchMenuItem.ActionView;
// Assumes current activity is the searchable activity
searchView.SetSearchableInfo (searchManager.GetSearchableInfo (ComponentName));
searchView.SetSearchViewListener (this);
return base.OnCreateOptionsMenu (menu);
}
I have a custom Search View implementation:
public class AppSearchView : SearchView
{
private IAppSearchViewListener mListener;
public AppSearchView (Context ctxt) : base (ctxt)
{
}
public override void OnActionViewCollapsed ()
{
if (mListener != null)
mListener.OnSearchViewCollapsed (this);
base.OnActionViewCollapsed ();
}
public override void OnActionViewExpanded ()
{
if (mListener != null)
mListener.OnSearchViewExpanded (this);
base.OnActionViewExpanded ();
}
public interface IAppSearchViewListener
{
void OnSearchViewCollapsed (SearchView sView);
void OnSearchViewExpanded (SearchView sView);
}
public void SetSearchViewListener (IAppSearchViewListener listener)
{
mListener = listener;
}
}
The searchMenuItem.ActionView is null (Consequently, search view is null). But this same code works in another application I have. Both applications are using Xamarin.Android.Support.v13.
Also, if I use android.widget.SearchView, it works fine and ActionView is not null.
Could someone please shed some light on the same?
Problem is that you are trying to cast a Java type into a .NET type. This only works for some types.
Instead in your OnCreateOptionsMenu implementation you will need to use .JavaCast<T>() extension method to help you.
Something like this works for me:
public override bool OnCreateOptionsMenu(IMenu menu)
{
MenuInflater.Inflate(Resource.Menu.main, menu);
var item = menu.FindItem(Resource.Id.action_search);
var searchView = MenuItemCompat.GetActionView(item);
_searchView = searchView.JavaCast<SearchView>();
_searchView.QueryTextChange += (s, e) => _adapter.Filter.InvokeFilter(e.NewText);
_searchView.QueryTextSubmit += (s, e) =>
{
// Handle enter/search button on keyboard here
Toast.MakeText(this, "Searched for: " + e.Query, ToastLength.Short).Show();
e.Handled = true;
};
MenuItemCompat.SetOnActionExpandListener(item, new SearchViewExpandListener(_adapter));
return true;
}
This is the SearchViewExpandListener:
private class SearchViewExpandListener
: Java.Lang.Object, MenuItemCompat.IOnActionExpandListener
{
private readonly IFilterable _adapter;
public SearchViewExpandListener(IFilterable adapter)
{
_adapter = adapter;
}
public bool OnMenuItemActionCollapse(IMenuItem item)
{
_adapter.Filter.InvokeFilter("");
return true;
}
public bool OnMenuItemActionExpand(IMenuItem item)
{
return true;
}
}
EDIT:
Ok so the above answer is still relevant, which shows the usage with Support v7. Either way, the new version of Xamarin.Android explicity specifies that, all views and types that you are going to reference in you AXML/XML files, need to use [Register("my.view.Name")]. If you don't do this, when the app is compiled a checksum is used, instead of your namespace as was used previously, for your package name. This means that you will never be able to find the view.
So in your custom AppSearchView class you need to add the RegisterAttributeFlags like:
[Register("com.abc.AppSearchView)]
public class AppSearchView : SearchView
{
}
Now you should be able to find the ActionView.
More information about the breaking changes of Xamarin.Android 5 can be read on the forums.
Related
I'm trying to change the title of a menu item from outside of the onOptionsItemSelected(MenuItem item) method.
I already do the following;
public boolean onOptionsItemSelected(MenuItem item) {
try {
switch(item.getItemId()) {
case R.id.bedSwitch:
if(item.getTitle().equals("Set to 'In bed'")) {
item.setTitle("Set to 'Out of bed'");
inBed = false;
} else {
item.setTitle("Set to 'In bed'");
inBed = true;
}
break;
}
} catch(Exception e) {
Log.i("Sleep Recorder", e.toString());
}
return true;
}
however I'd like to be able to modify the title of a particular menu item outside of this method.
I would suggest keeping a reference within the activity to the Menu object you receive in onCreateOptionsMenu and then using that to retrieve the MenuItem that requires the change as and when you need it. For example, you could do something along the lines of the following:
public class YourActivity extends Activity {
private Menu menu;
private String inBedMenuTitle = "Set to 'In bed'";
private String outOfBedMenuTitle = "Set to 'Out of bed'";
private boolean inBed = false;
#Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
// Create your menu...
this.menu = menu;
return true;
}
private void updateMenuTitles() {
MenuItem bedMenuItem = menu.findItem(R.id.bedSwitch);
if (inBed) {
bedMenuItem.setTitle(outOfBedMenuTitle);
} else {
bedMenuItem.setTitle(inBedMenuTitle);
}
}
}
Alternatively, you can override onPrepareOptionsMenu to update the menu items each time the menu is displayed.
As JxDarkAngel suggested, calling this from anywhere in your Activity,
invalidateOptionsMenu();
and then overriding:
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
MenuItem item = menu.findItem(R.id.bedSwitch);
if (item.getTitle().equals("Set to 'In bed'")) {
item.setTitle("Set to 'Out of bed'");
inBed = false;
} else {
item.setTitle("Set to 'In bed'");
inBed = true;
}
return super.onPrepareOptionsMenu(menu);
}
is a much better choice. I used the answer from https://stackoverflow.com/a/17496503/568197
you can do this create a global "Menu" object then assign it in onCreateOptionMenu
public class ExampleActivity extends AppCompatActivity
Menu menu;
then assign here
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu, menu);
this.menu = menu;
return true;
}
Then later use assigned Menu object to get required items
menu.findItem(R.id.bedSwitch).setTitle("Your Text");
Create a setOptionsTitle() method and set a field in your class. Such as:
String bedStatus = "Set to 'Out of Bed'";
...
public void setOptionsTitle(String status)
{
bedStatus = status;
}
Now when the menu gets populated, change the title to whatever your status is:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
menu.add(bedStatus);
// Return true so that the menu gets displayed.
return true;
}
You better use the override onPrepareOptionsMenu
menu.Clear ();
if (TabActual == TabSelec.Anuncio)
{
menu.Add(10, 11, 0, "Crear anuncio");
menu.Add(10, 12, 1, "Modificar anuncio");
menu.Add(10, 13, 2, "Eliminar anuncio");
menu.Add(10, 14, 3, "Actualizar");
}
if (TabActual == TabSelec.Fotos)
{
menu.Add(20, 21, 0, "Subir foto");
menu.Add(20, 22, 1, "Actualizar");
}
if (TabActual == TabSelec.Comentarios)
{
menu.Add(30, 31, 0, "Actualizar");
}
Here an example
I use this code to costum my bottom navigation item
BottomNavigationView navigation = this.findViewById(R.id.my_bottom_navigation);
Menu menu = navigation.getMenu();
menu.findItem(R.id.nav_wall_see).setTitle("Hello");
Declare your menu field.
private Menu menu;
Following is onCreateOptionsMenu() method
public boolean onCreateOptionsMenu(Menu menu) {
this.menu = menu;
try {
getMenuInflater().inflate(R.menu.menu_main,menu);
} catch (Exception e) {
e.printStackTrace();
Log.i(TAG, "onCreateOptionsMenu: error: "+e.getMessage());
}
return super.onCreateOptionsMenu(menu);
}
Following will be your name setter activity. Either through a button click or through conditional code
public void setMenuName(){
menu.findItem(R.id.menuItemId).setTitle(/*Set your desired menu title here*/);
}
This worked for me.
You can do it like this, and no need to dedicate variable:
Toolbar toolbar = findViewById(R.id.toolbar);
Menu menu = toolbar.getMenu();
MenuItem menuItem = menu.findItem(R.id.some_action);
menuItem.setTitle("New title");
Or a little simplified:
MenuItem menuItem = ((Toolbar)findViewById(R.id.toolbar)).getMenu().findItem(R.id.some_action);
menuItem.setTitle("New title");
It works only - after the menu created.
You can Change Menu Item text using below Code: -
fun showPopup(v: View) {
popup = PopupMenu(context, v)
val inflater = popup?.menuInflater
popup?.setOnMenuItemClickListener(this)
inflater?.inflate(R.menu.menu_main, popup?.menu)
val menu: Menu = popup!!.menu
val item = menu.findItem(R.id.name)
if (item.title.equals("Name")) {
item.title = "Safal Bhatia"
}
}
It seems to me that you want to change the contents of menu inside a local method, and this method is called at any time, whenever an event is occurred, or in the activity UI thread.
Why don't you take the instance of Menu in the global variable in onPrepareOptionsMenu when this is overridden and use in this method of yours. Be sure that this method is called whenever an event is occurred (like button click), or in the activity UI thread, handler or async-task post-execute.
You should know in advance the index of this menu item you want to change. After clearing the menu, you need to inflate the menu XML and update your item's name or icon.
For people that need the title set statically.
This can be done in the AndroidManifest.xml
<activity
android:name=".ActivityName"
android:label="Title Text" >
</activity>
I needed to change the menu icon for the fragment. I altered Charles’s answer to this question a bit for the fragment:
private Menu top_menu;
//...
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
setHasOptionsMenu(true);
//...
rootview = inflater.inflate(R.layout.first_content,null);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.fragment_menu, menu);
this.top_menu = menu;
}
// my procedure
private void updateIconMenu() {
if(top_menu!= null) {
MenuItem nav_undo = top_menu.findItem(R.id.action_undo);
nav_undo.setIcon( R.drawable.back);
}
}
I hit this problem too. In my case I wanted to set the string to
reflect additional information using getString.
As stated above you need to find the correct menuItem in the menu and set it in the onPrepareOptionsMenu method. The solutions above didn't handle the case where the item was in a sub menu and for this you need to search the submenu for the item. I wrote a little Kotlin recursive function to allow me to this for multiple items. Code below...
override fun onPrepareOptionsMenu(menu: Menu) {
...
menu.menuSetText(R.id.add_new_card,
getString(R.string.add_card, currentDeck.deckName))
...
}
private fun Menu.getMenuItem(idx: Int, itemId: Int): MenuItem? {
Log.d(TAG, "getMenuItem: $idx of ${this.size()}")
if (idx >= size()) return null
val item = getItem(idx)
if (item.hasSubMenu()) {
val mi = item.subMenu.getMenuItem(0, itemId)
// mi non-null means we found item.
if (mi != null)
return mi
}
if (item != null && item.itemId == itemId)
return item
return getMenuItem(idx + 1, itemId)
}
fun Menu.menuSetText(itemId: Int, title: String) {
val menuItem = getMenuItem(0, itemId)
if (menuItem != null)
menuItem.title = title
else
Log.e(TAG,
"menuSetText to \"$title\": Failed to find ${
"itemId:0x%08x".format(itemId)}"
)
}
I have implemented BottomNavigationView and have no idea how to set selection index or MenuItem id (in my case, middle item should be selected by default).
I'm afraid there's no such possibility for now as far as it's too raw yet, but anyways any help will be appreciated. Thanks!
Set the selected menu item ID using setSelectedItemId:
bottomNavigationView.setSelectedItemId(R.id.item_id);
This method started being available from Android Support Library 25.3.0.
The only solution that worked for me is:
View view = bottomNavigationView.findViewById(R.id.menu_action_dashboard);
view.performClick();
Simply performing click does the trick. Hope we'll get extra methods/properties in future releases.
UPD:
As user5968678 mentioned, a new method was added since Android Support Library v25.3.0:
bottomNavigationView.setSelectedItemId(R.id.item_id);
so use this instead :)
I think this solution my be slightly more elegant than accepted answer:
bottomNavigationView.getMenu().getItem(menuItemIndex).setChecked(true)
where menuItemIndex is index of the selected element.
Here's what the documentation says about it:
Menu items can also be used for programmatically selecting which destination is currently active. It can be done using MenuItem#setChecked(true)
As an alternative to what Jan posted, you can also find the item by id:
Menu menu = findViewById(R.id.navigation).getMenu();
menu.findItem(R.id.navigation_home).setChecked(true);
Also, in general, I can recommend calling .callOnClick() instead of .performClick().
If you're using listener, like default implementation in android studio, try this:
BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
Integer indexItem = 4;
navigation.getMenu().getItem(indexItem).setChecked(true);
mOnNavigationItemSelectedListener.onNavigationItemSelected(navigation.getMenu().getItem(indexItem));
I believe the question in this context is being viewed in different contexts basing on answers here.
According to assessment, whats required is ability to focus on specific BottomNavigationView item (definitely in new class holding different fragments).
Now, you could have BottomNavigationView OR Buttons or Anything clickable to launch new activity on intent : -
i.e
Intent intent = new Intent(getActivity(), New_Activity.class);
intent.putExtra("EXTRA_PAGE, 1);
startActivityForResult(intent, 30);
Then
-in our New_Activity, we receive the intent-
Intent intent = getIntent();
int page = intent.getExtras().getInt("EXTRA_PAGE);
We then loop over the page variable to find the number/Index for which the current BottomNavigationView is reflecting , THEN we set our focus menu item (assuming your BottomNavigationView has Menu Item for its display)
if(page == 1) {
currentselect = new Pending();
bottomNavigationView.getMenu().getItem(0).setChecked(true);
}
This answers the question above. The rest of Fragment switch is handled well by number of posts above by invoking :
bottomNavigationView.setOnNavigationItemSelectedListener(navListener);
Then something like :
private BottomNavigationView.OnNavigationItemSelectedListener navListener =
new BottomNavigationView.OnNavigationItemSelectedListener(){
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment selectedFrag = null;
switch (item.getItemId()) {
case R.id.pending:
selectedFrag = new Pending();
break;
case R.id.onTransmit:
selectedFrag = new inTransmit();
break;
case R.id.complete:
selectedFrag = new Complete();
break;
}
getSupportFragmentManager().beginTransaction().replace(R.id.select_field, selectedFrag).commit();
return true;
}
};
NOTE:
Using BottomNavigationView and ContentFrameLayout is soo economical and will slash down your code to over 50 % unlike using likes of ViewPager and Tablayout
Kotlin Code for initial selected item in bottomnavigation.BottomNavigationView :
bottom_navigation_view.selectedItemId = R.id.navigation_item_messages
Stop using Reflection! It is bad!
Well, while the support library does not gives us the option to select the item from the BottomNavigationView to be displayed on the first time when it is visible, we have two possibilities:
First, using loop:
private void setupBottomNavigationView() {
// Get the menu from our navigationBottomView.
Menu bottomNavigationViewMenu = bottomNavigationView.getMenu();
// Uncheck the first menu item (the default item which is always checked by the support library is at position 0).
bottomNavigationMenu.findItem(R.id.action_one).setChecked(false);
// Check the wished first menu item to be shown to the user.
bottomNavigationMenu.findItem(R.id.action_two).setChecked(true);
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Menu bottomNavigationMenu = bottomNavigationView.getMenu();
for (int i = 0; i < bottomNavigationMenu.size(); i++) {
if (item.getItemId() != bottomNavigationMenu.getItem(i).getItemId()) {
bottomNavigationMenu.getItem(i).setChecked(false);
}
}
switch (item.getItemId()) {
case R.id.action_one :
replaceFragment(new OneFragment());
break;
case R.id.action_two :
replaceFragment(new TwoFragment());
break;
case R.id.action_three :
replaceFragment(new ThreeFragment());
break;
}
return false;
}
});
}
Second, without loop but with a class variable (because the logic is done from within inner class) :
private void setupBottomNavigationView() {
// Get the menu from our navigationBottomView.
Menu bottomNavigationViewMenu = bottomNavigationView.getMenu();
// Uncheck the first menu item (the default item which is always checked by the support library is at position 0).
bottomNavigationViewMenu.findItem(R.id.action_one).setChecked(false);
// Check the wished first menu item to be shown to the user. Also store that menu item on a variable to control when a menu item must be unchecked.
mActiveBottomNavigationViewMenuItem = bottomNavigationViewMenu.findItem(R.id.action_two).setChecked(true);
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem selectedMenuItem) {
switch (selectedMenuItem.getItemId()) {
case R.id.action_one :
replaceFragment(new OneFragment());
break;
case R.id.action_two :
replaceFragment(new TwoFragment());
break;
case R.id.action_three :
replaceFragment(new ThreeFragment());
break;
}
if (selectedMenuItem != mActiveBottomNavigationViewMenuItem){
mActiveBottomNavigationViewMenuItem.setChecked(false);
mActiveBottomNavigationViewMenuItem = selectedMenuItem;
}
return false;
}
});
}
private MenuItem mActiveBottomNavigationViewMenuItem;
When the setupBottomNavigationView() method is executed? In Activity onCreate() method, take a look:
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// ...
setupBottomNavigationView();
}
Simple and without extensive code.
Hope it helps!
Implement BottomNavigationView.OnNavigationItemSelectedListener and set the selectedItemId at initialisation.
this.bottomNavigationView.setOnNavigationItemSelectedListener {
val targetFragment = when (menuItem.itemId) {
R.id.action_home -> {
HomeFragment()
}
R.id.action_post -> {
PostFragment()
}
R.id.action_settings -> {
SettingsFragment()
}
else -> null
}
targetFragment?.let {
this.activity?.supportFragmentManager?.transaction {
replace(R.id.containerLayout, it, it.javaClass.simpleName)
}
}
true
}
this.bottomNavigationView.selectedItemId = R.id.action_home
You can achieve this effect by adding a dummy menu item
as the first item in the menu you assign to BottomNavigationView
and setting this item to be invisible. Then in
your reselect handler, call setSelectedItem(dummy) to the dummy
item. As a result, the visible menu items will behave as
"virtual" toggles. Took me more work than it should have to
figure this one out. You will have to do it like this in order
that the setSelectItem be called after the reselect is complete:
#Override
public void onNavigationItemReselected(#NonNull MenuItem item) {
anyView.post(new Runnable() {
#Override
public void run() {
navigationView.setSelectedItemId(R.id.action_dummy);
}
}
});
You can extend BottomNavigationView and use reflection to invoke private methods.
public class SelectableBottomNavigationView extends BottomNavigationView {
public SelectableBottomNavigationView(Context context) {
super(context);
}
public SelectableBottomNavigationView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SelectableBottomNavigationView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void setSelected(int index) {
try {
BottomNavigationMenuView menuView = (BottomNavigationMenuView) getField(BottomNavigationView.class, "mMenuView");
OnNavigationItemSelectedListener listener = (OnNavigationItemSelectedListener) getField(BottomNavigationView.class, "mListener");
try {
Method method = menuView.getClass().getDeclaredMethod("activateNewButton", Integer.TYPE);
method.setAccessible(true);
// activate item.
method.invoke(menuView, index);
if (listener != null) {
// trigger item select event.
listener.onNavigationItemSelected(getMenu().getItem(index));
}
} catch (SecurityException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
private Object getField(Class clazz, String fieldName) throws NoSuchFieldException, IllegalAccessException {
Field f = clazz.getDeclaredField(fieldName);
f.setAccessible(true);
return f.get(this);
}
}
To set initial page in navigation - Jetpack Navigation
set property "startDestination" inside in the navigation graph, value should be the id given to the fragment.
<navigation
app:startDestination="#+id/navigation_movies"
...
>
<!-- default page -->
<fragment
android:id="#+id/navigation_movies"
...`enter code here`
/>
<fragment
android:id="#+id/navigation_tv_shows"
...
/>
</fragment>
I'm using SearchView (android.support.v7.widget.SearchView) to filter items in my listview. I have a listview which includes items with a checkbox (the checkbox is a marker to select the item). When i click the checkbox, i call invalidateOptionsMenu(). Then there appears a new menu item which can do some things with the "selected" items. Here some Code:
SearchView in menu.xml:
<item
android:id="#+id/search_movie_icon"
android:icon="#drawable/ic_search_white_24dp"
android:title="#string/search_title"
hmkcode:actionViewClass="android.support.v7.widget.SearchView"
hmkcode:showAsAction="always|collapseActionView"/>
Fragment:
#Override
public void onCreateOptionsMenu(Menu p_Menu, MenuInflater p_Inflater) {
p_Menu.clear();
p_Inflater.inflate(R.menu.movie_actionbar, p_Menu);
m_SearchView = (SearchView) MenuItemCompat.getActionView(p_Menu.findItem(R.id.search_movie_icon));
m_SearchView.setIconified(false);
m_OnQueryTextListener = new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextChange(String p_NewText) {
m_MovieManager.setFilter(p_NewText);
// this call will get the new movie list from the moviemanager and update the view
updateViews();
return false;
}
#Override
public boolean onQueryTextSubmit(String p_Submit) {
// do nothing -> this will be called on pressing enter
return false;
}
};
m_SearchView.setOnQueryTextListener(m_OnQueryTextListener);
//some more unimportant stuff
}
Checkbox in listadapter:
l_ViewHolder.m_cbMarked.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View p_View) {
l_Movie.setMarked(((CheckBox) p_View).isChecked());
// This should update the optionsmenu to see the new menu item
((Activity) m_Context).invalidateOptionsMenu();
}
}
My problem is that the call invalidateOptionsMenu() removes the string in my searchview.
I know that there were some changes in SearchView:
Before:
#Override
public void onActionViewCollapsed() {
clearFocus();
updateViewsVisibility(true);
mQueryTextView.setImeOptions(mCollapsedImeOptions);
mExpandedInActionView = false;
}
Now:
#Override
public void onActionViewCollapsed() {
setQuery("", false);
clearFocus();
updateViewsVisibility(true);
mQueryTextView.setImeOptions(mCollapsedImeOptions);
mExpandedInActionView = false;
}
I tried some workarounds:
StateFulSearchView from SearchView in ActionBar -- problems with the *Up* button
Here i have some focus and icon problems...
A callback which removes my OnChangeTextListener before calling invalidateOptionsMenu() and readd it after this call (to avoid the filter actions) -> it didn't work...
Safe the filter before calling invalidateOptionsMenu() and set the old filter after that call -> then i can clearly see the flicker effect in my listview :(
I can't find a good solution...
Can someone help me? Let me know if you have questions.
I have five action menu items in the action bar, which I'm using action bar sherlock library as follows :
In onCreateOptionsMenu(), i used the following code :
menu.add(0,1,0 "Settings")
.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
menu.add(0,2,0 "Favorites")
.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
menu.add(0,3,0 "List")
.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
menu.add(0,4,0 "Upload")
.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
menu.add(0,5,0 "Search")
.setActionView(R.layout.search_layout)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
Now my Problem is Search Edit text (which is in red color) appears like this:
I want to make it to a full view in the action bar, like this :
This question is a bit old but I'll try to answer it anyway. I hope someone will find it useful.
Here is what I have done:
Create a custom SearchView class that extends SearchView. It defines 2 events: one fired when the search view expands and the other when it collapses.
public class EnglishVerbSearchView extends SearchView {
OnSearchViewCollapsedEventListener mSearchViewCollapsedEventListener;
OnSearchViewExpandedEventListener mOnSearchViewExpandedEventListener;
public EnglishVerbSearchView(Context context) {
super(context);
}
#Override
public void onActionViewCollapsed() {
if (mSearchViewCollapsedEventListener != null)
mSearchViewCollapsedEventListener.onSearchViewCollapsed();
super.onActionViewCollapsed();
}
#Override
public void onActionViewExpanded() {
if (mOnSearchViewExpandedEventListener != null)
mOnSearchViewExpandedEventListener.onSearchViewExpanded();
super.onActionViewExpanded();
}
public interface OnSearchViewCollapsedEventListener {
public void onSearchViewCollapsed();
}
public interface OnSearchViewExpandedEventListener {
public void onSearchViewExpanded();
}
public void setOnSearchViewCollapsedEventListener(OnSearchViewCollapsedEventListener eventListener) {
mSearchViewCollapsedEventListener = eventListener;
}
public void setOnSearchViewExpandedEventListener(OnSearchViewExpandedEventListener eventListener) {
mOnSearchViewExpandedEventListener = eventListener;
}
}
In my activity, I did the following:
- Created a private field to store the reference to the menu.
- Defined the events for collapsing and expanding the search view where I hide and show other actions by using the reference to the menu.
public class DictionaryActivity extends ActionBarActivity {
private Menu mMenu;
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.dictionary, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
EnglishVerbSearchView searchView = (EnglishVerbSearchView) MenuItemCompat.getActionView(searchItem);
searchView.setOnSearchViewCollapsedEventListener(listenerCollapse);
searchView.setOnSearchViewExpandedEventListener(listenerExpand);
mMenu = menu;
return super.onCreateOptionsMenu(menu);
}
final private OnSearchViewCollapsedEventListener listenerCollapse = new OnSearchViewCollapsedEventListener() {
#Override
public void onSearchViewCollapsed() {
// show other actions
MenuItem favouriteItem = mMenu.findItem(R.id.action_favourite);
MenuItem playItem = mMenu.findItem(R.id.action_play);
favouriteItem.setVisible(true);
playItem.setVisible(true);
// I'm doing my actual search here
}
};
final private OnSearchViewExpandedEventListener listenerExpand = new OnSearchViewExpandedEventListener() {
#Override
public void onSearchViewExpanded() {
// hide other actions
MenuItem favouriteItem = mMenu.findItem(R.id.action_favourite);
MenuItem playItem = mMenu.findItem(R.id.action_play);
favouriteItem.setVisible(false);
playItem.setVisible(false);
}
};
}
In the menu.xml file, I used the custom search view:
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:yourapp="http://schemas.android.com/apk/res-auto" >
<item android:id="#+id/action_search"
android:title="#string/action_search"
android:icon="#drawable/action_search"
yourapp:showAsAction="always|collapseActionView"
yourapp:actionViewClass="com.xxx.EnglishVerbSearchView" />
</menu>
I hope it's all that's needed as it's just an extract from my full code of the activity. Let me know if there's anything missing.
As per comment from arne.jans:
It seems to be enough to do MenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); to make room for the SearchView. The advantage would be: the other menu-items go into the overflow menu and are still accessible, even with the opened SearchView.
I plan to use quick actions UI pattern in my application. Android Quick Actions UI Pattern . The quick action window needs a pivot view to stick to.
quickAction.show(View pivotView);
I intend to use quick action for the menu Item, I can get access to the item that is clicked.
But the problem is i need to reference a view from the menu item so that i can pass it to the quick action.
How can i get reference to a view in the menuItem that is selected.
You can achieve this by providing your menu item with an actionViewClass property in xml and then you will be able to get the pivot view u wanted. The code would be something like this
<item
android:id="#+id/menu_find"
android:showAsAction="ifRoom"
android:actionViewClass="android.widget.ImageButton"
/>
In your OnCreateOptionsMenu do this
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.menu_search, menu);
locButton = (ImageButton) menu.findItem(R.id.menu_find).getActionView();
locButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
createPopup();
mQuickAction.show(v);
}
});
return true;
}
Old question, but I ran into some issues with the actionViewClass attribute. For anyone who runs into this later...
Calling findViewById(R.id.mnu_item) in onOptionsItemSelected will return a View anchor.
QuickActions on the MenuItems aren't good design, but I found that they are the simplest way to implement submenus with custom backgrounds.
Inorder to get reference Views of menu items we need to do this,
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.section, menu);
new Handler().post(new Runnable() {
#Override
public void run() {
final View menuItemView = findViewById(R.id.action_preview);
// SOME OF YOUR TASK AFTER GETTING VIEW REFERENCE
}
});
return true;
}
An update for anyone that want to find the menu view item for other reasons (like I wanted).
If you have access to and use AppCompat's Toolbar there is a way. It's not the most efficient way, but it's the easiest way I've found to access the menu item's view.
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
Toolbar toolbar = (Toolbar) view.findViewById(R.id.toolbar);
// Find Menu
for (int toolbarChildIndex = 0; toolbarChildIndex < toolbar.getChildCount(); toolbarChildIndex++) {
View view = toolbar.getChildAt(toolbarChildIndex);
// Found Menu
if (view instanceof ActionMenuView) {
ActionMenuView menuView = (ActionMenuView) view;
// All menu items
for (int menuChildIndex = 0; menuChildIndex < menuView.getChildCount(); menuChildIndex++) {
ActionMenuItemView itemView = (ActionMenuItemView) menuView.getChildAt(menuChildIndex);
// Do something to itemView...
}
}
}
}
Universal code which also works on Android 10
/**
* pass toolbar and menu item id, i.e. R.id.menu_refresh
*/
#Nullable
#Throws(
IllegalAccessException::class,
NoSuchFieldException::class
)
fun getMenuItemView(toolbar: Toolbar?, #IdRes menuItemId: Int): View? {
val mMenuView: Field = Toolbar::class.java.getDeclaredField("mMenuView")
mMenuView.setAccessible(true)
val menuView: Any? = mMenuView.get(toolbar)
(menuView as ViewGroup).children.forEach {
if(it.id == menuItemId) {
return it
}
}
return null
}
in the main activity class, best to override the onOptionsItemSelected(...) method; should be something as below:
public boolean onOptionsItemSelected(MenuItem item) {
// the id is of type int
int someId = item.getItemId();
// can use an if() or switch() statement to check if id is selected
//a Toast message can be used to show item is selected
}
Kotlin!!
override fun onCreateOptionsMenu(Menu menu): Boolean {
/*Adding menu items to action bar*/
menuInflater.inflate(R.menu.main, menu)
/*Getting menu item*/
val locButton: MenuItem = menu.findItem(R.id.menu_find)
/*Creating click listener*/
locButton.setOnMenuItemClickListener{
/*TODO: Handle it*/
true
}
return true;
}