I am trying to create an Android app with a search button in the Action Bar and when the user presses on the search button, then a search text box appears on the action bar, like in Google's Messenger app (see below).
I tried to implement it as shown below but my app looks like this:
There are a few problems with this. For example, the text reads "Search..." with the elipsis, unlike a simple "Search" without the elipsis, but by far the most concerning thing, is that there is no back button in the toolbar, the search button is pushed too far to the left, and the overflow button on the right has been pushed to the side. In addition, pressing the physical back button on my device does not collapse the searchview, it just exists to app.
Some of the code which I used to try to implement the search bar is below. I tried to set a SearchViewExpandListener as seen below so that the back button would appear when the search view is expanded, however it does not work.
EDIT: I also ran the app with breakpoints on my onMenuItemActionExpand and onMenuItemActionCollapsed methods, and I found out that these methods are in fact never called.
MainActivity.java
import android.content.Context;
import android.support.v4.view.MenuItemCompat;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.SearchView;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayShowHomeEnabled(false);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
// See above
MenuItemCompat.setOnActionExpandListener(searchItem, new SearchViewExpandListener(this));
MenuItemCompat.setActionView(searchItem, searchView);
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String s) {
Toast.makeText(MainActivity.this, "You searched " + s, Toast.LENGTH_SHORT).show();
return false;
}
#Override
public boolean onQueryTextChange(String s) {
return false;
}
});
return true;
}
// See above
private class SearchViewExpandListener implements MenuItemCompat.OnActionExpandListener {
private Context context;
public SearchViewExpandListener (Context c) {
context = c;
}
#Override
public boolean onMenuItemActionExpand(MenuItem item) {
((AppCompatActivity) context).getSupportActionBar().setDisplayShowHomeEnabled(true);
return false;
}
#Override
public boolean onMenuItemActionCollapse(MenuItem item) {
((AppCompatActivity) context).getSupportActionBar().setDisplayShowHomeEnabled(false);
return false;
}
}
}
menu.xml
<?xml version="1.0" encoding="utf-8" ?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/action_search"
android:title="Search"
app:actionViewClass="android.support.v7.widget.SearchView"
app:showAsAction="ifRoom"/>
<item android:id="#+id/action_about"
android:title="About"
app:showAsAction="never"/>
</menu>
It also appears that it is not just me who has this problem. This guide on implementing a SearchView appears to experience similar issues.
So what is the correct way to implement a search bar in an AppCompatActivity which results in a search bar like that in Google's Material Design guidelines and like that in their apps such as Google Messenger? I feel like I've been Googling endlessly for the past while, but I cannot find anything which helps me.
Use collapseActionView flag along with always in showAsAction on serchView menu item
app:showAsAction="always|collapseActionView"
The collapseActionView flag indicates how to display the widget when the user is not interacting with it: If the widget is on the app bar, the app should display the widget as an icon. If the widget is in the overflow menu, the app should display the widget as a menu item. When the user interacts with the action view, it expands to fill the app bar.
Related
I'm getting mad with using SearchView in a fragment and the back button is always shown whatever i touched the search bar or not and i do the search but i have a problem that back button do nothing but clear the text in search i would like to use it to switch also between fragments. I've tried many solutions in stack overflow questions but seems not solving my issue.
the code after adding toolbar in the fragment:
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.search_menu_fragment, menu);
MenuItem searchItem = menu.findItem(R.id.action_search_locations);
SearchView searchView = new SearchView(((AppCompatActivity)getActivity()).getSupportActionBar().getThemedContext());
MenuItemCompat.setShowAsAction(searchItem, searchItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW ); //searchItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW |
MenuItemCompat.setActionView(searchItem, searchView);
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
// filter recycler view when query submitted
locationStatesPreviewAdapter.getFilter().filter(query);
return false;
}
#Override
public boolean onQueryTextChange(String query) {
// filter recycler view when text is changed
Log.e("QueryChange",query);
locationStatesPreviewAdapter.getFilter().filter(query);
return false;
}
});
}
the xml file has only the search item in the menu :
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="#+id/action_search_locations"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:title="#string/app_name"
android:icon="#android:drawable/ic_menu_search"
app:showAsAction="always|collapseActionView"
app:actionViewClass="android.support.v7.widget.SearchView" />
</menu>
Thanks.
That was a problem of mis-understanding, as i thought it's the back button of the SearchView in Fragment and afterwards it was the toolbar Navigation button and after adding this lines to make it responsive and all things done ! thanks for help all.
((AppCompatActivity)getActivity()).setSupportActionBar(toolbar);
((AppCompatActivity)getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);
((AppCompatActivity)getActivity()).getSupportActionBar().setTitle("TOOLBAR");
toolbar.setNavigationOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view) {
Toast.makeText(getActivity(), "Back clicked!", Toast.LENGTH_SHORT).show();
}
});
I'm following official android tutorials from Docant pdf book. For some reason my search icon won't show up. I included ic_action_search.png photos from holo_dark and im using holo light with dark action bar theme.
Here is code, no erros found by eclipse, min sdk is set to 11.
DisplayMessageActivity.java file
package com.example.myfirstapp1;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.TextView;
public class DisplayMessageActivity extends ActionBarActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Get the message from the intent
Intent intent = getIntent();
String message = intent.getStringExtra(MainActivity.EXTRA_MESSAGE);
// Create the text view
TextView textView = new TextView(this);
textView.setTextSize(40);
textView.setText(message);
// Set the text view as the activity layout
setContentView(textView);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu items for use in the action bar
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_activity_actions, menu);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<!-- Search, should appear as action button -->
<item android:id="#+id/action_search"
android:icon="#drawable/ic_action_search"
android:title="#string/action_search"
android:showAsAction="always" />
<!-- Settings, should always be in the overflow -->
<item android:id="#+id/action_settings"
android:title="#string/action_settings"
android:showAsAction="never" />
</menu>
I think your error is in your onCreate method, in this line:
setContentView(textView);
You should set the content view to the xml of your view, and not to a textview.
Your onCreate should look something like this:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(the_name_of_your_xml_for_this_activity);
// Get the message from the intent
Intent intent = getIntent();
String message = intent.getStringExtra(MainActivity.EXTRA_MESSAGE);
// Create the text view
TextView textView = new TextView(this);
textView.setTextSize(40);
textView.setText(message);
}
I would recommend you to use actionbar library http://actionbarsherlock.com/
For better result on any actionbar related action
I think you need to defined it first in res/valuse/drawables.xml
<item name="ic_action_search" type="drawable">#android:drawable/ic_menu_search</item>
check the photo,
If you have a .bng photo you have to import it by another way to drawable than use
android:src="#drawable/ic_action_search"
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.
different android devices will occasionally have different onscreen features (such as the buttons at the bottom of the screen in kindle fire apps). How can you change the behavior of these kind of buttons? I can't find any resources on doing such a thing..
** EDIT **
I found out that what I referred to as the "bottom buttons" is more appropriately called the Options Bar per some Kindle Fire documentation from Amazon
** EDIT **
Considering both answers say that this isn't possible, I decided it's time for an example. It looks like the menu I want to make is actually part of the application, but has a button listener for those system buttons. How do I go about finding example code for using those buttons?
How can you change the behavior of these kind of buttons?
You ask the manufacturer of the device in question how to modify things that they did that lie outside of the Android SDK. The odds are very good that the answer is "you can't".
How can you change the behavior of these kind of buttons?
behavior? You cant change behavior of 3rd party apps buttons that placed at the bottom of kindle fire (Its just OptionsMenu, and called by pressing "Menu" button on other android based devices)
You can disable these buttons - Home, Back and other stuff... (but not on kindle)
Kindle Fire does not support apps that contain disable_keyguard permissions or customize the lockscreen.
https://developer.amazon.com/help/faq.html#KindleFire
here it is: (java)
package com.wali.jackonsoptionsmenu;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
public class JacksonsOptionsMenuActivity extends Activity {
private final static String TAG = JacksonsOptionsMenuActivity.class
.getSimpleName();
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
// this one is called once before showing OptionsMenu
#Override
public boolean onCreateOptionsMenu(Menu menu) {
Log.d(TAG,
"onCreateOptionsMenu: called once, while creating options menu");
getMenuInflater().inflate(R.menu.jackonsmenu, menu); // this one
// inflates your
// xml based
// menu into
// memory and
// sets to menu,
// from
// 'R.menu.jacksonsmenu
// to 'menu'
return true; // if You want to handle bottom bar menu (OptionsMenu) you
// have to return 'true'
}
// this one is called everytime, but before showing the menu
// if You want to change button name, icon or other stuff, do it here
// its something like preparing
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
Log.d(TAG,
"onPrepareOptionsMenu: called everytime before showing the OptionsMenu");
return true;
}
// this one is called everytime, after the OptionsMenu is shown
// this one comes, if everything is ok in Your implementation, otherwise,
// nothing
#Override
public boolean onMenuOpened(int featureId, Menu menu) {
Log.d(TAG, "onMenuĂ–pened: called everytime after the OptionsMenu shown");
return true;
}
// this on is called when an item selected try item.getItemId()
#Override
public boolean onOptionsItemSelected(MenuItem item) {
Log.d(TAG, "onOptionsItemSelected: called when an item selected");
switch (item.getItemId()) {
case R.id.menuRefreshAll:
Log.i(TAG, "onOptionsItemSelected: refreshing everything");
break;
case R.id.menuManageSources:
Log.i(TAG, "onOptionsItemSelected: managing sources");
break;
}
return true;
}
// this on is called everytime after the optionsmenu is disappeared
#Override
public void onOptionsMenuClosed(Menu menu) {
Log.d(TAG,
"onOptionsMenuClosed: called everytime after the OptionsMenu is disappeared");
Log.i(TAG, "Hey Jackson, I'm disappeared");
}
}
xml file
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#+id/itemStatus" android:title="#string/titleStatus"
android:icon="#android:drawable/ic_menu_edit"></item>
<item android:title="#string/titleTimeline" android:id="#+id/itemTimeline"
android:icon="#android:drawable/ic_menu_sort_by_size"></item>
<item android:id="#+id/itemPrefs" android:title="#string/titlePrefs"
android:icon="#android:drawable/ic_menu_preferences"></item>
<item android:icon="#android:drawable/ic_menu_delete"
android:title="#string/titlePurge" android:id="#+id/itemPurge"></item>
<item android:title="#string/titleRefresh" android:id="#+id/itemRefresh"
android:icon="#android:drawable/ic_menu_rotate"></item>
</menu>
there are some tricks:
if You have multiple activities with same OptionsMenu:
1. Create a base activity with OptionsMenu
2. Inherit this base activity on other activies, that handles same OptionsMenu
Result:
same Menu on multiple activities
Regards, Galymzhan Sh
On pressing menu button , I have 2 options : Add & more.
On click of more i have 3 options : Organize ,Export & Exit
On click of Organize i want other 5 options.
On click of more i get my submenu. But i want other 5 options on click of organize.How do i proceed???
My code in parts is as follows :
XML file-------------------------------
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/more"
android:title="#string/moreMenu"
android:icon="#drawable/icon">
<menu>
<item android:id="#+id/Organize"
android:title="#string/Organize" />
<item android:id="#+id/Export"
android:title="#string/Export" />
</menu>
</item>
<item
android:id="#+id/add"
android:title="#string/addMenu"
android:icon="#drawable/add"/>
</menu>
Java-------------------------
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
public class ToDoList extends Activity {
Menu menu;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.todolist);
}
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.layout.categorymenu, menu);
return true;
}
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.more:
Toast.makeText(this, "You pressed more!", Toast.LENGTH_LONG).show();
//(What needs to be done from here)
return true;
case R.id.add:
Toast.makeText(this, "You pressed add!", Toast.LENGTH_LONG).show();
return true;
}
return false;
}
public boolean onPrepareOptionsMenu(Menu menu) {
return true;
}
}
As can be seen in Creating Menus sub menus can not contain sub menus.
You could show a Context menu after clicking on the item in the options menu.
This could show your five more options in a floating view above the screen.
You have to overwrite the onCreateContextMenu to create a ContextMenu and I think you have to call the contextMenu manually in the onOptionsItemSelected method. For resources on how to create the context menu see this paragraph in the article mentioned above.
To open the ContextMenu you can call openContextMenu in your Activity. You may need to register the menuitem before to enable your activity to find the correct context menu.