Leo
Leo

Reputation: 1443

ActionBar Icon doesn't appear on ActionBar again after setVisible to false then true

I have an ActionBar with mode ActionBar.NAVIGATION_MODE_TABS, I want to change icons which appear on ActionBar when I choose different tabs.

I did it successfully with an Activity, but it acted weird when I applied it again on another Activity.

Let's say I have 2 tabs: Tab1 and Tab2, and I want a Camera icon to appear when Tab2 is being chosen and disappear when Tab1 is being chosen. Moreover, Tab1 is the first tab will be chosen when the activity start. So I did something like this:

Because I don't want the camera icon to appear at the first time HomeActivity start, so I set android:visible="false", then when I run below code: when HomeActivity starts, camera icon doesn't appear on ActionBar -> correct, but when I switch to tab2, camera icon doesn't appear on ActionBar too, but if I press "Menu" button -> a MenuItem which is "Camera" appears as an overflow actionbar item.

And if I set android:visible="true" -> except the camera icon appears at the first time first time HomeActivity start (incorrect!!!) -> then camera icon disappears/appears correctly when I change tab1/tab2.

Can anyone explain and give me a solution to make it works correctly. Thanks!

This is my code:

actionbar_home.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/actionbar_home_camera"
        android:title="@string/actionbar_rc_camera"
        android:icon="@drawable/ic_action_camera"
        android:showAsAction="always" 
        android:visible="false"/>
</menu>

HomeActivity.java

public class HomeActivity extends SherlockFragmentActivity {
private ActionBar actionBar;
private Menu menu;
private Tab1Fragment tab1Fragment;
private Tab2Fragment tab2Fragment;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_home);

    this.configActionBar();
    this.createTabs();
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getSupportMenuInflater().inflate(R.menu.actionbar_home, menu);
    this.menu = menu;

    // pass objects to tabs
    tab1Fragment.setOptionMenu(this.menu);
    tab2Fragment.setOptionMenu(this.menu);

    return true;
}


@Override
public boolean onOptionsItemSelected(MenuItem item) {

    return super.onOptionsItemSelected(item);
}

private void configActionBar()
{
    actionBar = this.getSupportActionBar();
    // below line makes application icon in top-left corner become a button
    actionBar.setHomeButtonEnabled(true);
    // below line add an arrow "<" before the top-left icon
    //ab.setDisplayHomeAsUpEnabled(true);
    //actionBar.setDisplayShowTitleEnabled(true);
}

private void createTabs()
{
    actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
    ActionBar.Tab tab1 = actionBar.newTab().setText(
            Const.TAB_TITLE_HOME_TAB1);
    ActionBar.Tab tab2 = actionBar.newTab().setText(
            Const.TAB_TITLE_HOME_TAB2);

    // create the two fragments we want to use for display content
    tab1Fragment = new Tab1Fragment();
    tab2Fragment = new Tab2Fragment();        

    // add listener
    tab1.setTabListener(
            new HomeTabListener(tab1Fragment));
    tab2.setTabListener(
            new HomeTabListener(tab2Fragment));        
    actionBar.addTab(tab1);
    actionBar.addTab(tab2);     
}
}

BaseTabFragment.java

public class BaseTabFragment extends SherlockFragment{
    protected View root;
    protected Menu optionMenu;
    protected SherlockFragmentActivity container;

    public Menu getOptionMenu() {
        return optionMenu;
    }
    public void setOptionMenu(Menu optionMenu) {
        this.optionMenu = optionMenu;
    }
    public SherlockFragmentActivity getContainer() {
        return container;
    }
    public void setContainer(SherlockFragmentActivity container) {
        this.container = container;
    }
}

Tab1Fragment.java

public class Tab1Fragment extends BaseTabFragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        root = inflater.inflate(R.layout.tab1_layout, 
                container, false);


        this.changeActionBarLayout();

        return root;
    }

    private void changeActionBarLayout()
    {
        try {
            this.optionMenu.findItem(R.id.actionbar_home_camera)
                .setVisible(false);
        } catch (NullPointerException e)
        {
            // e will be thrown at the first time MainActivity is called
        }       
    }
}

Tab2Fragment.java

public class Tab2Fragment extends BaseTabFragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        root = inflater.inflate(R.layout.tab2_layout, 
                container, false);


        this.changeActionBarLayout();

        return root;
    }

    private void changeActionBarLayout()
    {
        try {
            this.optionMenu.findItem(R.id.actionbar_home_camera)
                .setVisible(true);
        // Camera Icon still doesn't appear on ActionBar even when I set it as SHOW_AS_ACTION_ALWAYS
        this.optionMenu.findItem(R.id.actionbar_home_camera)
            .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
        } catch (NullPointerException e)
        {
            // e will be thrown at the first time MainActivity is called
        }       
    }   
}

Upvotes: 3

Views: 3034

Answers (4)

Alessandro Roaro
Alessandro Roaro

Reputation: 4733

I had the same problem and I found out that setVisible(true) works when there is at least another MenuItem visible. I hope this can be helpful to someone.

Upvotes: 0

Jeyhun Karimov
Jeyhun Karimov

Reputation: 1295

I faced the same problem and solved in this way:

Firstly I save the com.actionbarsherlock.view.Menu when onCreateOptionsMenu(Menu menu)

@Override
public boolean onCreateOptionsMenu ( Menu menu )
{
    ShowOrEditTaskActivity.this.getSupportMenuInflater().inflate(R.menu.edit_or_show_task_menu, menu);
    setOptionsMenu ( menu );
    optionsMenu.findItem ( R.id.save_action ).setVisible ( false );
    return super.onCreateOptionsMenu ( menu ) ;
}

Then I check in every

public boolean onOptionsItemSelected ( MenuItem item )

call like this:

@Override
public boolean onOptionsItemSelected ( MenuItem item )
{
    if ( item.getItemId ( ) ==   R.id.edit_action  )
    {
        isEditMode ( true ) ;
        optionsMenu.findItem ( R.id.edit_action ).setVisible ( false );
        optionsMenu.findItem ( R.id.save_action ).setVisible ( true );
    }...

Hope this helps..

Upvotes: 0

kofi
kofi

Reputation: 200

I had the same problem and found an easy solution for it: Just implement onPreparePanel in your Activity and return true even if all items are invisible.

public class HomeActivity extends SherlockFragmentActivity {

    [...]

    @Override
    public boolean onPreparePanel(int featureId, View view, Menu menu) {
        super.onPreparePanel(featureId, view, menu); // this returns false if all items are hidden
        return true; // return true to prevent the menu's deletion 
    }

    [...]

}

Upvotes: 4

Leo
Leo

Reputation: 1443

After some investigation, I think this is a bug, but I don't know it's ActionBarSherlock's bug or Android ActionBar's bug.

Reason

The reason is because of there's ONLY ONE MenuItem in option menu, let's say the MenuItem is mItem. When I set mItem.setVisible(false), there will be no item left on ActionBar, then apparently, the space which contains ActionBar MenuItems is removed. After that, when I set mItem.setVisible(true), the space is not restored, in that case, my mItem is considered as an overflow MenuItem -> it's only revealed when use Menu hardware button of devices.

Solution

  • Use more than one MenuItem
  • Subtly, use combination of setEnable(false) and setIcon(null) and setTitle("") instead of setVisible(false)

Upvotes: 3

Related Questions