操作栏问题:使用SearchView后,列表模式导航不可见。

13

这个项目展示了一个bug:https://github.com/smarek/ActionBar-Navigation-Bug


b.android.com上的错误报告:http://code.google.com/p/android/issues/detail?id=51449


I'm currently facing an issue with ActionBar.
Let's have a ViewPager+PagerTitleStrip and 3 Fragments. User flow:
- Open application - First Fragment has set navigation mode to NAVIGATION_MODE_LIST - Other Fragments has NAVIGATION_MODE_STANDARD - All Fragments has options menu item with SearchView - Go to second or third and open search (click on search item) - Close search view or not (you can just swipe back to previous fragment) - Go to first fragment, and see, there is no NAVIGATION_MODE_LIST - On first fragment open search and close it - Navigation list is visible again
Adding just the code of MainActivity and layout the project is standard Android Application Project, minSdk 11, when creating main activity, select blank activity and swipe views + title strip

layout/activity_main.xml

<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <!--
    This title strip will display the currently visible page title, as well as the page
    titles for adjacent pages.
    -->

    <android.support.v4.view.PagerTitleStrip
        android:id="@+id/pager_title_strip"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="top"
        android:background="#33b5e5"
        android:paddingBottom="4dp"
        android:paddingTop="4dp"
        android:textColor="#fff" />

</android.support.v4.view.ViewPager>

com/example/project/MainActivity.java

// imports ommited

public class MainActivity extends FragmentActivity {

    SectionsPagerAdapter mSectionsPagerAdapter;
    ViewPager mViewPager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mSectionsPagerAdapter = new SectionsPagerAdapter(
                getSupportFragmentManager());

        mViewPager = (ViewPager) findViewById(R.id.pager);
        mViewPager.setAdapter(mSectionsPagerAdapter);

    }

    public static class DummySectionFragment extends Fragment {

        public static final String ARG_SECTION_NUMBER = "section_number";
        public static final int MENU_SEARCH = -1;
        protected MenuItem searchItem;
        protected SearchView mSearchView;

        public DummySectionFragment() {
            setHasOptionsMenu(true);
        }

        /*
        * Initializing menu items, adding only searchItem (aka SearchView in actionview)
        */
        @Override
        public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
            mSearchView = new SearchView(getActivity().getActionBar()
                    .getThemedContext());
            searchItem = menu
                    .add(Menu.NONE, MENU_SEARCH, Menu.NONE, "Search")
                    .setIcon(android.R.drawable.ic_menu_search)
                    .setActionView(mSearchView)
                    .setShowAsActionFlags(
                            MenuItem.SHOW_AS_ACTION_ALWAYS
                                    | MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
            super.onCreateOptionsMenu(menu, inflater);
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
            TextView textView = new TextView(getActivity());
            textView.setGravity(Gravity.CENTER);
            textView.setText(Integer.toString(getArguments().getInt(
                    ARG_SECTION_NUMBER)));
            return textView;
        }

        // Using setUserVisibleHint to operate with actionbar
        // (navigation mode) and visibility of option menu items
        // if isVisibleToUser, we're doing setup for current Fragment
        @Override
        public void setUserVisibleHint(boolean isVisibleToUser) {
            super.setUserVisibleHint(isVisibleToUser);
            if (isVisibleToUser) {
                    // setting navigation mode according to fragment
                ActionBar ab = getActivity().getActionBar();
                int mode = 0;
                    // ARG_SECTION_NUMBER is argument with numbers 1, 2, 3
                switch (getArguments().getInt(ARG_SECTION_NUMBER)) {
                default:
                case 1:
                    mode = ActionBar.NAVIGATION_MODE_LIST;
                            // Simple adapter added to spinner, to be visible
                    ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<String>(
                            getActivity(),
                            android.R.layout.simple_spinner_dropdown_item,
                            new String[] { "A", "B", "C" });
                    ab.setListNavigationCallbacks(spinnerArrayAdapter,
                            new OnNavigationListener() {

                                @Override
                                public boolean onNavigationItemSelected(
                                        int itemPosition, long itemId) {
                                    return false;
                                }
                            });
                    break;
                case 2:
                case 3:
                    mode = ActionBar.NAVIGATION_MODE_STANDARD;
                    break;
                }
                getActivity().getActionBar().setNavigationMode(mode);
            } else {
                    // resetting navigation mode
                if (getActivity() != null
                        && getActivity().getActionBar() != null)
                    getActivity().getActionBar().setNavigationMode(
                            ActionBar.NAVIGATION_MODE_STANDARD);
            }
        }
    }

    public class SectionsPagerAdapter extends FragmentPagerAdapter {

        public SectionsPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public int getCount() {
            return 3;
        }

        @Override
        public Fragment getItem(int position) {
            Fragment fragment = new DummySectionFragment();
            Bundle args = new Bundle();
            args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, position + 1);
            fragment.setArguments(args);
            return fragment;
        }

        @Override
        public CharSequence getPageTitle(int position) {
            switch (position) {
            case 0:
                return getString(R.string.title_section1).toUpperCase();
            case 1:
                return getString(R.string.title_section2).toUpperCase();
            case 2:
                return getString(R.string.title_section3).toUpperCase();
            }
            return null;
        }
    }

}

我听说过一些有关在ViewPager中使用Fragment与操作栏不正确地协同的问题报告,所以我对你在这里遇到问题并不感到意外。请搜索http://b.android.com,看看是否有其他人报告了类似的行为。我还建议您上传一个完整的示例项目,以展示问题。 - CommonsWare
@CommonsWare 谢谢关注,我已经将整个项目上传到了Github,并在问题中提供了链接。目前我还没有找到类似的问题,但我会继续搜索。 - Marek Sebera
@CommonsWare:好消息,我有点担心问题只出现在我的设备上。现在剩下的就是找到原因,然后(如果可能的话)解决方法。 - Marek Sebera
如果所有的片段都有SearchView选项,也许你可以从Activity中添加它,而不是从Fragment中添加? - nicopico
@nicopico 这会有什么不同吗? - Marek Sebera
显示剩余4条评论
3个回答

5

Bug

我发帖只是为了指出这个问题的方向。

这个问题与SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW标志更相关。一旦删除该标志,一切都将完美地运行。这很可能是一个漏洞,但再次强调,我不确定是否有合理的解释。

解决方案(并不是真正的解决方案)

当您在onCreateOptionsMenu中创建菜单项时,请删除ORedMenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW

简单地说,将此更改为:

searchItem = menu
.add(Menu.NONE, MENU_SEARCH, Menu.NONE, "Search")
.setIcon(android.R.drawable.ic_menu_search)
.setActionView(mSearchView)
.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_ALWAYS
    | MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);

为了

searchItem = menu
.add(Menu.NONE, MENU_SEARCH, Menu.NONE, "Search")
.setIcon(android.R.drawable.ic_menu_search)
.setActionView(mSearchView)
.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_ALWAYS);

没有使用ViewPager的Bug

我已经fork了这个项目,并且去掉了ViewPager,行为方式与原版相同。请查看ActionBar-Navigation-Bug


@MarekSebera 你有没有尝试在你自己的项目中使用他的解决方案? - PravinCG
1
@MarekSebera 感谢您的更新,这确保了其他人不会浪费时间尝试这个。 - PravinCG
@SherifelKhatib 哦,它在特定条件下可以工作,我会调查并回复你的,但另一方面,搜索视图在扩展时没有填满操作栏的整个宽度。 - Marek Sebera
这个解决方法修复了该缺陷,但似乎也改变了“后退”按钮的行为。 - Learn OpenGL ES

4

当SearchView设置了SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW标志时,我遇到了类似的问题。我的解决方法是在切换到NAVIGATION_MODE_LIST后展开和折叠SearchView的MenuItem:

actionBar.setNavigationMode( ActionBar.NAVIGATION_MODE_LIST );
actionBar.setDisplayShowTitleEnabled( false );
searchMenuItem.expandActionView();
searchMenuItem.collapseActionView();

虽然有点脏,但对我来说还是起到了作用。

顺便说一下...同样的错误和解决方案也适用于ActionBarSherlock。


@Moritz 这个解决方法在执行时会导致快速的 Galaxy S4 打开键盘。手动关闭无效。 - Lazy Beard
这个对我有效。我关注了Lazy Beard的评论,但是我注意到这个错误在我的4.4版本上不会发生,所以我将解决方法排除在4.2和以下版本之外。 - Learn OpenGL ES
澄清一下,对我来说,这个错误在4.3上也没有发生。 - Learn OpenGL ES

0
这是我绕过这个bug的方法:
首先,我在Activity中将MenuItem定义为全局变量:
private  MenuItem searchItem;

在这个活动中,我有以下方法:
public void hideSearch() 
{
     MenuItemCompat.collapseActionView(searchItem);
} 

在该片段的onCreateView()方法中,在返回视图之前,我调用了这个方法。我的下拉菜单随后停止被隐藏。说实话,我不确定为什么它起作用,但对我来说确实起作用了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接