如何防止弹出菜单关闭复选框单击

时间:2015-04-19 05:07:15

标签: android checkbox popupmenu

我在网上搜索了很多,但没有任何关于阻止弹出菜单关闭的内容。

每当我点击复选框项或任何其他弹出菜单项时,弹出菜单都会自动关闭。如何在用户选中/取消选中弹出菜单中的复选框时阻止它被忽略。

我在操作栏菜单项的点击事件中显示弹出菜单。

//main_menu.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.worldofjobs.woj.MainActivity" >

<item
    android:id="@+id/action_popUpMenu"
    android:icon="@drawable/ic_action_overflow"
    android:title="@string/main_action_popUpMenu"
    app:showAsAction="always"/>

</menu>

//popup_items.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >

<item
    android:id="@+id/refresh_item"
    android:title="@string/main_refresh"/>
<item
    android:id="@+id/checkbox_item"
    android:checkable="true"
    android:title="Start notification"/>
<item
    android:id="@+id/changePasswrod_item"
    android:title="@string/main_changePassword"/>
<item
    android:id="@+id/deleteAccount_item"
    android:title="@string/main_deleteAccount"/>
<item
    android:id="@+id/logout_item"
    android:title="@string/main_logout"/>

</menu>

/**
 * Shows popup menu on click of action bar-menu inflates from
 * menu.pop_items-xml
 */
private void showPopup() {

    try {

        View v = findViewById(R.id.action_popUpMenu);

        PopupMenu popup = new PopupMenu(this, v);
        popup.setOnMenuItemClickListener(MainActivity.this);

        MenuInflater inflater = popup.getMenuInflater();
        inflater.inflate(R.menu.pop_items, popup.getMenu());
        popup.show();

    } catch (Exception e) {

        Log.e("MainActivity-showPopup:", e.toString());
    }
}

/**
 * Handles click events of popup menu items
 */
@Override
public boolean onMenuItemClick(MenuItem item) {

    super.onMenuItemSelected(1, item);
    switch (item.getItemId()) {

    case R.id.refresh_item:
        refresh();
        return true;

    case R.id.checkbox_item:
        return true;

    case R.id.changePasswrod_item:
        changePasswordPopup();
        return true;

    case R.id.deleteAccount_item:
        deleteAccount();
        return true;

    case R.id.logout_item:
        session.logout();
        finish();
        return true;
    }
    return true;
}

6 个答案:

答案 0 :(得分:21)

在更改已检查状态时,使用popupMenu.show()立即重新显示弹出菜单与可检查菜单项无法正常工作。

这是一种防止首先关闭弹出菜单的方法。确保onMenuItemClick返回false。

popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
    @Override
    public boolean onMenuItemClick(MenuItem item) {

        item.setChecked(!item.isChecked());

        // Do other stuff

        // Keep the popup menu open
        item.setShowAsAction(MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
        item.setActionView(new View(context));
        item.setOnActionExpandListener(new MenuItem.OnActionExpandListener() {
            @Override
            public boolean onMenuItemActionExpand(MenuItem item) {
                return false;
            }

            @Override
            public boolean onMenuItemActionCollapse(MenuItem item) {
                return false;
            }
        });
        return false;
    }
});

答案 1 :(得分:5)

这里的诀窍是在菜单解散后立即显示菜单 以下是示例代码段:

popupMenu.setOnMenuItemClickListener(new OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
    if(item.getItemId()==R.id.search_by_date_checkbox){
        item.setChecked(!item.isChecked());
    }
    //This is the trick here!!!!
    popupMenu.show();
    return true;
    }

});

你可以用你的代码尝试这个技巧!这就是我做到的。 :)

答案 2 :(得分:2)

Oliver上面的回答(https://stackoverflow.com/a/31727213/2423194)给了我一个崩溃,它的消息告诉我使用MenuItemCompat代替。经过对此代码的一些调整后,它可以工作:

// Keep the popup menu open              
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
item.setActionView(new View(getContext()));
MenuItemCompat.setOnActionExpandListener(item, new MenuItemCompat.OnActionExpandListener() {
    @Override
    public boolean onMenuItemActionExpand(MenuItem item) {
        return false;
    }

    @Override
    public boolean onMenuItemActionCollapse(MenuItem item) {
        return false;
    }
});

谢谢奥利弗!

答案 3 :(得分:0)

在你的情况下R.id.checkbox_item

return false;

这将告诉系统该事件尚未被处理,并且不会使菜单失效。见HERE

答案 4 :(得分:0)

尝试全局声明PopupMenu并在import time def skipped(n): print("Ohhh no, skipped {0} ticks!".format(n)) # the object of the module im searching for timer = Timer() # mainloop while True: # a short calculation wouldn't cause skipped() to be called time.sleep(0.1) # but a too long calculation would # theoretically this should cause "Ohhh no, skipped 0.5 ticks!" to be printed #time.sleep(3) # wait until n seconds since the last sleep passed # if already more than n seconds passed call skipfunc((secondspassed-n)/n) timer.sleep(n=2, skipfunc=skipped) 函数中返回true之前调用popup.show();

答案 5 :(得分:0)

通过添加popup.show()得到它的工作;点击按钮并点击结束。

package com.example.exampleapp;

import android.app.PendingIntent;
import android.content.Intent;
import android.content.IntentFilter;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.Ndef;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.Toast;

public class NfcTestActivity extends AppCompatActivity {

    private static String LOG_TAG = NfcTestActivity.class.getSimpleName();
    private static int SUCCESS_COUNT = 0;
    private static int FAILURE_COUNT = 0;

    private NfcAdapter nfcAdapter;
    private PendingIntent pendingIntent;
    private IntentFilter[] intentFiltersArray;
    private String[][] techListsArray;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_nfc_test);
        getSupportActionBar().setDisplayShowHomeEnabled(true);

        nfcAdapter = NfcAdapter.getDefaultAdapter(this);
        if (nfcAdapter == null) {

            makeToast("NFC not available!", Toast.LENGTH_LONG);
            finish();

        }
        else {

            //makeToast("NFC available");

            pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);

            IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
            try {
                ndef.addDataType("*/*");    /* Handles all MIME based dispatches.
                                           You should specify only the ones that you need. */
            } catch (IntentFilter.MalformedMimeTypeException e) {
                throw new RuntimeException("fail", e);
            }
            intentFiltersArray = new IntentFilter[]{
                    ndef
            };

            techListsArray = new String[][]{
                    new String[]{
                            Ndef.class.getName()
                    }
            };
        }

    }

    @Override
    public void onPause() {
        super.onPause();

        if (nfcAdapter != null) {
            nfcAdapter.disableForegroundDispatch(this);
        }

    }

    @Override
    public void onResume() {
        super.onResume();

        if (nfcAdapter != null) {
            nfcAdapter.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, techListsArray);
        }

    }

    public void onNewIntent(Intent intent) {

        Ndef ndef = null;

        try {

            String action = intent.getAction();
            //makeToast("action: " + action);

            if (!NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {

                throw new Exception("Tag was not ndef formatted: " + action); // line #124

            }
            else {

                Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
                //do something with tagFromIntent

                ndef = Ndef.get(tag);
                //makeToast("ndef: " + ndef);

                if (ndef == null) {

                    throw new Exception("ndef == null!");

                }
                else {

                    // Connect
                    ndef.connect();

                    // Get cached message
                    NdefMessage ndefMessageOld = ndef.getCachedNdefMessage();

                    if (ndefMessageOld == null) {

                        throw new Exception("No ndef message on tag!");

                    }
                    else {

                        // Get old records
                        NdefRecord[] ndefRecordsOld = ndefMessageOld.getRecords();
                        int numRecords = (ndefRecordsOld == null) ? 0 : ndefRecordsOld.length;

                        // Create/copy 'new' records

                        NdefRecord[] ndefRecordsNew = new NdefRecord[numRecords];
                        for (int i = 0; i < numRecords; i++) {
                            ndefRecordsNew[i] = ndefRecordsOld[i];
                        }

                        // Create new message
                        NdefMessage ndefMessageNew = new NdefMessage(ndefRecordsNew);

                        // Write new message
                        ndef.writeNdefMessage(ndefMessageNew); // line #170

                        SUCCESS_COUNT++;

                        // Report success
                        String msg = "Read & wrote " + numRecords + " records.";
                        makeToast(msg);
                        Log.d(LOG_TAG, msg);

                    }

                }

            }

        }
        catch(Exception e) {

            FAILURE_COUNT++;

            Log.e(LOG_TAG, "Tag error", e);
            makeToast("Tag error: " + e, Toast.LENGTH_LONG);

        }
        finally {

            try {
                if (ndef != null) {
                    ndef.close();
                }
            }
            catch(Exception e) {
                Log.e(LOG_TAG, "Error closing ndef", e);
                makeToast("Error closing ndef: " + e, Toast.LENGTH_LONG);
            }

            makeToast("Successes: " + SUCCESS_COUNT + ". Failures: " + FAILURE_COUNT);

        }

    }

    private void makeToast(final String msg) {

        makeToast(msg, Toast.LENGTH_SHORT);

    }

    private void makeToast(final String msg, final int duration) {

        new Handler(Looper.getMainLooper()).post(new Runnable() {
            @Override
            public void run() {

                Toast.makeText(NfcTestActivity.this, msg, duration).show();

            }
        });
    }

}

但是,这不是最佳解决方案,因为如果列表中有很多项目可以滚动列表,则单击某个项目时列表将滚动到顶部。