onOptionsItemSelected not called when using actionLayout (SherlockActionBar)

The method onOptionsItemSelected isn't being called when using actionLayout in a menu item. Am I missing something, or is it a known problem with SherlockActionBar?

Activity

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getSupportMenuInflater();
    inflater.inflate(R.menu.article, menu);

    super.onCreateOptionsMenu(menu);

    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {   

    Log.d(TAG, "onOptionsItemSelected()");

    switch (item.getItemId()) {        
        case android.R.id.home:            
            finish();      
            return true; 
        case R.id.menu_item_comment:
            return true;
        default:            
            return super.onOptionsItemSelected(item);    
    }
}

Menu

<item android:id="@+id/menu_item_comment"
    android:showAsAction="ifRoom"
    android:actionLayout="@layout/action_bar_comment_layout"/>

Answers


well, you have to set onClickListener on that actionLayout to receive callback. I do it like this:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getSupportMenuInflater().inflate(R.menu.map_menu, menu);
    for (int i = 0; i < menu.size(); i++) {
        MenuItem item = menu.getItem(i);
        if (item.getItemId() == R.id.menu_more) {
            itemChooser = item.getActionView();
            if (itemChooser != null) {
                itemChooser.setOnClickListener(this);
            }
        }
    }
    return super.onCreateOptionsMenu(menu);
}

You should use MenuItemCompat.getActionView(menuItem); instead of item.getActionView(); if you are developing for older version.

@Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu, menu);
        for (int i = 0; i< menu.size() ;i++) {
            MenuItem menuItem = menu.getItem(i);
            if (menuItem.getItemId() == R.id.add_item) {
                View view = MenuItemCompat.getActionView(menuItem);
                if (view != null) {
                    view.setOnClickListener(new OnClickListener() {

                        @Override
                        public void onClick(View v) {
                            Intent intent = new Intent(MainActivity.this, ToDoActivity.class);
                            startActivity(intent);
                        }
                    });
                }
            }
        }       
        return true;
    }

You'll have to add your own OnClickListener and explicitly call onOptionsItemSelected:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuItem awesomeMenuItem = menu.findItem(R.id.action_awesome);
    View awesomeActionView = menuItem.getActionView();
    awesomeActionView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            onOptionsItemSelected(awesomeMenuItem));
        }
    });
}

P.S: Don't know why it doesn't work out of the box.


@Override
public boolean onCreateOptionsMenu(Menu menu) {
    super.onCreateOptionsMenu(menu);
    getMenuInflater().inflate(R.menu.main, menu);
    View view = menu.findItem(R.id.menu_item_comment).getActionView();
    view.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // do something
        }
    });
    return true;
}

Also, (and that was very important for me, so other answers did not work) you need to disable the clickable option of all views in your action layout (that is, action_bar_comment_layout.xml):

android:clickable="false"

Combining @Arun Kumar's and @Luten's answers, the below method will make the implementation generic. For all the menu items using actionView, we setOnClickListener to call onOptionsItemSelected(item). This way we can mix and match normal and actionLayout menu items, without worrying about setting individual onClickListeners.

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    menu.clear();
    inflater.inflate(menuResourceId(), menu);

    for (int i = 0; i < menu.size(); i++) {
        final MenuItem item = menu.getItem(i);
        View actionView = MenuItemCompat.getActionView(item);
        if (actionView != null) {
            actionView.setOnClickListener(new View.OnClickListener(){
                @Override
                public void onClick(View v){
                    onOptionsItemSelected(item);
                }
            });
        }
    }

    super.onCreateOptionsMenu(menu, inflater);
}

 override fun onCreateOptionsMenu(menu: Menu?): Boolean {
    menuInflater.inflate(R.menu.menu_add_require, menu)

    val menuItem = menu!!.findItem(R.id.menu_cart)
    val view = menuItem.actionView
    view.setOnClickListener {
        onOptionsItemSelected(menuItem)
    }

    return true
}

Working for me (code is in kotlin)


Need Your Help

Accessing elements of nested hashes in ruby

ruby hash hash-of-hashes

I'm working a little utility written in ruby that makes extensive use of nested hashes. Currently, I'm checking access to nested hash elements as follows:

C++ Cross-Platform High-Resolution Timer

c++ cross-platform timer

I'm looking to implement a simple timer mechanism in C++. The code should work in Windows and Linux. The resolution should be as precise as possible (at least millisecond accuracy). This will be us...