I'm trying to implement the contextual action bar in my app. I'm extending a ListFragment and I have a custom ArrayAdapter and list item xml defined. Clicking on items works fine and the background color changes on the list item. Where I'm running into trouble is when selecting multiple items. The contextual action bar comes up and I can tell I'm actually selecting items when I touch them because I'm having it log which items are selected, but the background highlight color on the list item does not change! It seems like some other people were running into this problem when using the Fragments API as well and they had come up with a sort-of hack to get it to work properly. However, I was wondering if anyone has a definitive answer as to why my list doesn't show selected items.
For good measure, here's my code:
ListView list = getListView();
list.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
list.setSelector(R.drawable.list_selector);
// configure contextual action bar
list.setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
#Override
public void onItemCheckedStateChanged(ActionMode actionMode, int position, long id, boolean b) {
Log.i("debug", "item " + position + " changed state");
}
#Override
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
MenuInflater inflater = actionMode.getMenuInflater();
inflater.inflate(R.menu.context_menu, menu);
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(ActionMode actionMode, MenuItem item) {
switch (item.getItemId()) {
case R.id.delete:
Log.i("debug", "delete stuff");
return true;
default:
return false;
}
}
#Override
public void onDestroyActionMode(ActionMode actionMode) {
}
});
I provide my custom list item view with a background selector.
<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:exitFadeDuration="#android:integer/config_mediumAnimTime">
<item android:state_activated="true" android:drawable="#drawable/number_bg_pressed" />
<item android:drawable="#android:color/transparent" />
I refer to APIdemos View/List/List16 example.
I use android.R.layout.simple_list_item_activated_1 for layout when I set up SimpleCursorAdapter. Custom theme may be a better solution. In my case I have a static method to retrieve the layout depending on android api version.
Related
I've discovered a strange problem while try to implement ListView with multichoice mode. I use CHOICE_MODE_MULTIPLE_MODAL to turn on multichoice mode, and MultiChoiceModeListener to provide action mode menu and handle events. Here is my code:
ListView listView = (ListView) findViewById(R.id.list);
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, R.layout.item,
new String[] {"111", "222", "333", "444", "555"});
listView.setAdapter(adapter);
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
listView.setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
#Override
public void onItemCheckedStateChanged(ActionMode actionMode, int i, long l, boolean b) {
}
#Override
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
MenuInflater inflater = actionMode.getMenuInflater();
inflater.inflate(R.menu.my_menu, menu); // my_menu is just stub empty menu
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
return false;
}
#Override
public void onDestroyActionMode(ActionMode actionMode) {
}
});
It works fine, I can select my list items and action mode appears: screenshot. The problem is that when I rotate my device and then close action mode by pressing back button, sometimes (not every time) the action bar becomes ugly, with strange light background: screenshot
It is reproducing on my device with Android 5.0. The code is quite easy, and I don't think that it is bug in my code. Maybe, it is internal bug in Android system? Did anyone face this problem? Thanks in advance!
You should force the ActionBar to redraw itself. Check my answer here:
https://stackoverflow.com/a/53997778/3185295
How to create custom menu for webview when longpress event occur as shown in image at the top?
public class MainActivity extends Activity {
private String data;
private WebView webview;
private String clipdata = "";
private boolean mark_text;
#SuppressLint("NewApi")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
webview = (WebView) this.findViewById(R.id.webView1);
data = "The entire plan-to-produce process, including enterprise-level planning and scheduling, plant-level operations, manufacturing execution, batch manufacturing, and quality management. Capabilities for Big Data management and process integration support the use of real-time data from the shop floor to maintain batch traceability and genealogy. Embedded quality and compliance controls enable process manufacturers to manage exceptions and address nonconformance through corrective and preventive actions for batches. Leveraging mobile and cloud as well ![enter image description here][2]as on-premise technologies, this level of production control helps increase throughput, set predictable and shorter cycle times, improve asset utilization, and help ensure that inventory targets are met.</body></html>";
webview.loadDataWithBaseURL("", data, "text/html", "UTF-8", "");
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu items for use in the action bar
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle presses on the action bar items
switch (item.getItemId()) {
case R.id.action_search:
Toast.makeText(this, "action_search selected", Toast.LENGTH_SHORT)
.show();
return true;
case R.id.action_settings:
Toast.makeText(this, "action_settings selected", Toast.LENGTH_SHORT)
.show();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}
I have update answer with my code. plz check it and say how how can I disable this default action bar and add my own action bar but at the same time text selection functionality should work.
This is called a Contextual Action Bar, it's an overlay on top of the default action bar.
There is a good tutorial here which describes how to work with it.
To get own action bar to work there while still keeping the selection functionality is going to be tricky to say the least I'm afraid...
To add actions to the action bar, create a new XML file in your project's res/menu/ directory.
main_activity_actions.xml
<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="ifRoom" />
<!-- Settings, should always be in the overflow -->
<item android:id="#+id/action_settings"
android:title="#string/action_settings"
android:showAsAction="never" />
</menu>
Add the Actions to the Action Bar
To place the menu items into the action bar, implement the onCreateOptionsMenu() callback method in your activity to inflate the menu resource into the given Menu object. For example:
#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);
}
Respond to Action Buttons
When the user presses one of the action buttons or another item in the action overflow, the system calls your activity's onOptionsItemSelected() callback method. In your implementation of this method, call getItemId() on the given MenuItem to determine which item was pressed—the returned ID matches the value you declared in the corresponding element's android:id attribute.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle presses on the action bar items
switch (item.getItemId()) {
case R.id.action_search:
Toast.makeText(this,"action_search selected",Toast.LENGTH_SHORT).show();
return true;
case R.id.action_settings:
Toast.makeText(this,"action_settings selected",Toast.LENGTH_SHORT).show();
return true;
default:
return super.on
OptionsItemSelected(item);
}
}
for further guidance refer the official doc
first create your own ActionModeCallBack then you need to create a class and extend WebView and overwrite this method:
public ActionMode startActionMode(ActionMode.Callback callback)
{
actionModeCallback = new CustomizedSelectActionModeCallback();
return super.startActionMode(actionModeCallback);
}
update: look at this
It's work for me...
I have a standard search EditText in my ActionBar, triggered by a touch on a little magnifying glass icon. I can cache the user's search string using the OnQueryTextListener. I want to put that string back into the EditText when the user touches the icon a second time.
I'm using ABS (soon to abandon), targeting 8-19.
How can I do this?
With a normal action bar (you'll have to find the different variation with ABS, not sure if my answer will apply completely with that library).
SearchView is a widget that can be inflated in the options menu, so what I do is inflate a menu using an XML containing an action view:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="#+id/search_user"
android:actionViewClass="android.widget.SearchView"
android:icon="#drawable/magnifing_glass"
android:showAsAction="ifRoom|collapseActionView"
android:title="Search Users"/>
</menu>
Next, when inflating the action view, set your listeners, and use a global variable to save the previous search.
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.search_menu, menu);
MenuItem search = menu.findItem(R.id.search_user);
//Keep a global variable of this so you can set it within the next listener
SearchView user_search = (SearchView) search.getActionView();
user_search.setOnQueryTextListener(new OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
global_variable = query;
return true;
}
#Override
public boolean onQueryTextChange(String text) {
return true;
}
});
Finally, in a second listener, set the text of the global variable to your previous query when the action view expands.
//This is set on the menu item
search.setOnActionExpandListener(new OnActionExpandListener() {
#Override
public boolean onMenuItemActionCollapse(MenuItem item) {
// Do something when collapsed
return true; // Return true to collapse action view
}
#Override
public boolean onMenuItemActionExpand(MenuItem item) {
user_search.setQuery(global_variable, false);
return true; // Return true to expand action view
}
});
I'm creating a universal app compatible with Froyo upwards, so I'm using the brilliant ActionBarSherlock. I wish to create submenu pulldowns from Action Items in the ActionBar that includes icons and text in the rows. There are a few threads that ask similar questions but I got no where with trying to implement them. I've tried Spinners but I need API 8 compatibility, so then I tried IcsSpinner in the Sherlock lib but Jake had advised someone else not to rely on it in case the lib changed. I tried a custom ActionProvider to mimic the ShareActionProvider but I found it too complicated:
This image shows exactly what I want but I could not get it to work with my app. My code is as follows:
public class AddDocActionProvider extends ActionProvider {
private Context mContext;
public AddDocActionProvider(Context context) {
super(context);
mContext = context;
}
#Override
public View onCreateActionView() {
LayoutInflater layoutInflater = LayoutInflater.from(mContext);
View view = layoutInflater.inflate(
R.layout.actionbar_new_doc_action_provider, null);
return view;
}
#Override
public boolean hasSubMenu() {
return true;
}
#Override
public void onPrepareSubMenu(SubMenu subMenu) {
// loop was here calling
subMenu.add(0, id, 0, "Type 1")
.setIcon(R.drawable.type_1)
.setOnMenuItemClickListener(mOnMenuItemClickListener);
// added type 2, 3, etc
}
#Override
public boolean onPerformDefaultAction() {
// This is called if the host menu item placed in the overflow menu of the
// action bar is clicked and the host activity did not handle the click.
return true;
}
My SherlockFragmentActivity had this code:
#Override
public boolean onCreateOptionsMenu(com.actionbarsherlock.view.Menu menu) {
MenuItem newDoc = menu.add(0, MENU_ADD_DOC, 0, "New Document");
newDoc.setVisible(!isPhoneShowingStorageList);
newDoc.setIcon(R.drawable.dark_content_new);
newDoc.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
mNewDocActionProvider = new AddDocActionProvider(getSupportActionBar().getThemedContext());
newDoc.setActionProvider(mNewDocActionProvider);
}
I don't see the submenu and it also crashes on froyo phones when the actionbar invalidates.
Other threads I've looked at:
How to create a custom Pulldown in the Honeycomb ActionBar?
How to add a Dropdown item on the action bar
Custom drop-down from action item (actionbarsherlock)
While this isn't necessarily an ActionBarSherlock specific issue, frankly I can't believe something this easy should be so complicated to implement in the standard Action Bar. Any help would be greatly appreciated.
UPDATE:
Using XML rather than code added the icons for me:
<item
android:id="#+id/menu_new_doc"
android:icon="#drawable/dark_content_new"
android:showAsAction="always"
android:title="New Document">
<menu>
<item
android:id="#+id/word2010"
android:icon="#drawable/doc"
android:title="Word 2010"/>
<item
android:id="#+id/excel2010"
android:icon="#drawable/excel"
android:title="Excel 2010"/>
</menu>
</item>
So in order to dynamically had the submenus, I had to do this:
MenuItem newDoc = menu.findItem(R.id.menu_new_doc);
SubMenu subMenu = newDoc.getSubMenu();
subMenu.clear();
for (/* loop */) {
MenuItem subMenuItem = subMenu.add(0, hash, 0, fileType.GetDescription());
subMenuItem.setIcon(R.drawable.doc);
}
i think you should set the icon to the newly added Item to the subMenu. Example :
public boolean onCreateOptionsMenu(Menu menu) {
SubMenu subMenu = menu.addSubMenu("Add");
subMenu.add("Add Subitem 1").setIcon(R.drawable.ic_action_add1);
subMenu.add("Add Subitem 2").setIcon(R.drawable.ic_action_add2);
MenuItem subMenu1Item = subMenu.getItem();
subMenu1Item.setIcon(R.drawable.ic_action_add);
subMenu1Item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
return super.onCreateOptionsMenu(menu);
}
I can easily do it when I am using onCreateOptionsMenu or onOptionsItemSelected methods.
But I have a button somewhere in screen, and on clicking that button, it should enable/disable context menu items.
Anyway, the documentation covers all the things.
Changing menu items at runtime
Once the activity is created, the
onCreateOptionsMenu() method is called
only once, as described above. The
system keeps and re-uses the Menu you
define in this method until your
activity is destroyed. If you want to
change the Options Menu any time after
it's first created, you must override
the onPrepareOptionsMenu() method.
This passes you the Menu object as it
currently exists. This is useful if
you'd like to remove, add, disable, or
enable menu items depending on the
current state of your application.
E.g.
#Override
public boolean onPrepareOptionsMenu (Menu menu) {
if (isFinalized) {
menu.getItem(1).setEnabled(false);
// You can also use something like:
// menu.findItem(R.id.example_foobar).setEnabled(false);
}
return true;
}
On Android 3.0 and higher, the options menu is considered to always be open when menu items are presented in the action bar. When an event occurs and you want to perform a menu update, you must call invalidateOptionsMenu() to request that the system call onPrepareOptionsMenu().
On all android versions, easiest way: use this to SHOW a menu action icon as disabled AND make it FUNCTION as disabled as well:
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
MenuItem item = menu.findItem(R.id.menu_my_item);
if (myItemShouldBeEnabled) {
item.setEnabled(true);
item.getIcon().setAlpha(255);
} else {
// disabled
item.setEnabled(false);
item.getIcon().setAlpha(130);
}
}
You could save the item as a variable when creating the option menu and then change its properties at will.
private MenuItem securedConnection;
private MenuItem insecuredConnection;
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.connect_menu, menu);
securedConnection = menu.getItem(0);
insecuredConnection = menu.getItem(1);
return true;
}
public void foo(){
securedConnection.setEnabled(true);
}
How to update the current menu in order to enable or disable the items when an AsyncTask is done.
In my use case I needed to disable my menu while my AsyncTask was loading data, then after loading all the data, I needed to enable all the menu again in order to let the user use it.
This prevented the app to let users click on menu items while data was loading.
First, I declare a state variable , if the variable is 0 the menu is shown, if that variable is 1 the menu is hidden.
private mMenuState = 1; //I initialize it on 1 since I need all elements to be hidden when my activity starts loading.
Then in my onCreateOptionsMenu() I check for this variable , if it's 1 I disable all my items, if not, I just show them all
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_galeria_pictos, menu);
if(mMenuState==1){
for (int i = 0; i < menu.size(); i++) {
menu.getItem(i).setVisible(false);
}
}else{
for (int i = 0; i < menu.size(); i++) {
menu.getItem(i).setVisible(true);
}
}
return super.onCreateOptionsMenu(menu);
}
Now, when my Activity starts, onCreateOptionsMenu() will be called just once, and all my items will be gone because I set up the state for them at the start.
Then I create an AsyncTask Where I set that state variable to 0 in my onPostExecute()
This step is very important!
When you call invalidateOptionsMenu(); it will relaunch onCreateOptionsMenu();
So, after setting up my state to 0, I just redraw all the menu but this time with my variable on 0 , that said, all the menu will be shown after all the asynchronous process is done, and then my user can use the menu.
public class LoadMyGroups extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
mMenuState = 1; //you can set here the state of the menu too if you dont want to initialize it at global declaration.
}
#Override
protected Void doInBackground(Void... voids) {
//Background work
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
mMenuState=0; //We change the state and relaunch onCreateOptionsMenu
invalidateOptionsMenu(); //Relaunch onCreateOptionsMenu
}
}
Results
simplify #Vikas version
#Override
public boolean onPrepareOptionsMenu (Menu menu) {
menu.findItem(R.id.example_foobar).setEnabled(isFinalized);
return true;
}
A more modern answer for an old question:
MainActivity.kt
private var myMenuIconEnabled by Delegates.observable(true) { _, old, new ->
if (new != old) invalidateOptionsMenu()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
findViewById<Button>(R.id.my_button).setOnClickListener { myMenuIconEnabled = false }
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.menu_main_activity, menu)
return super.onCreateOptionsMenu(menu)
}
override fun onPrepareOptionsMenu(menu: Menu): Boolean {
menu.findItem(R.id.action_my_action).isEnabled = myMenuIconEnabled
return super.onPrepareOptionsMenu(menu)
}
menu_main_activity.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_my_action"
android:icon="#drawable/ic_my_icon_24dp"
app:iconTint="#drawable/menu_item_icon_selector"
android:title="My title"
app:showAsAction="always" />
</menu>
menu_item_icon_selector.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="?enabledMenuIconColor" android:state_enabled="true" />
<item android:color="?disabledMenuIconColor" />
attrs.xml
<resources>
<attr name="enabledMenuIconColor" format="reference|color"/>
<attr name="disabledMenuIconColor" format="reference|color"/>
</resources>
styles.xml or themes.xml
<style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="disabledMenuIconColor">#color/white_30_alpha</item>
<item name="enabledMenuIconColor">#android:color/white</item>
What I did was save a reference to the Menu at onCreateOptionsMenu. This is similar to nir's answer except instead of saving each individual item, I saved the entire menu.
Declare a Menu Menu toolbarMenu;.
Then in onCreateOptionsMenusave the menu to your variable
#Override
public boolean onCreateOptionsMenu(Menu menu)
{
getMenuInflater().inflate(R.menu.main_menu, menu);
toolbarMenu = menu;
return true;
}
Now you can access your menu and all of its items anytime you want.
toolbarMenu.getItem(0).setEnabled(false);
the best solution
when you are perform on navigation drawer
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
menu.setGroupVisible(0,false);
return true;
}
If visible menu
menu.findItem(R.id.id_name).setVisible(true);
If hide menu
menu.findItem(R.id.id_name).setVisible(false);
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.item_id:
//Your Code....
item.setEnabled(false);
break;
}
return super.onOptionsItemSelected(item);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
// getMenuInflater().inflate(R.menu.home, menu);
return false;
}
Generally can change the properties of your views in runtime:
(Button) item = (Button) findViewById(R.id.idBut);
and then...
item.setVisibility(false)
but
if you want to modify de visibility of the options from the ContextMenu, on press your button, you can activate a flag, and then in onCreateContextMenu you can do something like this:
#Override
public void onCreateContextMenu(ContextMenu menu,
View v,ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
menu.setHeaderTitle(R.string.context_title);
if (flagIsOn()) {
addMenuItem(menu, "Option available", true);
} else {
Toast.makeText(this, "Option not available", 500).show();
}
}
I hope this helps