I am trying to implement the feature that, when I am long clicking a list item, the action mode shall start and it shall be possible to delete one or more items.
I am starting in DocumentsActivity a search, which starts a Fragment DocumentsFragment with a ListView and their items. The ListAdapter is initialized and set via method call setListAdapter(this.documentsAdapter) in onCreate of Fragment. I set various listeners on the listview in the onActivityCreated in the Fragment:
public void onActivityCreated(Bundle savedInstanceState) {
getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
getListView().setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
getListView().setItemChecked(position, true);
return true;
}});
getListView().setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
menu.clear();
((DocumentsActivity)getActivity()).getMenuInflater().inflate(R.menu.documents_context_menu, menu);
return true;
}
});
super.onActivityCreated(savedInstanceState);
}
When long clicking on a listitem the action mode gets started and the menu documents_context_menu appears to be the action bar. But the problem is, the action bar appears above the toolbar and the toolbar won't disappear (see the picture).
I've tried to call getSupportActionBar().hide() or set it to null or even use another style/theme. It all didn't work. Sometimes the blue toolbar was completely white, but that is all.
I have absolutely no idea why the toolbar won't disappear. May you give some advice?
Thanks in advance!
_____ Update 1 _____
This is the styles.xml
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:fitsSystemWindows">true</item>
<item name="colorAccent">#color/darkblue100</item>
<item name="android:actionOverflowButtonStyle">#style/ActionButtonOverflow</item>
<item name="actionOverflowButtonStyle">#style/ActionButtonOverflow</item>
<item name="android:actionMenuTextColor">#color/black</item>
</style>
And this is how the action bar is set in the Activity:
protected void onCreate(Bundle savedInstanceState) {
handleIntent(getIntent());
requestWindowFeature(5);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_documents);
Toolbar mToolbar = (Toolbar) findViewById(R.id.tool_bar);
setSupportActionBar(mToolbar);
args = getIntent().getExtras();
if (findViewById(R.id.container_documents) != null && savedInstanceState == null) {
showDocumentsFragment();
}
}
As pointed out in the link provided in comments you just need to add following line to your AppTheme style:
<item name="windowActionModeOverlay">true</item>
It just indicates that action mode should overlay window content instead of pushing it down,it tells that you don't need any reserved space for action mode.
Well as far as i go through your code and understand it, you have done everything that you provided your Toolbar to act as ActionBar and used .NoActionBar theme except according to Android Developer you should also set the windowActionBar attribute to false in your style. enter link description here Second para clears it out.
I hope it helps!
all of this answers are fine you should try them but what you need is a ContextualMenu so you should first add views to a registerForContextMenu() so menu knows which menus are contextual then implement the onCreateContextMenu of your Activity
#Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.context_menu, menu);
}
then implement onContextItemSelected() like this :
#Override
public boolean onContextItemSelected(MenuItem item) {
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
switch (item.getItemId()) {
case R.id.edit:
editNote(info.id);
return true;
case R.id.delete:
deleteNote(info.id);
return true;
default:
return super.onContextItemSelected(item);
}
}
then you have to perform an action on views and implement AbsListView.MultiChoiceModeListener then call setChoiceMode() with the CHOICE_MODE_MULTIPLE_MODAL argument. like this :
ListView listView = getListView();
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
listView.setMultiChoiceModeListener(new MultiChoiceModeListener() {
#Override
public void onItemCheckedStateChanged(ActionMode mode, int position,
long id, boolean checked) {
// Here you can do something when items are selected/de-selected,
// such as update the title in the CAB
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
// Respond to clicks on the actions in the CAB
switch (item.getItemId()) {
case R.id.menu_delete:
deleteSelectedItems();
mode.finish(); // Action picked, so close the CAB
return true;
default:
return false;
}
}
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
// Inflate the menu for the CAB
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.context, menu);
return true;
}
#Override
public void onDestroyActionMode(ActionMode mode) {
// Here you can make any necessary updates to the activity when
// the CAB is removed. By default, selected items are deselected/unchecked.
}
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
// Here you can perform updates to the CAB due to
// an <code>invalidate()</code> request
return false;
}
});
all of what i said and ultimately more, you can find in this android developer documentation
Add:
//Set action mode null after use
public void setNullToActionMode() {
if (mActionMode != null)
mActionMode = null;
}
Or:
//Remove selected selections
public void removeSelection() {
mSelectedItemsIds = new SparseBooleanArray();
}
Actually the issue were caused by different things.
First, the windowActionBar was set true, also was the attribute fitsSystemWindows.I deleted both lines in styles.xml.
Then there was in the activity layout the attribute layout_marginTop="?actionBarSize" I did not see, following in complete confusion. But this attribute needs to be there so I am handling it in the method onActivityCreated when onCreateActionMode and onDestroyActionMode are called.
After that all I had the automagically problem that the listview items disappeared. I fixed it by commiting my fragment again in onDestroyActionMode.
public void onActivityCreated(Bundle savedInstanceState) {
getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
getListView().setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {...}
});
getListView().setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
LinearLayout ll = ((DocumentsActivity)getActivity()).findViewById(R.id.container_documents);
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
DrawerLayout.LayoutParams params = (DrawerLayout.LayoutParams) ll.getLayoutParams();
params.setMargins(0, 0, 0, 0);
ll.setLayoutParams(params);
((DocumentsActivity)getActivity()).getSupportActionBar().hide();
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.documents_context_menu, menu);
return true;
}
#Override
public void onDestroyActionMode(ActionMode mode) {
DrawerLayout.LayoutParams params = (DrawerLayout.LayoutParams) ll.getLayoutParams();
params.setMargins(0, R.attr.actionBarSize, 0, 0);
ll.setLayoutParams(params);
((DocumentsActivity)getActivity()).getSupportActionBar().show();
if (getFragmentManager() != null)
getFragmentManager()
.beginTransaction()
.detach(this)
.attach(this)
.commit();
}
});
super.onActivityCreated(savedInstanceState);
}
In Kotlin, assuming that your Activity extends from AppCompatActivity
You should get the instance of the support action bar and call the methods
supportActionBar?.show() or supportActionBar?.hide()
If you're using a fragment, you can access the action bar from the Fragment's activity instance
(activity as AppCompatActivity).supportActionBar?.show()
Related
My Fragment class:
Toolbar toolbar;
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
toolbar = getView().findViewById(R.id.toolbar3);
toolbar.inflateMenu(R.menu.menufragmentmain);
setHasOptionsMenu(true); //i also tried putting this function in oncreate function
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
Toast.makeText(getActivity(), "i never enter this function also" , Toast.LENGTH_LONG).show();
super.onCreateOptionsMenu(menu,inflater);
inflater.inflate(R.menu.menufragmentmain, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
Toast.makeText(getActivity(), "i never enter this function" , Toast.LENGTH_LONG).show();
//some switch cases.....
return super.onOptionsItemSelected(item);
}
I've got a stupid error which I cant find unfourtantly. I've got a simple toolbar for my fragment. In onViewCreated I inflate my actionbar menu with my toolbar.
The issue is that the functions onCreateOptionsMenu and 'onOptionsItemSelected' are never called. I've got no clue why.
Things i checked in other similar questions with the same issue:
I checked if my main activity has a onCreateOptionsMenu or'onOptionsItemSelected'. It doesn*t
Checked if my style class has NOT: android:theme="#android:style/Theme.Black.NoTitleBar
None of the points unfourtantly work. What did I miss. Do I need to check something else?
As per the Fragment-owned app bar guide which explains how to use a Fragment-owned Toolbar, you do not use any of the setHasOptionsMenu(), onCreateOptionsMenu(), or onOptionsItemSelected() APIs - those are only used for activity owned app bars.
Instead, you would follow the guide for handling menu click events by using the Toolbar APIs:
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
toolbar = getView().findViewById(R.id.toolbar3);
toolbar.inflateMenu(R.menu.menufragmentmain);
toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
Toast.makeText(getActivity(), "onMenuItemClick called" , Toast.LENGTH_LONG).show();
//some switch cases.....
return true;
}
});
}
Set up the toolbar in the host Activity. Then override the menu handling in each Fragment wherever necessary.
Here's some generic scaffolding (with comments):
public class MyFragment extends Fragment {
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Report that this Fragment has an options menu
setHasOptionsMenu(true);
}
#Override
public void onCreateOptionsMenu(#NonNull Menu menu, #NonNull MenuInflater inflater) {
// Inflate then menu, and THEN call super()
// Note the order of the invocations
inflater.inflate(R.menu.my_menu, menu);
super.onCreateOptionsMenu(menu, inflater);
}
#Override
public boolean onOptionsItemSelected(#NonNull MenuItem item) {
// Handle menu item selections
final int itemId = item.getItemId();
switch(itemId) {
case R.id.my_menu_option_x: ...; return true;
case R.id.my_menu_option_y: ...; return true;
case R.id.my_menu_option_z: ...; return true;
default: return super.onOptionsItemSelected(item);
}
}
}
I have this scenario:
I have a activity, lets call itAcitivty1 with
#Override
public boolean onCreateOptionsMenu(Menu menu) {
return false;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
return false;
}
I open a fragment from Activity1 lets call it Fragment1 with:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
setHasOptionsMenu(true);
View view = inflater.inflate(R.layout.layout, container, false);
return view;
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
if (menu != null){
menu.clear();
}
if (!boolean) {
inflater.inflate(R.menu.menu1, menu);
} else {
inflater.inflate(R.menu.menu2, menu);
}
}
This fragment will be called again from activity as a new instance.
Based on the boolean in onCreateOptionsMenu() I'm deciding what menu should be loaded in the fragment so, during the second instance if I click on a menu item, I see the objects of first instance fragment.
I have no clue, why is this happening?
How is the workflow for displaying menu options...
if (menu != null){
menu.clear();
}
That piece of code might be the root cause.
You're telling the system to clear the menu if it's null. Well, FYI, the menu will never be null in the first place; it is supplied by the system. It might have no items inside, but it'll never be null.
One way to check if a menu already contains an item (or more) is to call hasVisibleItems().
From the documentations:
public abstract boolean hasVisibleItems()
Returns True if there is one or more item visible, else false.
Therefore, this is how you should do it:
if (menu.hasVisibleItems()){
menu.clear();
}
In a case like this, you need to put the menu in activity and update the menu dynamically in onPrepareOptionsMenu()
You need to inflate menu in onCreateOptionsMenu(..) of your Activity1 and need to make return true to display menu.
#Override
public boolean onCreateOptionsMenu(Menu menu) {
//Your code here
getMenuInflater().inflate(R.menu.main1, menu);//My menu
return true;
}
After that you get menu in your fragment also.
Edits:
If you use single menu file and show / hide MenuItem of your menu. it will solve your problem.
Add all menu in single file.by default all menu items are visible false using android:visible="false"
See example code:
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
MenuItem item1 = menu.getItem(0);
MenuItem item2 = menu.getItem(1);
MenuItem item3 = menu.getItem(2);
MenuItem item4 = menu.getItem(3);
if(!boolean){
//visible items which you want to show when boolean is false
item1.setVisible(true);
item2.setVisible(true);
}
else
{
//visible items which you want to show when boolean is true
item3.setVisible(true);
item4.setVisible(true);
}
super.onCreateOptionsMenu(menu, inflater);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.menuItem1) {
return true;
}
if (id == R.id.menuItem2) {
return true;
}
...
return super.onOptionsItemSelected(item);
}
I have a fragment that contains a ListView, when I try to show a DialogFragment on the top of it the selected list items are deselected. Is it possible to keep the items selected when the DialogFragment appears/disappears?
My Fragment's onCreateView():
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (DEBUG) {
Log.d(TAG, "BrowserFragment.onCreateView()");
}
View v = inflater.inflate(R.layout.fragment_filebrowser, container,
false);
listView = (ListView) v.findViewById(android.R.id.list);
listView.setAdapter(mAdapter);
listView.setOnItemClickListener(this);
listView.setEmptyView(v.findViewById(android.R.id.empty));
// FOR CONTEXT ACTION MENU
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
listView.setMultiChoiceModeListener(new MultiChoiceModeListener() {
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.contexual, menu);
mode.setTitle("Choose Files");
return true;
}
#Override
public void onDestroyActionMode(ActionMode mode) {
// TODO Auto-generated method stub
Log.d(TAG, "onDestroyActionMode!");
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_delete:
SimpleDialogFragment
.createBuilder(getActivity(),
getActivity().getSupportFragmentManager())
.setTitle(R.string.delete_files)
.setMessage(R.string.confirm_delete)
.setPositiveButtonText(R.string.yes)
.setNegativeButtonText(R.string.no).show();
mode.finish();
//The rest of the program..
Screenshots:
As you can see in the second screenshot, the listview's selected items have been deselected. How can I prevent that?
UPDATE: I'm using StyledDialogs library
Found the solution, the problem was that i was calling mode.finish() right after the dialogfragment.show(). I stored the ActionMode variable and used it inside my DialogFragments positive button callback to call the .finish() instead and everything is working correctly.
I am using the ActionBar drop-down navigation with OnNavigationListener implemented.
The requirement is to fire the onNavigationItemSelected() method every time, also when the same drop-down item is selected. The default Android implementation prevents the onNavigationItemSelected() method from running when the same item is selected.
I have seen the solutions to this requirement only for the standard Spinner implementation here and here, however not for the specific ActionBar drop-down navigation implementation.
Any suggestions how to overcome this default Android behaviour would be most appreciated.
Here is my code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPosition = -1;
actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
....
and
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.eventmenu, menu);
SpinnerAdapter mSpinnerAdapter = ArrayAdapter.createFromResource(actionBar.getThemedContext(), R.array.s_events,
android.R.layout.simple_spinner_dropdown_item);
OnNavigationListener mOnNavigationListener = new OnNavigationListener() {
#Override
public boolean onNavigationItemSelected(int position, long itemId) {
if (mPosition > -1) { // to prevent opening the data entry fragment when the Events fragment is initially opened
...
startActivity(newEvent);
}
mPosition = position;
return true;
}
};
actionBar.setListNavigationCallbacks(mSpinnerAdapter, mOnNavigationListener);
return true;
}
I got a Fragment B in a Fragment A in a Activity. Works as expected.
When clicking an item in Fragment B, I want to display a contextual menu bar.
I am working with ActionbarSherlock.
What i've done this inside my Fragment B:
private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.entry_list_context_menu, menu);
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
// make sure no item is selected when bar is shown
adapter.clearSelection();
adapter.notifyDataSetChanged();
return false;
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
Log.d("EntryList", "Item '" + item.getTitle()
+ "' clicked [onActionItemClicked()]");
return true;
}
#Override
public void onDestroyActionMode(ActionMode mode) {
adapter.clearSelection();
adapter.notifyDataSetChanged();
contextualMode = null;
}
};
private ActionMode contextualMode;
#Override
public void onItemClick(AdapterView<?> parentView, View itemView,
int index, long id) {
DocumentEntity entry = (DocumentEntity) itemView.getTag();
// something went wrong
if (entry == null) {
Log.e("EntryList", "Tag-Less item clicked [onItemClick()]");
return;
}
if (contextualMode != null) {
Log.d("EntryList",
"contextualMode is not yet initialized [onItemClick()]");
contextualMode = getSherlockActivity().startActionMode(
mActionModeCallback);
} else {
Log.d("EntryList",
"contextualMode already initialized [onItemClick()]");
}
entry.setSelected(!entry.isSelected());
Log.d("EntryList", "entry.selected set to " + entry.isSelected()
+ " [onItemClick()]");
}
The selection works pretty good, but no contextual Actionbar is shown.
The debug result is:
contextualMode already initialized [onItemClick()] entry.selected set
to 'true' [onItemClick()]
There is no other position where contextualMode is set...
I got a Fragment B in a Fragment A...
Android does not support embedding a fragment within another fragment. Sorry. This leads me to believe that your problem goes beyond the fact that your contextual ActionBar is not being shown. I suggest you clarify your original post.