ListView loses all selections when DialogFragment is shown - android

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.

Related

Toolbar won't disappear in action mode

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()

Focus ListView Items on Button Click

Is it possible to focus the List View Items through any button click?
Like i want that when user click on Floating Action Button then the listview gets focused. I dont want to show checkbox type layout on button clicked. I just want to show the same like in the screenshot on Button click.
What i did is I put the listview onItemLongClick code in the button click blocks but it doesnot work.
fabButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
listViewMessages.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
listViewMessages.setMultiChoiceModeListener(new MultiChoiceModeListener() {
#Override
public void onItemCheckedStateChanged(ActionMode mode, int position,
long id, boolean checked) {
tv.setText(listViewMessages.getCheckedItemCount()+ " Selected");
}
#Override
public boolean onActionItemClicked(final ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.menu:
}
});
mode.finish();
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.contextual, menu);
fabButton.setVisibility(View.INVISIBLE);
fabButtonn.setVisibility(View.VISIBLE);
fabButtonn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
for ( int i=0; i< messageListAdapter.getCount(); i++ ) {
listViewMessages.setItemChecked(i, true);
}
}
});
return true;
}
#Override
public void onDestroyActionMode(ActionMode mode) {
fabButton.setVisibility(View.VISIBLE);
fabButtonn.setVisibility(View.GONE);
}
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
// Here you can perform updates to the CAB due to
// an invalidate() request
return false;
}
});
With this code if user clcik on button then he/she has too long press items again to focus the list items which is not what i want. I want to focus items right when button click. Any explanation or link provided will be helpful

onOptionsItemsSelected not being used in Fragment

I'm trying to add a button to my menu bar in my ListFragment class. When I click the button, nothing happens though. The onCreateOptionsMenu method is never being called in the class. I've tried everything to get it working but it still won't work. Has anyone got any solutions?
I've attached my code below:
public class FragmentZero extends ListFragment {
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
// use your custom layout
setHasOptionsMenu(true);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_layout_zero, container, false);
oslist = new ArrayList<HashMap<String, String>>();
new JSONParse().execute();
return view;
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
// Inflate the menu items for use in the action bar
inflater.inflate(R.menu.main_fragment_zero, menu);
super.onCreateOptionsMenu(menu, inflater);
}
public boolean onOptionsItemsSelected(MenuItem item) {
// Take appropriate action for each action item click
switch (item.getItemId()) {
case R.id.action_refresh:
// check for updates action
RefreshButton();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
Add setHasOptionsMenu(true) to your onCreateView() method and remove it in OnCreate().
So this was a pretty stupid error that I was having and I solved it thanks to everyone's help here.
I was spelling onOptionItemSelected wrong. I was adding an extra 's' after item.
As soon as I corrected this, the method started to work.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_refresh:
RefreshButton();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void RefreshButton() {
oslist = new ArrayList<HashMap<String, String>>();
new JSONParse().execute();
}

listview scrolling to end after showing Contextual action bar

When i do a long click on an item in the list view(which triggers the contextual action bar to show up), the list view automatically scrolls to the end. This behaviour is very irritating if the user had selected an item after scrolling up.
Using breakpoints i verified that this happens after onItemCheckedStateChanged() in the MultiChoiceModeListener implementation has completed. But i am not sure what code gets executed after this that causes the behaviour.
Removing the transcriptMode attribute from the list view layout resolves the issue. But i don't want to remove it as it is required to scroll automatically when the data has changed in the cursor. Any ideas what is causing the problem?
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Get the chat messages list view from the layout
lv_chatMessages = (ListView) getActivity().findViewById(
R.id.listview_chat);
// Instantiate the adapter for the chat messages
adpt_chat = new ChatMessagesAdapter(getActivity());
// connect the adapter to the list view
lv_chatMessages.setAdapter(adpt_chat);
//Implement multi choice mode listener for the list view
//only if Android API 11 or higher
if (Utils.hasHoneycomb()) {
//Enable selection of multiple chat messages
lv_chatMessages.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
//Handle Action mode events
lv_chatMessages
.setMultiChoiceModeListener(new MultiChoiceModeListener() {
#Override
public boolean onActionItemClicked(ActionMode mode,
MenuItem item) {
switch(item.getItemId()){
case R.id.delete_menu :
long[] selected_IDs = lv_chatMessages.getCheckedItemIds();
int deletedRows = deleteMessages(selected_IDs);
Toast.makeText(getActivity(), deletedRows + " message(s) deleted",
Toast.LENGTH_SHORT).show();
return true; // true indicates the menu selection is handled. no further
// system handling required
default :
return false;
}
}
#Override
public boolean onCreateActionMode(ActionMode mode,
Menu menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.chatsession_contextmenu, menu);
return true;
}
#Override
public void onDestroyActionMode(ActionMode arg0) {
// TODO Auto-generated method stub
}
#Override
public boolean onPrepareActionMode(ActionMode arg0,
Menu arg1) {
// TODO Auto-generated method stub
return false;
}
#Override
public void onItemCheckedStateChanged(ActionMode mode,
int position, long id, boolean checked) {
mode.setTitle(lv_chatMessages.getCheckedItemCount() + " selected");
}
});
}
...
..
}
The list view layout :
<ListView
android:id="#+id/listview_chat"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:layout_alignParentTop="true"
android:transcriptMode="alwaysScroll"
android:stackFromBottom="true"
android:layout_above="#id/layout_input"
android:divider="#00000000"
/>
Removing the transcriptMode attribute seems to be the only solution. I use the below code whenever i require an automatic scroll to the end :
new Handler().postDelayed(new Runnable(){
public void run(){
lv_chatMessages.setSelection(lv_chatMessages.getCount());
}
},100);

Passing id of ListView item to ActionMode.Callback object

So my problem right now is that right now I am long clicking an item in a ListView which brings up a contextual action bar. The id passed into onItemLongClick is the variable that I would like to use in the mActionModeCallback's on ActionItemClicked() method. This seems like it would be a fairly common procedure since if a user is editing a list of items, you would want to access the id of that row in the database somehow when the user clicked an "edit" or a "delete" action.
listView.setOnItemLongClickListener(new OnItemLongClickListener() {
public boolean onItemLongClick(AdapterView<?> p, View view, int pos, long id) {
//The id of the row in the database
long variableThatIWantToPassToCallback = id;
mActionMode = getActivity().startActionMode(mActionModeCallback);
view.setSelected(true);
return true;
}
});
private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
public boolean onCreateActionMode(ActionMode mode, Menu menu) {}
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {}
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
//I would like access to the id of the clicked item here, NOT item.getItemId()
}
public void onDestroyActionMode(ActionMode mode) {}
};
The proper way to do this is to call mActionMode.setTag("1") in onItemCheckedStateChanged and then from the onActionItemClicked function call mode.getTag();
Create your own callback by extending the interface ActionMode.Callback
private interface ActionCallback extends ActionMode.Callback {
public void setClickedView(View view);
}
private ActionCallback mActionModeCallback = new ActionCallback() {
public View mClickedView;
public void setClickedView(View view) {
mClickedView = view;
}
// Called when the action mode is created; startActionMode() was called
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
// Inflate a menu resource providing context menu items
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.context_menu, menu);
return true;
}
// Called each time the action mode is shown. Always called after onCreateActionMode, but
// may be called multiple times if the mode is invalidated.
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false; // Return false if nothing is done
}
// Called when the user selects a contextual menu item
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item ) {
switch ( item.getItemId() ) {
case R.id.menu_delete:
Log.v( TAG, "#onActionItemClicked ready to delete the item with id: " + mClickedView.getTag() );
mode.finish(); // Action picked, so close the CAB
return true;
default:
return false;
} // end switch
}
// Called when the user exits the action mode
#Override
public void onDestroyActionMode(ActionMode mode) {
mActionMode = null;
}
};
For a view which has OnLongClickListener attached, override the onLongClick callback this way.
#Override
// Called when the user long-clicks on someView
public boolean onLongClick( View view ) {
// proceed only when actionmode is not null
// otherwise overlapping action modes will be
// displayed
if( mActionMode != null ) {
return false;
}
mActionModeCallback.setClickedView(view);
// Start the CAB using the ActionMode.Callback defined above
mActionMode = startActionMode( mActionModeCallback );
view.setSelected(true);
return true;
}

Categories

Resources