getActionProvider: item does not implement SupportMenuItem - android

I am trying to implement a ShareActionProvider using the support library in a contextual action bar in my fragment. I face no issues implementing it in a normal action bar( onCreateOptionsMenu() ), but when i try it in the CAB ( onCreateActionMode() in MultiModeListener interface), I get the error :
getActionProvider: item does not implement SupportMenuItem; returning null
Looking at the Android source at https://cells-source.cs.columbia.edu/plugins/gitiles/platform/frameworks/support/+/30837f1095c803f332f4a1c3f0917c8afdd50156/v4/java/android/support/v4/view/MenuItemCompat.java, the problem seems to be because my MenuItem is not an instance of SupportMenuItem :
public static ActionProvider getActionProvider(MenuItem item) {
if (item instanceof SupportMenuItem) {
return ((SupportMenuItem) item).getSupportActionProvider();
}
// TODO Wrap the framework ActionProvider and return it
Log.w(TAG, "getActionProvider: item does not implement SupportMenuItem; returning null");
return null;
}
Any ideas on how i can go about resolving this ?
Manifest :
<activity
android:name=".myactivity_ActionBarActivity"
android:theme="#style/Theme.AppCompat.Light"
android:windowSoftInputMode="stateUnchanged">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
Activity :
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
public class myactivity_ActionBarActivity extends ActionBarActivity{
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.actionbaractivity_layout); //loads a fragment
}
}
fragment :
import android.support.v7.widget.ShareActionProvider;
import android.support.v4.view.MenuItemCompat;
import android.view.MenuItem;
import android.view.Menu;
import android.support.v4.app.Fragment;
...
...
#Override
public void onActivityCreated(Bundle savedInstanceState) {
...
...
//Handle Action mode events
myListView.setMultiChoiceModeListener(new MultiChoiceModeListener() {
private ShareActionProvider mShareActonProvider;
....
....
#Override
public boolean onCreateActionMode(ActionMode mode,
Menu menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.chatsession_contextmenu, menu);
//get the ShareActionProvider from the menu item
MenuItem item = menu.findItem(R.id.share_menu);
mShareActonProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(item);
return true;
}
}
...
...
}
Menu layout file :
<?xml version="1.0" encoding="utf-8" ?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:myapp="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/delete_menu"
android:title="Delete message"
myapp:showAsAction="ifRoom|withText"
android:icon="#drawable/ic_action_discard">
</item>
<item
android:id="#+id/share_menu"
android:title="Share message"
myapp:showAsAction="ifRoom|withText"
android:icon="#drawable/ic_action_share"
myapp:actionProviderClass="android.support.v7.widget.ShareActionProvider">
</item>
</menu>
Edit 1 :
The root of the problem seems to be the difference in the Menu object that is being passed as argument to onCreateActionMode(ActionMode mode, Menu menu) and onCreateOptionsMenu(Menu menu, MenuInflater inflater). Only the one in onCreateOptionsMenu has the MenuWrapperICS. Here is a screenshot of both objects in debug mode :
onCreateActionMode(ActionMode mode, Menu menu) :
onCreateOptionsMenu(Menu menu, MenuInflater inflater) :

The problem is that the MultipleModeListener interface extends the android.view.ActionMode.Callback, as can be seen in the source code at http://androidxref.com/4.4.2_r2/xref/frameworks/base/core/java/android/widget/AbsListView.java#6301. If you are using ShareActionProvider from the support library, you need the android.support.v7.view.ActionMode.Callback instead.
The solution is to create your own ActionMode.CallBack implementation instead of using the framework's MultipleModeListener. This way you make sure that the support libraries are being used wherever required.
For example :
Import the v7 version of ActionMode and ActionBarActivity in your fragment
import android.support.v7.view.ActionMode;
import android.support.v7.app.ActionBarActivity;
Create an onClickListener for your list view and use startSupportActionMode to start your custom ActionMode.CallBack implementation
myListView.setItemsCanFocus(false);
myListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
actionMode = null;
myListView.setOnItemClickListener(new OnItemClickListener(){
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id){
if(myListView.getCheckedItemCount() == 0){
actionMode.finish();
return;
}
if(actionMode == null){
actionMode = ((ActionBarActivity)getActivity()).startSupportActionMode(new ContextualActionBar());
}
}
});
Create your custom ActionMode.Callback implementation
private class ContextualActionBar implements ActionMode.Callback{
private ShareActionProvider mShareActionProvider;
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch(item.getItemId()){
case R.id.share_menu :
mode.finish();
return true;
default :
return false;
}
}
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.chatsession_contextmenu, menu);
//Initialize the ShareActionProvider
MenuItem shareMenuItem = menu.findItem(R.id.share_menu);
mShareActionProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(shareMenuItem);
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("text/plain");
shareIntent.putExtra(Intent.EXTRA_TEXT, "test message");
mShareActionProvider.setShareIntent(shareIntent);
return true;
}
#Override
public void onDestroyActionMode(ActionMode mode) {
//Nullify the actionMode object
//so that the onClickListener can identify whether the ActionMode is ON
actionMode = null;
//Uncheck all checked messages
SparseBooleanArray selectedItems = myListView.getCheckedItemPositions();
for(int i=0;i<selectedItems.size();i++){
myListView.setItemChecked(selectedItems.keyAt(i), false);
}
}
#Override
public boolean onPrepareActionMode(ActionMode arg0, Menu arg1) {
// TODO Auto-generated method stub
return false;
}
}

Be careful to use the right MenuInflater when populating the IMenu in onCreateActionMode. When I use the one from the mode object, as you do in your fragment class, it doesn't create the support version of ShareActionProvider. I switched to using the MenuInflater from the parent AppCompatActivity class and it worked fine.
Given that the mode object is from the support library, one would assume it would use the support inflater, but apparently not.

Are you sure that your activity extends ActionBarActivity?

I had an almost identical setup. The problem in my case was that Proguard was optimizing away the constructor of the ShareActionProvider. There is a bug that they while they do keep the class and methods of ActionProvider classes detected in your XML, they don't keep the constructors or the class name.
If you have a "Cannot instantiate class" warning in your log, then this would apply to you, too.
Here is the Android bug report that helped me.
And the proguard config I added was:
-keepnames public class * extends android.support.v4.view.ActionProvider
-keepclassmembers public class * extends android.support.v4.view.ActionProvider {
<init>(android.content.Context);
}

Related

AndroidAnnotations. button click inside actionLayout of menuItem

In AA+AppCompat, I try to change below code in Activity to AA-style.
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater menuInflater = getMenuInflater();
menuInflater.inflate(R.menu.menu_done, menu);
MenuItem menuItem = menu.findItem(R.id.itemDone);
View menuView = MenuItemCompat.getActionView(menuItem);
mButtonQuestionPost = (Button) menuView.findViewById(R.id.buttonMenuDone);
mButtonQuestionPost.setOnClickListener(this);
return super.onCreateOptionsMenu(menu);
}
First, changed head of Activity as below. The menu was shown as expected.
#EActivity(R.layout.activity_question_post)
#OptionsMenu(R.menu.menu_done)
public class QuestionPostActivity extends FragmentActivity {...
And, try to do button click method as below but nothing fired. I changed #Click with #OptionsItem or changed attributes this and that but no luck.
#Click(R.id.buttonMenuDone)
void buttonMenuDone(){
if (mQuestionPostFragment.validatePost()) {
setSupportProgressBarIndeterminate(true);
mQuestionPostFragment.postQuestion();
}
}
menu.xml is as below. Note that I'm using actionLayout for design purpose.
<item
android:id="#+id/itemDone"
android:title="#string/done"
app:showAsAction="always"
android:menuCategory="system"
app:actionLayout="#layout/item_menu_done"
/>
item_menu_done is as below.
<Button
android:layout_width="48dp"
android:layout_height="?actionBarSize"
android:id="#+id/buttonMenuDone"
android:text="#string/done"
android:textColor="#android:color/white"
android:textSize="14sp"
android:background="?attr/actionBarItemBackground"
/>
The AA-generated file does not have MenuItemCompat.getActionView(menuItem), but hardly to make it with AA. Can someone please help me?
I am afraid you cannot bind a listener with #Click to a menu action view, since Activity.findViewById cannot find that view inside the menu items. What you can do is injecting the menuitem, then, manually bind your listener as you already did.
#EActivity(R.layout.activity_question_post)
#OptionsMenu(R.menu.menu_done)
public class QuestionPostActivity extends FragmentActivity {
#OptionsMenuItem(R.id.menuItemDone)
MenuItem buttonMenuDone;
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// this will be called by the generated subclass after it injected the menu
MenuItemCompat.getActionView(itemDone).findViewById(R.id.buttonMenuDone).setOnClickListener(this);
return true;
}
}
In case someone needs it, nowadays you can use the OptionsItem() annotation like so:
//Even with system items
#OptionsItem(android.R.id.home)
void onHomeItemClicked() {
finish();
}
//Or your custom ones
#OptionsItem(R.id.buttonMenuDone)
void onMenuDoneItemClicked() {
//Do your stuff
}

appcompat v21 throws java.lang.UnsupportedOperationException

After updating my project to use the appcompat library to version 21.0.0 I have a problem with a context menu created with a gridview multichoice modal event. The same code works nice with appcompat v20.
This is the relevant part of the main activity:
public class MainActivity extends android.support.v7.app.ActionBarActivity
implements AbsListView.MultiChoiceModeListener {
...
mGridView.setChoiceMode(AbsListView.CHOICE_MODE_MULTIPLE_MODAL);
mGridView.setMultiChoiceModeListener(this);
#Override
public boolean onCreateActionMode(final ActionMode mode, final Menu menu) {
mode.setTitle("Started");
mode.getMenuInflater().inflate(R.menu.context_menu, menu);
return true;
}
}
and this is the context_menu.xml:
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/menu_item_share"
android:title="Share..."
app:showAsAction="ifRoom"
android:icon="#android:drawable/ic_menu_share"
app:actionProviderClass="android.support.v7.widget.ShareActionProvider" />
</menu>
And this is the stacktrace I'm getting back:
java.lang.UnsupportedOperationException: This is not supported, use MenuItemCompat.setActionProvider()
at android.support.v7.internal.view.menu.MenuItemImpl.setActionProvider(MenuItemImpl.java:628)
at android.support.v7.internal.view.menu.MenuItemWrapperICS.setSupportActionProvider(MenuItemWrapperICS.java:315)
at android.support.v4.view.MenuItemCompat.setActionProvider(MenuItemCompat.java:345)
at android.support.v7.internal.view.SupportMenuInflater$MenuState.setItem(SupportMenuInflater.java:473)
at android.support.v7.internal.view.SupportMenuInflater$MenuState.addSubMenuItem(SupportMenuInflater.java:485)
at android.support.v7.internal.view.SupportMenuInflater.parseMenu(SupportMenuInflater.java:194)
at android.support.v7.internal.view.SupportMenuInflater.inflate(SupportMenuInflater.java:118)
at creativesdk.adobe.com.myapplication.MainActivity.onCreateActionMode(MainActivity.java:71)
at android.widget.AbsListView$MultiChoiceModeWrapper.onCreateActionMode(AbsListView.java:6165)
at android.support.v7.internal.view.SupportActionModeWrapper$CallbackWrapper.onCreateActionMode(SupportActionModeWrapper.java:151)
at android.support.v7.app.ActionBarActivityDelegateBase$ActionModeCallbackWrapper.onCreateActionMode(ActionBarActivityDelegateBase.java:1367)
at android.support.v7.internal.app.WindowDecorActionBar$ActionModeImpl.dispatchOnCreate(WindowDecorActionBar.java:1012)
at android.support.v7.internal.app.WindowDecorActionBar.startActionMode(WindowDecorActionBar.java:510)
at android.support.v7.app.ActionBarActivityDelegateBase.startSupportActionMode(ActionBarActivityDelegateBase.java:576)
at android.support.v7.app.ActionBarActivityDelegateHC.startActionModeForChild(ActionBarActivityDelegateHC.java:62)
at android.support.v7.internal.widget.NativeActionModeAwareLayout.startActionModeForChild(NativeActionModeAwareLayout.java:44)
at android.view.ViewGroup.startActionModeForChild(ViewGroup.java:694)
at android.view.View.startActionMode(View.java:4857)
at android.widget.AbsListView.performLongPress(AbsListView.java:3102)
at android.widget.AbsListView$CheckForLongPress.run(AbsListView.java:3061)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
I'm curious to know if anybody found the same problem and if there's a way around it.
There is indeed an issue on ICS devices when trying to inflate the menu item from the ActionMode with AppCompat v21. It seems the menu items are wrapped 2 times and a wrapped item method gets called instead of the native one, causing this Exception.
Google needs to fix this in a future version of AppCompat.
Anyway, here's a hack I implemented to make it work with the current release:
1) Create an utility class in the package android.support.v7.internal.view.menu (using this package is mandatory to allow accessing package-protected methods without using reflection):
package android.support.v7.internal.view.menu;
import android.view.Menu;
/**
* Hack to allow inflating ActionMode menus on Android 4.0.x with AppCompat v21
*/
public class MenuUnwrapper {
public static Menu unwrap(Menu menu) {
if (menu instanceof MenuWrapperICS) {
return ((MenuWrapperICS) menu).getWrappedObject();
}
return menu;
}
}
2) Inflate your menu like this:
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mode.getMenuInflater().inflate(R.menu.context_menu, MenuUnwrapper.unwrap(menu));
return true;
}
EDIT:
The bug has been fixed in AppCompat v21.0.2 and this hack is no longer necessary.
Update your tools.
Try this. It worked to me.
MenuItem menuItem = menu.findItem(R.id.search);
if (menuItem != null) {
MenuItemCompat.setOnActionExpandListener(menuItem,this);
MenuItemCompat.setActionView(menuItem, mSearchView);
}
Try this
inflater.inflate(R.menu.menu, menu);
// search
MenuItem item = menu.findItem(R.id.settings_search);
MenuItemCompat.setOnActionExpandListener(
item, new MenuItemCompat.OnActionExpandListener() {
#Override
public boolean onMenuItemActionExpand(MenuItem item) {
return true;
}
#Override
public boolean onMenuItemActionCollapse(MenuItem item) {
return true;
}
});
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
Log.d(TAG, "onCreateActionMode");
MenuItem item = menu.findItem(R.id.menu_item_share);
mShareActionProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(item);
MenuItemCompat.setActionProvider(item, mShareActionProvider);
return true;
}

How to add Action bar options menu in Android Fragments

I am trying to have a options menu in Android Fragments. ActionBar options menu are not displaying in my Fragments.
Here is my code and I have both onCreateOptionsMenu() and onOptionSelected() function. My code doesn't shows any error. But options menu are not displaying.
package org.reachout;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import org.general.R;
public class ViewMessageFragment extends Fragment {
/* (non-Javadoc)
* #see android.support.v4.app.Fragment#onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle)
*/
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (container == null) {
// We have different layouts, and in one of them this
// fragment's containing frame doesn't exist. The fragment
// may still be created from its saved state, but there is
// no reason to try to create its view hierarchy because it
// won't be displayed. Note this is not needed -- we could
// just run the code below, where we would create and return
// the view hierarchy; it would just never be used.
return null;
}
return (LinearLayout)inflater.inflate(R.layout.viewmessages_tab_fragment_layout, container, false);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
// TODO Auto-generated method stub
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.askexperts_menu, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// handle item selection
switch (item.getItemId()) {
case R.id.action_settings:
// do s.th.
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}
You need to call setHasOptionsMenu(true) in onCreate().
For backwards compatibility it's better to place this call as late as possible at the end of onCreate() or even later in onActivityCreated() or something like that.
See: https://developer.android.com/reference/android/app/Fragment.html#setHasOptionsMenu(boolean)
I am late for the answer but I think this is another solution which is
not mentioned here so posting.
Step 1: Make a xml of menu which you want to add like I have to add a filter action on my action bar so I have created a xml filter.xml. The main line to notice is android:orderInCategory this will show the action icon at first or last wherever you want to show. One more thing to note down is the value, if the value is less then it will show at first and if value is greater then it will show at last.
filter.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" >
<item
android:id="#+id/action_filter"
android:title="#string/filter"
android:orderInCategory="10"
android:icon="#drawable/filter"
app:showAsAction="ifRoom" />
</menu>
Step 2: In onCreate() method of fragment just put the below line as mentioned, which is responsible for calling back onCreateOptionsMenu(Menu menu, MenuInflater inflater) method just like in an Activity.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
Step 3: Now add the method onCreateOptionsMenu which will be override as:
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.filter, menu); // Use filter.xml from step 1
}
Step 4: Now add onOptionsItemSelected method by which you can implement logic whatever you want to do when you select the added action icon from actionBar:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if(id == R.id.action_filter){
//Do whatever you want to do
return true;
}
return super.onOptionsItemSelected(item);
}
in AndroidManifest.xml set theme holo like this:
<activity
android:name="your Fragment or activity"
android:label="#string/xxxxxx"
android:theme="#android:style/Theme.Holo" >

Actionbarsherlock searchview: setOnQueryTextListener

I'm trying to make a filter in a List using ActionBarSherlock's search view. The code I currently have is the following:
#Override
public boolean onCreateOptionsMenu(final Menu menu) {
getSupportMenuInflater().inflate(R.menu.building_search, menu);
SearchView searchView = new SearchView(getSupportActionBar().getThemedContext());
SearchView.OnQueryTextListener queryTextListener = new SearchView.OnQueryTextListener()
{
public boolean onQueryTextChange(String newText)
{
// this is your adapter that will be filtered
listAdapter.getFilter().filter(newText);
return true;
}
public boolean onQueryTextSubmit(String query)
{
// this is your adapter that will be filtered
listAdapter.getFilter().filter(query);
return true;
}
};
searchView.setOnQueryTextListener(queryTextListener);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.search:
onSearchRequested();
return true;
}
return super.onOptionsItemSelected(item);
}
These are my imports:
import android.os.Bundle;
import android.widget.AbsListView;
import android.widget.ArrayAdapter;
import be.ugent.zeus.hydra.AbstractSherlockActivity;
import be.ugent.zeus.hydra.R;
import be.ugent.zeus.hydra.data.caches.AssociationsCache;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import com.actionbarsherlock.widget.SearchView;
import com.dd.plist.NSArray;
import com.dd.plist.NSDictionary;
import com.dd.plist.NSString;
import com.dd.plist.XMLPropertyListParser;
import com.emilsjolander.components.stickylistheaders.StickyListHeadersListView;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.logging.Level;
import java.util.logging.Logger;
Most of it works: in my actionbar, I get a search icon, which is clickable and expands the searchview. What, however, doesn't work is the actual listener. I've put breakpoints inside both methods, but when I debug, nothing happens. The program doesn't break and nothing gets filtered and I can't figure out why.
Does anyone has any idea?
Thanks in advance.
This is how I implemented my search with ActionBarSherlock:
In the menu.xml under the res/menu folder, I added an icon:
<item android:id="#+id/search"
android:title="#string/search_title"
android:icon="#drawable/ic_search"
android:showAsAction="collapseActionView|ifRoom"
android:actionViewClass="com.actionbarsherlock.widget.SearchView"/>
I then created a class which is responsible for recieving the action search queries and presenting the data:
public class SearchActivity extends SherlockFragmentActivity{
#Override
protected void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "This is the search view activity");
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.search_result_layout);
}
private void handleIntent(Intent intent){
if(Intent.ACTION_SEARCH.equals(intent.getAction())){
searcdhQuery = intent.getStringExtra(SearchManager.QUERY);
//here we shall do e search..
Log.d(TAG, "This is the search query:" + searcdhQuery);
//This is the asynctask query to connect to the database...
String[] value = {searcdhQuery};
SearchQuery searchQuery = new SearchQuery();
searchQuery.execute(value);
}
}
#Override
protected void onNewIntent(Intent intent) {
// TODO Auto-generated method stub
super.onNewIntent(intent);
handleIntent(intent);
}
}
In the manifest, this activity is included with Search and View filters as Shown below:
<activity android:name=".SearchActivity"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
</intent-filter>
<meta-data
android:name="android.app.searchable"
android:resource="#xml/searchable"/>
</activity>
Also in the manifest, don't forget the meta-data in the application showing the default search of the activity, as shown below:
<meta-data android:name="android.app.default_searchable"
android:value=".SearchActivity" />
Finally in the onCreateOptionsMenu, be sure to add the search configuration by associating it with the search service:
//associating the searchable configuration with the search service...
SearchManager searchManager = (SearchManager)getSystemService(Context.SEARCH_SERVICE);
SearchView searchView = (SearchView)menu.findItem(R.id.search).getActionView();
searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
Nothing is required in the onOptionsItemSelected method.
This worked perfectly for me. In case you need more details please find more information from the Search View Demo in the actionBarSherlock and The developers tutorial on the Setting a Search Interface.
I hope this helps.
In case you haven't found an answer,this is how I'm doing it (I am using ActionBarSherlock):
add an entry to the menu declaration
<item android:id="#+id/menu_search"
android:actionViewClass="com.actionbarsherlock.widget.SearchView"
android:icon="#drawable/wfm_menu_search"
android:showAsAction="always|withText|collapseActionView"
android:title="#string/menu_search"/>
In your activity override"onCreateOptionsMenu" to inflate your menu and associate your SearcView :
public boolean onCreateOptionsMenu(final Menu menu) {
getSupportMenuInflater().inflate(R.menu.main_menu, menu);
this.refreshMenuItem = menu.findItem(R.id.menu_refresh);
this.searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
this.searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
// collapse the view ?
menu.findItem(R.id.menu_search).collapseActionView();
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
// search goes here !!
// listAdapter.getFilter().filter(query);
return false;
}
});
That's it, no other activities. Hope you find it useful.
Is that your full code? Right now in the onCreateOptionsMenu you create a SearchView and assign to it a OnQueryTextListener but that is all you do with it. I don't see in your code where you add this SearchView to the inflated menu.
As you say you see the widget on the screen, I'm assuming you have declared the widget in the R.menu.building_search file, in which case you should look for that widget(which doesn't have a listener set on it so no action is performed) and not declare a new one(which will not interact with the user):
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
SearchView searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
(This is from the Search guide on the android developer site, if I'm not mistaken this should work for ActionBarSherlock as well).
As every other answer contained a bit of truth, but didn't answer the question fully, I'll create my own answer.
When this issue was created - half a year ago - ABS did not fully implement the SearchView functionality. As of ABS 4.2.0, this has been implemented.
My full implementation, by following the ABS sample app, can be found here.

How to make search menu item to a full view in the action bar using abs

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.

Categories

Resources