I have an app with two fragments, every fragment has a listview. When selecting elements from the list the context menu appears automatically, I handle events an so on ... so far so good, but my problem is when I change to the other fragment, the context menu keeps visible so user may get confused thinking that it is the context menu from the current visible list view.
I've tried calling
getActivity().closeContextMenu();
when switching between fragments but it doesn't work.
Any suggestion will be really appreciated.
Thank you!
I've found a solution:
I am using ListView.CHOICE_MODE_MULTIPLE_MODAL for multiple selection, at the MultiChoiceModeListener I save the actionmode for later use:
public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
// item selected
Log.d("FilesFragment.ContextMenu", "onItemCheckedStateChanged(); position: " + position);
actionmode = mode; // <- I save the action mode for later use
listadapter.getItem(position).setSelected(checked);
}
Then when I detect that user wants to change to another tab-frame I call
if (actionmode!=null){
actionmode.finish();
}
Related
I am using Actionbar dropdown navigation list ( mode ActionBar.NAVIGATION_MODE_LIST) in my app.
I am trying to launch a dialog on one of the item is chosen. Used the call back to get the position and could show the dialog.
public boolean onNavigationItemSelected(int position, long id) {
}
But when user doesn't choose any action on the dialog, or dismisses it, or user again chooses the drop down menu and chooses the same item, i need to show the dialog again. But the 'onNavigationItemSelected' won't be triggered if the same item is selected again. A
I have implemented a custom SpinnerAdapter and overriden, 'getView' (title for corresponding item) and getDropDownView' (drop down item).I could change the title, but i wanted to launch the dialog every time a specific item is chosen from the drop down.
'Moves' popular app uses a similar approach. The launch screen has spinner on the action bar with three options 'Today' 'Yesterday' 'Specific day'. The app could able to launch the (datepicker dialog) on every time the 'specific day' item is chosen. I am trying to implement the exact UI pattern. Couldn't get the clue how to achieve it.
I did try setting onClick listener for the particular dropdown item. It kinda of worked.
But the dropdown menu was not dismissed, after clicking on the item which had set onClick event.
Since we absorb the click event,framework doesn't perform background state change for that particular item too.
One thing to note on 'Moves' app is as soon as 'Specific day' is chosen, it doesn't set the selected item as 3rd option, navigation still remains on the previous selected item, only the datepicker dialog is shown.
I tried implementing onTouch Listener and basically dint absorb the click events,
launched dialog as soon as first touch event is made (ACTION_DOWN). It did dismisses the dropdown menu after clicking and showed background state change. But it doesn't bring the good user experience as we need to launch dialog only when user completes the click action.
holder.title.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
showTimePickerDialog();
return false;
}
}
Wondering how moves app would have done. Any insights how to achieve this behaviour. ?
Use a simple if
#Override
public boolean onNavigationItemSelected(int itemPosition, long itemId) {
if(itemPosition==0){
showDialogToday();
}else if(itemPosition==1){
showDialogYesterday();
} else{
showDialogOtherday();
}
return true;
}
each method called with the dialog code this suppose to be easy......i use this with a fragment and this is simple
What I want to achieve:
A list item is highlighted when the user is pressing it
When the user stops pressing it, the list item:
remains highlighted, if it was unselected before the pressing
loses the highlight, if it was selected before the pressing
Long clicks behave the same way as the user stopping the pressing (changing the background of the item depending on its previous state)
Scrolling the list, without pressing any specific item, should not highlight any item
Details:
For what I read, I think that behaviour could be achieved using list selectors and the state android:state_activated, but this state was introduced in API level 11. The solution I am looking for has to work in API level 10
I think that solutions relying on click (onItemClick, onClick...) will not work, because the click is triggered after the user stops the pressing, not when he starts it (like the pressed state does). Changing the highlight of an item using android:state_pressed is not persistent (it will change back after the press is finished) and changing it in android:state_pressed and making it persistent on click will produce a flicker
A good example of app that achieves that in API level 10 is Tasks. Just click or long click on items in the list to see the desired behaviour
So, anybody has already solved that? Any idea on how the Tasks app does it?
You probably want to set a OnTouchListener(in the getView method) on the row View. That way you'll see the MotionEvent for the first touch(the MotionEvent.ACTION_DOWN action) and can set the selection:
private OnTouchListener mTouchListener = new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
v.setBackgroundColor(Color.RED); // set the selection
}
// don't forget to store this new status so the adapter will see
// it. Otherwise you'll have some problems when the list will be
// scrolled.
return false;
}
};
I finally solved that issue implementing my own list (PressListView) extending ListView. PressListView has a callback to notify the user when an item on the list has been pressed.
Knowing when the items are pressed (which was the most difficult part), the only thing left is handling in a proper way the backgrounds of the item, which you can do in your own Adapter using selectors.
For those interested on seeing this fully working, take a look at my demo project.
You can launch the CAB performing a long click in an item, and once in CAB you can test the highlighting of items, both with touches and D-pad/trackpad.
Although my solution works as I wanted, it is still slower than the list in the Tasks app, when changing the state of the items. If you try to select two items really fast, most of the times it will not select one of the items on my example, but it will in Tasks. If someone knows what it can be, I would be extremely grateful!
Implement ActionMode on your ListView (see second link below). In ActionMode, the ListView keeps track of the item checked state automatically when the user clicks on an item. When you are using an adapter for your ListView, you set the background of an item based on the checked state:
#Override
public void bindView(final View view, final Context context, final Cursor cursor)
{
int pos = cursor.getPosition();
boolean selected = ((SessionsActivity)context).listView.isItemChecked(pos);
if(!selected)
view.setBackgroundResource(R.drawable.list_selector);
else
view.setBackgroundResource(R.drawable.list_selector_active);
...
AND, you also need to invalidate the ListView, after each item click:
private AbsListView.MultiChoiceModeListener multiChoiceModeListener = new AbsListView.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
listView.invalidateViews();
}
See https://stackoverflow.com/a/50639298/2477937 and https://medium.com/over-engineering/using-androids-actionmode-e903181f2ee3
Our UX asks for a button to start multi-choice mode. this would do the same thing as long-pressing on an item, but would have nothing selected initially.
What I'm seeing in the code is that I cannot enter multi-choice mode mode unless I have something selected, and if I unselect that item, multi-choice mode exits (contextual action bar closes).
I've also tried this in other apps (gmail), and it works the same way.
Is there a way to be in multi-select mode, with no items selected?
It's very hacky, but I've done this by having an item selected, but making it look like it's not selected, by making the background temporarily transparent. When an item is then selected by the user, the secretly-selected item is deselected and the background restored to normal. Or, if it's the secretly-selected item which is selected (thus deselecting it), I reselect it, then set a boolean to stop it happening again.
I also had to use a counter in onItemCheckedStateChanged, as I was changing the checked state of the secret item from within that callback, resulting in a loop.
Probably not an ideal solution for all cases, but I don't think there's another way to do it at the moment, since AbsListView can't easily be extended.
Edit: if the screen orientation changes while the selected state of the selected item is hidden, it will suddenly be shown as being selected, so you have to make sure to save the fact that it should be hidden, and restore it after the listview is recreated. I had to use the View post() method to ensure the restoration happened after the listview had finished redrawing all its child items after the configuration change.
Edit: another potential issue is if the user tries to carry out an action while there are supposedly no items selected. As far as the application knows there is an item selected so it will carry out the action on that item, unless you make sure it doesn't.
Just call:
mListView.setItemChecked(-1, true);
ListView's actionMode will be started without selecting any list element.
Make sure you've properly set your ListView before call:
mListView.setMultiChoiceModeListener( ... )
mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
or
mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
You just have to use :
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
If you want to change the action bar, call this from your activity:
startActionMode(new ActionMode.Callback {
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
return false;
}
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
#Override
public void onDestroyActionMode(ActionMode mode) {
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
return false;
}
});
How can we handle the check button in the CAB menu?
Is the item associated to some internal id like android.R.id.checkbox?
I've read that it could be handled in SherlockActionBar CAB, but could it be the same with the native ActionBar CAB?
Is there any way to detect the interaction of this item? onActionModeFinished() is not sufficient since I'm calling it multiple times since the CAB needs to be present due to previous changes that happened.
Thanks.
Ok, finally found a solution after trying some things.
Place the code you want for the checkbox or onbackpressed in the method below
public void onDestroyActionMode(ActionMode mode)
{
//place the code you want for the checkbox or back icon here. If you don't want
// this code run if other selections are used, then just create a boolean value that
//you earlier on and check the value in this section before implementing the code
}
};
Do you know how to rename existing menu ?
I can rename when press menu item. But I don't know how to access to menu item when press the button.
Please advice.
It would be good if you can clarify the question a little, but each time the user presses the Menu on their Android device while inside one of your activities, the onPrepareOptionsMenu method is called. The first time the menu is shown (i.e. only once), the onCreateOptionsMenu method is called.
Basically, the onPrepareOptionsMenu method is where you should make any changes such as enabling/disabling certain menu items, or changing the menu item text depending on the circumstances.
As an example:
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
// Check current message count
boolean haveMessages = mMessageCount != 0;
// Set 'delete' menu item state depending on count
MenuItem deleteItem = menu.findItem(R.id.menu_delete);
deleteItem.setTitle(haveMessages ? R.string.delete : R.string.no_messages);
deleteItem.setEnabled(haveMessages);
return super.onPrepareOptionsMenu(menu);
}
Use MenuItem.setTitle(). If this isn't what you needed, you have to be more specific.
The onPrepareOptionsMenu is the proper place to make changes to menuitems.