在ListFragment中实现Android Actionbar搜索小部件

20

我的应用程序目前在左侧设置了一个ListFragment,右侧设置了一个DetailsFragment(类似于下面平板电脑的布局)。

layout

我在操作栏上添加了一个搜索小部件,当提交搜索词时,应更新列表的内容(在ListFragment中)。 我一直在遵循Android开发者指南中的搜索指南 (http://developer.android.com/guide/topics/search/search-dialog.html),但是我无法使搜索在同一活动中更新列表。

我已经通过在提交搜索词时调用新的Activity来实现某种形式的实现,但这会使返回按钮表现奇怪(即单击返回按钮后,您会回到先前的Activity,但搜索小部件仍显示搜索词)。

我已将意图行添加到清单中,如下所示。

<intent-filter>
        <action android:name="android.intent.action.SEARCH" />
    </intent-filter>
    <meta-data android:name="android.app.searchable"
               android:resource="@xml/searchable"/>

搜索小部件是否可以更新当前活动的列表?

1个回答

46

是的,事实上,那是“正常”的使用情况。您需要记住的是,使用搜索操作栏小部件的片段应该是通常注册它的部分,因为该小部件将随着该片段而被销毁。

以下是正确绑定的方法:

在您的ListFragment中让其知道您有选项菜单项...

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    ..
    setHasOptionsMenu(true);
    ..
}

然后在同一个ListFragment内,通过重写回调函数创建选项菜单。一旦您获得了SearchView小部件的引用,请注册一个QueryTextListener回调函数:

@Override 
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    inflater.inflate(R.menu.grid_default, menu); 
    SearchView searchView = (SearchView)menu.findItem(R.id.grid_default_search).getActionView();
    searchView.setOnQueryTextListener(queryListener);
}

您可以通过编程方式(Java)或声明方式(XML)创建搜索小部件,这里是XML示例(命名为grid_default.xml,来自上面的内容):

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

    <item     
        android:id="@+id/grid_default_search"
        android:icon="@android:drawable/ic_menu_search"
        android:title="search"
        android:showAsAction="always"
        android:actionViewClass="android.widget.SearchView" 
    />

    <!-- other items or whatever  -->

</menu>

现在回到你的ListFragment,你需要创建我们之前注册的queryListener

private String grid_currentQuery = null; // holds the current query...

final private OnQueryTextListener queryListener = new OnQueryTextListener() {       

    @Override
    public boolean onQueryTextChange(String newText) {
        if (TextUtils.isEmpty(newText)) {
            getActivity().getActionBar().setSubtitle("List");               
            grid_currentQuery = null;
        } else {
            getActivity().getActionBar().setSubtitle("List - Searching for: " + newText);
            grid_currentQuery = newText;

        }   
        getLoaderManager().restartLoader(0, null, MyListFragment.this); 
        return false;
    }

    @Override
    public boolean onQueryTextSubmit(String query) {            
        Toast.makeText(getActivity(), "Searching for: " + query + "...", Toast.LENGTH_SHORT).show();
        return false;
    }
};

现在你知道当查询被更改或提交时的情况了,在我的示例中,每当按键被按下,我会重新查询,因为我的数据库非常小而且结果很快,你可能需要更改它.. 但是你会注意到我只是使用小部件将当前搜索小部件的文本(grid_currentQuery)设置为私有类字段(ListFragment),然后我只是调用getLoaderManager().restartLoader(0, null, MyListFragment.this);,在我的onCreateLoader内部,我只是像这样更新所使用的查询:

@Override
public Loader<Cursor> onCreateLoader(int id, Bundle bargs) {

    String sort = "SortColumn ASC";
    String[] grid_columns = new String[] { "ColumnA", "ColumnB", "Etc..." };
    String grid_whereClause = "ColumnToSearchBy LIKE ?"

    if (!TextUtils.isEmpty(grid_currentQuery)) {            
        return new CursorLoader(getActivity(), DataProvider.CONTENT_URI, grid_columns, grid_whereClause, new String[] { grid_currentQuery + "%" }, sort);
    }       

    return new CursorLoader(getActivity(), DataProvider.CONTENT_URI, grid_columns, null, null, sort);
}

这就是你需要做的全部内容,我知道这有点零散,但是因为还有更多需要发生的事情,比如设置适配器、首先使用getLoaderManager().initLoader(0, null, this);启动加载器以及需要处理的所有其他加载器回调... 但如果你遵循Android开发者提出的最佳实践(在ListActivityListFragments中使用LoaderManager),那么这应该对你来说非常容易...

希望这可以帮助你,如果需要澄清,请随时在评论中提问-ck


@bencallis,你最好使用SearchView的setOnCloseListener(SearchView.OnCloseListener listener)方法... - ckozl
我刚刚在处理这个问题,但是遇到了一些困难。 searchView.setOnCloseListener(new OnCloseListener() { @Override public boolean onClose() { Toast.makeText(DealPadActivity.this, "Closed", Toast.LENGTH_SHORT).show(); Log.d("Search", "search closed");似乎没有被调用。 - bencallis
只有在单击“关闭”搜索时才会调用它,这对我来说很有效:searchView.setOnCloseListener(new OnCloseListener() { @Override public boolean onClose() { /* 这个很完美,你的问题可能出在其他地方 */ return false; } }); - ckozl
我的唯一问题是我不知道应该在DataProvider.CONTENT_URI上放什么。我正在使用一个预填充的sqlite数据库,将其复制到用户文件夹中,因此我没有每个表的类。我该怎么办? - Deses
getLoaderManager().restartLoader(0, null, MyListFragment.this); 这行代码给我报错了,我需要在一个ArrayList<String>中进行搜索。有没有一种方法可以设置适配器以在文本更改时显示建议? - Ashish Dwivedi
显示剩余6条评论

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