I have some weird behavior in the contextual action bar.
Firstly:
One menu item is only shown every second time I click on the overflow button:
Secondly / thirdly:
Is there a way that the icons do not use so much space?
When I change add property android:showAsAction="always"
to all items, there is actually enough space to show all icons - but my share icon is not clickable anymore:
Clean Project does not help.
I use Android 4.2.2 on my test device (Galaxy S3).
I even tried to completely flash a new ROM on my XXX GS3 (CyanogenMod 10.1 now, before SlimBean, also removed the navigationbar at at the bottom) - did not help.
I also tried it on a Nexus 4. There is more space, so the share button and the delete button are visible. The share button is not clickable when I start action mode, but when I turn the device to landscape mode it works, and when I turn it back to portrait it still works. So basicially on the Nexus 4, the share button does not work before rotating.
Manifest:
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="17" />
Compiling against minSdkVersion=17
makes no difference.
I start the Action Mode from a fragment like this:
mActionMode = activity.startActionMode(mMultipleCallback);
In the ActionMode.Callback
I populate the menu:
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.management_cab, menu);
MenuItem item = menu.findItem(R.id.managementCABShare);
mShareActionProvider = (ShareActionProvider) item.getActionProvider();
//...other stuff
return true;
}
And here is the XML:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:title="@string/checkAll"
android:id="@+id/managementCABCheckAll"
android:icon="@android:drawable/checkbox_on_background">
</item>
<item
android:title="@string/enable"
android:id="@+id/managementCABEnable"
android:icon="@drawable/sphere_green">
</item>
<item
android:title="@string/disable"
android:id="@+id/managementCABDisable"
android:icon="@drawable/sphere_red">
</item>
<item
android:title="@string/delete"
android:id="@+id/managementCABDelete"
android:icon="@android:drawable/ic_menu_close_clear_cancel">
</item>
<item
android:title="@string/share"
android:id="@+id/managementCABShare"
android:actionProviderClass="android.widget.ShareActionProvider"
android:icon="@android:drawable/ic_menu_share">
</item>
<item
android:title="@string/export"
android:id="@+id/managementCABExport"
android:icon="@drawable/explorer">
</item>
</menu>
For the sake of completeness the whole callback
:
protected ActionMode.Callback mMultipleCallback = new ActionMode.Callback() {
private ShareActionProvider mShareActionProvider;
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.management_cab, menu);
MenuItem item = menu.findItem(R.id.managementCABShare);
mShareActionProvider = (ShareActionProvider) item.getActionProvider();
hideUnwantedCABItems(menu);
return true;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
List<Integer> checkedPositions = getAllCheckedPositions();
switch (item.getItemId()) {
case R.id.managementCABCheckAll:
changeCheckedOfAllItems(true);
return true;
case R.id.managementCABEnable:
changeEnabled(checkedPositions, true);
return true;
case R.id.managementCABDisable:
changeEnabled(checkedPositions, false);
return true;
case R.id.managementCABDelete:
if (deleteAlert == null)
createDeleteDialog(checkedPositions);
initDeleteDialog(checkedPositions);
return true;
case R.id.managementCABShare:
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND_MULTIPLE);
shareIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, exportItemsAndGetUris(checkedPositions));
shareIntent.setType("application/xml");
setShareIntent(shareIntent);
return true;
case R.id.managementCABExport:
String message;
if (StorageController.copyUriListToExportFolder(exportItemsAndGetUris(checkedPositions)))
message = getActivity().getString(R.string.export_success);
else
message = getActivity().getString(R.string.export_fail);
Toast.makeText(getActivity(), message + ":\n" + StorageController.getExternalExportApplicationFolder(), Toast.LENGTH_LONG).show();
return true;
default:
return false;
}
}
@Override
public void onDestroyActionMode(ActionMode mode) {
mActionMode = null;
changeCheckedOfAllItems(false);
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
private void setShareIntent(Intent shareIntent) {
if (mShareActionProvider != null) {
mShareActionProvider.setShareIntent(shareIntent);
}
}
};
Okay, the solution to the unclickable share icon. This was kind of a misunderstanding from me to the API.
I thought you could treat a SharedActionProvider-Item
like every other item in your menu XML file. But actually you can't. onActionItemClicked
is not even triggered for this icon when it's shown as an action (this is why it's not clickable when you add showAsAction=always
). Funny enough, the click event is triggered when the icon is not shown, but it is visible in the overflow menu. This may be an actual bug in the contextual action bar!
Now I finally figured out how you should trigger a SharedActionProvider-Item
:
You have to (!) put a Intent
in the onCreateActionMode
method:
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.management_cab, menu);
MenuItem item = menu.findItem(R.id.managementCABShare);
initSharedActionProvider(item); //Check out this method in the next code fragment
return false;
}
Now you may say: "You idiot, this was obvious, and it's even better to set the intent always there instead as in the onActionItemClicked
Method as you did before".
Sorry, but I disagree: It does not really make sense to set it here. The reason is: For me the intent changes with every additional item you check. It creates an export-XML file for each item you check, and I really don't want to create an XML file each time an icon is clicked. This makes no sense, and I want all XML files to be created only when a user really wants to export the items.
So basically I made a workaround for this. At the beginning, I make an Intent
and add an empty List<Uri>
. This list is saved as a member variable in my class, so if I add items to it, the items will also be in the intent. Then when the user clicks the share item, the list is populated with all selected items. To accomplish this I overrode the OnShareTargetSelectedListener
. This method is triggered when a user clicks on a concrete share target (like email, dropbox, etc.).
Now here's the whole code for that (the method is only called once from onCreateActionMode
):
private void initSharedActionProvider(MenuItem item) {
mShareActionProvider = (ShareActionProvider) item.getActionProvider();
mShareActionProvider.setOnShareTargetSelectedListener(new OnShareTargetSelectedListener() {
@Override
public boolean onShareTargetSelected(ShareActionProvider source, Intent intent) {
//Here is the exportedFiles list populated
exportItemsAndSetList(getAllCheckedPositions());
return true;
}
});
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND_MULTIPLE);
//exportedFiles is a member Variable which I populate with the selected items, with the exportItemsAndSetList method
shareIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, exportedFiles);
shareIntent.setType("application/xml");
mShareActionProvider.setShareIntent(shareIntent);
}
I hope you understand what I did there. If not, feel free to ask.
With all this above, one of my problems is solved (that the share icon is not clickable when shown as an icon) - but the other two remain open (icons shouln't use so much space and the first problem).
Problem 2 kind of solved:
Seems like Android needs the icons which are in the higher resolution folders (hdpi, xhdpi) really to be in a higher resolution - my enable / disable icon had only a size of 32x32 pixels (and I just put them in all folders) and therefore Android made a big mess somehow, so only three icons did fit on the action bar. I just removed all icons, but the original ones of 32x32 pixels in mdpi. Now Android upscales the 32x32 pixels icons and can display five items in the actionbar. It is kind of strange.
Problem 1 kind of solved:
Looks like this was directly related to problem 2, as soon as I solved problem 2, the delete icon was placed directly on the action bar.
Also with some testing I saw that the text was always there if I added showAsAction=never
to the delete icon. I really think it had something to do with problem 2 (the icons really did bad stuff there).
My problems are almost solved.
I think I got a (new) real bug now: the most recently used share action is floating over the overflow icon. When clicking there, the overflow menu still opens, but it looks pretty shitty:
How did I fix this?
Well I'm done with messing around with this ****, so I just added the showAsAction=never
to the share icon. (And yes I saw this, but I get an exception if I do this, also it's another change of the normal lifecycle...)
Feel free to comment if you a know better solution than I used :>
来源:https://stackoverflow.com/questions/16200242/contextual-action-bar-weird-behavior-for-menu-item