Странное поведение контекстного меню для элемента меню

У меня есть странное поведение в контекстной панели действий.

Во-первых:

Один пункт меню отображается только каждый раз, когда я нажимаю кнопку переполнения:

Clicking behavior overflow button of CAB

Второе/третье:

Есть ли способ, которым иконки не используют столько места?

Когда я изменяю добавление свойства android:showAsAction="always" ко всем элементам, на самом деле достаточно места для отображения всех значков, но мой значок общего доступа больше не доступен:

All Items with showAsAction always

Чистый проект не помогает.

Я использую Android 4.2.2 на своем тестовом устройстве (Galaxy S3).

Я даже попытался полностью запустить новый ROM на моем XXX GS3 (CyanogenMod 10.1 теперь, перед SlimBean, также удалил навигационную панель внизу) - не помогло.

Я также пробовал это на Nexus 4. Больше места, поэтому кнопка совместного доступа и кнопка удаления видны. При запуске режима действия кнопка совместного доступа не переключается, но когда я включаю устройство в альбомный режим, он работает, и когда я верну его обратно к портрету, он все еще работает. Таким образом, в основном на Nexus 4 кнопка share не работает до поворота.


манифеста:

<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="17" />

Компиляция с minSdkVersion=17 не имеет значения.

Я запускаю Action Mode из фрагмента следующим образом:

mActionMode = activity.startActionMode(mMultipleCallback);

В ActionMode.Callback я заполняю меню:

@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;
}

И вот 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>

Для полноты всего 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);
        }
    }
};

Ответ 1

Хорошо, это решение для незакрепленной иконки общего доступа. Это было неправильное понимание от меня к API.

Я думал, что вы можете относиться к SharedActionProvider-Item как к любому другому элементу в вашем XML файле меню. Но на самом деле вы не можете. onActionItemClicked даже не запускается для этого значка, когда он отображается как действие (поэтому он не доступен при добавлении showAsAction=always). Довольно забавно, событие щелчка запускается, когда значок не отображается, но он отображается в меню переполнения. Это может быть фактическая ошибка в контекстной панели действий!

Теперь я наконец понял, как вы должны запускать SharedActionProvider-Item:

Вы должны (!) поместить Intent в метод onCreateActionMode:

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;
}

Теперь вы можете сказать: "Вы идиот, это было очевидно, и даже лучше установить намерение всегда там, а не в методе onActionItemClicked, как вы это делали раньше".

Извините, но я не согласен: на самом деле нет смысла устанавливать его здесь. Причина: для меня намерение меняется с каждым дополнительным элементом, который вы проверяете. Он создает файл export-XML для каждого элемента, который вы проверяете, и я действительно не хочу создавать XML файл каждый раз, когда нажимается значок. Это не имеет смысла, и я хочу, чтобы все файлы XML были созданы только тогда, когда пользователь действительно хочет экспортировать элементы.

Итак, в основном я сделал обходной путь для этого. Сначала я создаю Intent и добавляю пустой List<Uri>. Этот список сохраняется как переменная-член в моем классе, поэтому, если я добавляю в него элементы, элементы также будут в намерении. Затем, когда пользователь щелкает элемент общего доступа, список заполняется всеми выбранными элементами. Для этого я перевернул OnShareTargetSelectedListener. Этот метод запускается, когда пользователь нажимает на конкретную цель общего доступа (например, электронную почту, Dropbox и т.д.).

Теперь здесь весь код для этого (метод вызывается только один раз из 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);
}

Надеюсь, ты понимаешь, что я там сделал. Если нет, не стесняйтесь спрашивать.

С учетом всего вышеизложенного одна из моих проблем решена (значок ресурса не доступен для клика, когда отображается как значок), но остальные два остаются открытыми (значки не используют столько места и первой проблемы).


Проблема 2 вида решения:

Похоже, Android нуждается в значках, которые находятся в папках с более высоким разрешением (hdpi, xhdpi), чтобы быть в более высоком разрешении - значок включения/выключения имел только размер 32x32 пикселя (и я просто помещал их во все папки), и поэтому Android сделал какой-то большой беспорядок, поэтому только три значка действительно вписывались в панель действий. Я просто удалил все значки, но оригинальные из 32x32 пикселей в mdpi. Теперь Android расширяет иконки 32x32 пикселей и может отображать пять элементов в панели действий. Это странно.


Проблема 1 вид решены:

Похоже, что это было напрямую связано с проблемой 2, как только я решил проблему 2, значок удаления был помещен непосредственно на панель действий.

Также с некоторым тестированием я увидел, что текст всегда был там, если я добавил значок showAsAction=never на значок удаления. Я действительно думаю, что это как-то связано с проблемой 2 (значки действительно делали плохие вещи там).


Мои проблемы почти решены.

Я думаю, что теперь у меня появилась (новая) реальная ошибка: последнее действие с общим доступом плавает над значком переполнения. При нажатии там меню переполнения открывается, но выглядит довольно дерьмо:

Most recent share icon above overflow icon

Как я это исправил?

Ну, я покончил с этим ****, поэтому я просто добавил значок showAsAction=never к значку общего доступа. (И да, я видел этот, но я получаю исключение, если я это делаю, а также другое изменение нормального жизненного цикла...)

Не стесняйтесь комментировать, если вы знаете лучшее решение, чем я использовал: >