用Fragments进行Androidsearch

有人知道如何使用Fragment s实现标准Androidsearch界面的教程或例子吗? 换句话说,是否有可能把一个标准的search与SearchManager在一个片段?

总之,你不能。 在Fragment创buildsearch界面是不可能的。

  1. 创build可search的界面时,您必须在Android清单中指定一个默认的“可search的活动”。 我相信你知道,没有父ActivityFragment就不能存在,因此,这种分离是不可能的。

  2. 如果你已经知道了#1,我想你问了这个问题,希望有一些神奇的“黑客”可以完成工作。 但是,文件指出,

    当用户在search对话框或窗口小部件中执行search时,系统将启动您的可search活动,并使用ACTION_SEARCH操作以Intent的forms提供search查询。 您的可search活动从意图的QUERY附加项中检索查询,然后search您的数据并显示结果。

    负责提供search结果的内部系统需要一个Activity ,而不是一个Fragment ; 因此,实现一个完全独立于Activity的search接口是不可能的,因为它需要改变底层系统本身 。 查看SearchableInfo类的源代码,如果你不相信我:)。

这就是说,看起来似乎并不太难实现类似于你所描述的东西。 例如,你可能会考虑实现你的searchable-Activity,以便它接受android.intent.action.SEARCH意图,而不是立即在一个ListView显示结果,例如)将search查询传递给你的Fragment 。 例如,考虑以下可search的活动:

 public class SearchableActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (Intent.ACTION_SEARCH.equals(getIntent().getAction())) { String query = intent.getStringExtra(SearchManager.QUERY); doMySearch(query); } } /** * Performs a search and passes the results to the container * Activity that holds your Fragments. */ public void doMySearch(String query) { // TODO: implement this } } 

当发出search请求时,系统将启动您的可search活动,执行查询,并将结果传递给某个容器活动(基于您的doMySearch实现)。 容器活动然后将这些结果传递到包含的可searchFragment ,在其中显示结果。 实现需要比您希望的更多的工作,但是我确信有一些方法可以使它更加模块化,而且看起来这可能是您可以做的最好的。

ps如果您使用这种方法,您可能需要特别注意哪些活动被添加/移除到了后台。 看到这个职位的一些更多的信息如何做到这一点。

pps你也可能完全忘记了标准的search界面,只是在一个Fragment内实现一个简单的search,如下面的Raghav的post所述

这里是使用片段search的例子。 希望它有帮助,这是你在找什么:

 public class LoaderCursor extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); FragmentManager fm = getFragmentManager(); // Create the list fragment and add it as our sole content. if (fm.findFragmentById(android.R.id.content) == null) { CursorLoaderListFragment list = new CursorLoaderListFragment(); fm.beginTransaction().add(android.R.id.content, list).commit(); } } public static class CursorLoaderListFragment extends ListFragment implements OnQueryTextListener, LoaderManager.LoaderCallbacks<Cursor> { // This is the Adapter being used to display the list's data. SimpleCursorAdapter mAdapter; // If non-null, this is the current filter the user has provided. String mCurFilter; @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); // Give some text to display if there is no data. In a real // application this would come from a resource. setEmptyText("No phone numbers"); // We have a menu item to show in action bar. setHasOptionsMenu(true); // Create an empty adapter we will use to display the loaded data. mAdapter = new SimpleCursorAdapter(getActivity(), android.R.layout.simple_list_item_2, null, new String[] { Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS }, new int[] { android.R.id.text1, android.R.id.text2 }, 0); setListAdapter(mAdapter); // Start out with a progress indicator. setListShown(false); // Prepare the loader. Either re-connect with an existing one, // or start a new one. getLoaderManager().initLoader(0, null, this); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { // Place an action bar item for searching. MenuItem item = menu.add("Search"); item.setIcon(android.R.drawable.ic_menu_search); item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); SearchView sv = new SearchView(getActivity()); sv.setOnQueryTextListener(this); item.setActionView(sv); } public boolean onQueryTextChange(String newText) { // Called when the action bar search text has changed. Update // the search filter, and restart the loader to do a new query // with this filter. mCurFilter = !TextUtils.isEmpty(newText) ? newText : null; getLoaderManager().restartLoader(0, null, this); return true; } @Override public boolean onQueryTextSubmit(String query) { // Don't care about this. return true; } @Override public void onListItemClick(ListView l, View v, int position, long id) { // Insert desired behavior here. Log.i("FragmentComplexList", "Item clicked: " + id); } // These are the Contacts rows that we will retrieve. static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] { Contacts._ID, Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS, Contacts.CONTACT_PRESENCE, Contacts.PHOTO_ID, Contacts.LOOKUP_KEY, }; public Loader<Cursor> onCreateLoader(int id, Bundle args) { // This is called when a new Loader needs to be created. This // sample only has one Loader, so we don't care about the ID. // First, pick the base URI to use depending on whether we are // currently filtering. Uri baseUri; if (mCurFilter != null) { baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, Uri.encode(mCurFilter)); } else { baseUri = Contacts.CONTENT_URI; } // Now create and return a CursorLoader that will take care of // creating a Cursor for the data being displayed. String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND (" + Contacts.HAS_PHONE_NUMBER + "=1) AND (" + Contacts.DISPLAY_NAME + " != '' ))"; return new CursorLoader(getActivity(), baseUri, CONTACTS_SUMMARY_PROJECTION, select, null, Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"); } public void onLoadFinished(Loader<Cursor> loader, Cursor data) { // Swap the new cursor in. (The framework will take care of closing the // old cursor once we return.) mAdapter.swapCursor(data); // The list should now be shown. if (isResumed()) { setListShown(true); } else { setListShownNoAnimation(true); } } public void onLoaderReset(Loader<Cursor> loader) { // This is called when the last Cursor provided to onLoadFinished() // above is about to be closed. We need to make sure we are no // longer using it. mAdapter.swapCursor(null); } } } 

使用标准的ActionBar SearchView ActionView API来search片段是非常有可能的。 这将使用AppCompat支持类v7,回到Android 2.1(API级别7)。

在你的片段中:

 @Override public void onCreateOptionsMenu (Menu menu, MenuInflater inflater){ inflater.inflate(R.menu.search, menu); MenuItem item = menu.findItem(R.id.action_search); SearchView sv = new SearchView(((YourActivity) getActivity()).getSupportActionBar().getThemedContext()); MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW | MenuItemCompat.SHOW_AS_ACTION_IF_ROOM); MenuItemCompat.setActionView(item, sv); sv.setOnQueryTextListener(new OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String query) { System.out.println("search query submit"); return false; } @Override public boolean onQueryTextChange(String newText) { System.out.println("tap"); return false; } }); } 

在你的菜单XML中

 <item android:id="@+id/action_search" android:icon="@drawable/ic_action_search" android:title="Search Waste Items" android:showAsAction="ifRoom|collapseActionView" nz.govt.app:actionViewClass="android.support.v7.widget.SearchView" nz.govt.app:showAsAction="ifRoom|collapseActionView" /> 

使用AppCompat支持类v7。 只需在@Rookie解决scheme中添加一些@David的解决scheme,以简单的方式正常工作,以下是我的片段代码:

MyFragment

 public class MyFragment extends Fragment implements SearchView.OnQueryTextListener { @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); // What i have added is this setHasOptionsMenu(true); } @Override public void onCreateOptionsMenu (Menu menu, MenuInflater inflater) { //inflater.inflate(R.menu.main, menu); // removed to not double the menu items MenuItem item = menu.findItem(R.id.action_search); SearchView sv = new SearchView(((MainActivity) getActivity()).getSupportActionBar().getThemedContext()); MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW | MenuItemCompat.SHOW_AS_ACTION_IF_ROOM); MenuItemCompat.setActionView(item, sv); sv.setOnQueryTextListener(this); sv.setIconifiedByDefault(false); sv.setOnSearchClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Utils.LogDebug("Clicked: "); } }); MenuItemCompat.setOnActionExpandListener(item, new MenuItemCompat.OnActionExpandListener() { @Override public boolean onMenuItemActionCollapse(MenuItem item) { // Do something when collapsed Utils.LogDebug("Closed: "); return true; // Return true to collapse action view } @Override public boolean onMenuItemActionExpand(MenuItem item) { // Do something when expanded Utils.LogDebug("Openeed: "); return true; // Return true to expand action view } }); super.onCreateOptionsMenu(menu,inflater); } @Override public boolean onQueryTextSubmit(String query) { Utils.LogDebug("Submitted: "+query); return true; } @Override public boolean onQueryTextChange(String newText) { Utils.LogDebug("Changed: "+newText); return false; } } 

我添加了onActivityCreated ,因为没有调用setHasOptionsMenu(true); 系统将不知道这个片段需要与菜单进行交互。

然后我删除了行inflater.inflate(R.menu.main, menu); 因为活动膨胀了一个菜单,所以菜单项翻了一倍,然后Fragment膨胀了另一个菜单

感谢@David和@Rookie

使用Fragments ,仍然需要使用Activity来控制和分配Fragments 。 此Activity可以像以前一样具有searchfunction。

我最近从一个“普通”的基于Activity的应用程序切换到基于Fragment的应用程序,searchfunction对我来说也是一样的。

你有没有尝试过,并没有成功? 如果是的话,请提供一些更详细的问题。

编辑:

如果您想要进行特定于片段的search,请让所有Fragments使用startSearch方法扩展接口MyFragment ,并让您的ActivitystartSearch方法调用当前片段的startSearch方法。

我想我已经实现了:你可以实际使用片段,并将一个search图标添加到一个操作栏,以便在片段内进行search。 诀窍是使用一个动作栏,一个动作视图,一个监听器,一个加载器和一个适配器。

尽pipe它完全绕过了android平台的search机制,但是它可以完成一些工作来find@Alex Lockwood描述的内容并将search传递给片段。 它不会像预期的那样在一个活动的情况下作出反应,但它是有效的:用户可以在片段中search。

这里是代码:

SearchInFragmentActivity

 package com.sof.test.searchfragment; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; import android.view.View; import com.actionbarsherlock.app.ActionBar; import com.actionbarsherlock.app.ActionBar.Tab; import com.actionbarsherlock.app.ActionBar.TabListener; import com.actionbarsherlock.app.SherlockFragmentActivity; import com.sof.test.searchfragment.SearchFragment; import com.sof.test.R; public class SearchInFragmentActivity extends SherlockFragmentActivity implements TabListener { private SearchFragment tab1 = new SearchFragment(); private SearchFragment tab2 = new SearchFragment(); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView( R.layout.search_in_fragments ); getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); createTab( R.string.tab1, R.drawable.ic_menu_search ); createTab( R.string.tab2, R.drawable.ic_menu_search ); getSupportActionBar().setSelectedNavigationItem( 0 ); invalidateOptionsMenu(); } private void createTab(int tabNameResId, int tabIconResId) { ActionBar.Tab tab = getSupportActionBar().newTab(); tab.setText( tabNameResId ); tab.setTabListener(this); getSupportActionBar().addTab(tab); }// met @Override public void onTabSelected(Tab tab, FragmentTransaction ft) { if( ft == null ) { return; }//if View fragmentSlot = findViewById( R.id.fragment ); Fragment newFragment = null; if( fragmentSlot != null ) { newFragment = (tab.getPosition() == 0) ? tab1 : tab2; ft.replace(R.id.fragment, newFragment ); ft.setTransition( FragmentTransaction.TRANSIT_FRAGMENT_FADE); }//if } @Override public void onTabUnselected(Tab tab, FragmentTransaction ft) { } @Override public void onTabReselected(Tab tab, FragmentTransaction ft) { } }//class 

片段类SearchFragment(我在上面的活动中使用了2个实例)。

 package com.sof.test.searchfragment; import java.util.ArrayList; import java.util.List; import android.content.Context; import android.os.Bundle; import android.support.v4.app.LoaderManager.LoaderCallbacks; import android.support.v4.content.AsyncTaskLoader; import android.support.v4.content.Loader; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.SearchView; import android.widget.TextView; import com.sof.test.R; import com.actionbarsherlock.app.SherlockListFragment; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuInflater; public class SearchFragment extends SherlockListFragment { private StringLoader loader = null; private StringAdapter adapter = null; private List<String> listData = new ArrayList<String>(); private String query; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = super.onCreateView(inflater, container, savedInstanceState); createListData(); loader = new StringLoader( getActivity(), this ); adapter = new StringAdapter(listData); setListAdapter(adapter); getLoaderManager().initLoader(0, null, new LoaderCallBacks() ); loader.forceLoad(); setHasOptionsMenu( true ); return view; } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater ) { super.onCreateOptionsMenu(menu, inflater); inflater.inflate( R.menu.menu_search, menu); System.out.println( "inflating menu"); final SearchView searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView(); final SearchView.OnQueryTextListener queryTextListener = new SearchView.OnQueryTextListener() { @Override public boolean onQueryTextChange(String newText) { showFilteredItems( newText ); return true; } @Override public boolean onQueryTextSubmit(String query) { return true; } }; searchView.setOnQueryTextListener(queryTextListener); return; }//met private void showFilteredItems( String query ) { this.query = query; loader.onContentChanged(); } private void createListData() { for( int i = 0; i < 100 ; i ++ ) { listData.add( "String "+ i ); } } public List<String> getData() { List<String> listFilteredData = new ArrayList<String>(); for( String string : listData ) { if( query == null || string.contains( query ) ) { listFilteredData.add( string ); } } return listFilteredData; }//met private class LoaderCallBacks implements LoaderCallbacks< List<String>> { @Override public void onLoadFinished(Loader<List<String>> loader, List<String> listData) { adapter.setListData( listData ); }// met @Override public void onLoaderReset(Loader<List<String>> listData) { adapter.setListData( new ArrayList<String>() ); }// met @Override public Loader<List<String>> onCreateLoader(int arg0, Bundle arg1) { return loader; }// met }//class private class StringAdapter extends ArrayAdapter< String > { private List<String> listDataToDisplay = new ArrayList<String>(); private LayoutInflater mInflater; public StringAdapter( List<String> listData ) { super( getActivity(), android.R.layout.simple_list_item_1, android.R.id.text1, listData ); listDataToDisplay = listData; mInflater = (LayoutInflater)getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); }//cons private void setListData( List<String> newListData ) { this.listDataToDisplay.clear(); this.listDataToDisplay.addAll( newListData ); notifyDataSetChanged(); }//met /** * Populate new items in the list. */ @Override public View getView(int position, View convertView, ViewGroup parent) { View view; if (convertView == null) { view = mInflater.inflate(android.R.layout.simple_list_item_1, parent, false); } else { view = convertView; } ((TextView)view.findViewById( android.R.id.text1)).setText( listDataToDisplay.get( position ) ); return view; } }//inner class }//class class StringLoader extends AsyncTaskLoader<List<String>> { SearchFragment fragment = null; public StringLoader(Context context, SearchFragment fragment) { super(context); this.fragment = fragment; }// cons @Override public List<String> loadInBackground() { return fragment.getData(); }// met }// class 

search片段菜单的XML文件res / menu / menu_search.xml:

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:baselineAligned="false" android:orientation="horizontal" > <FrameLayout android:id="@+id/fragment" android:layout_width="0px" android:layout_height="match_parent" android:layout_weight="1" /> </LinearLayout> 

和XML布局文件res / layout / search_in_fragments.xml

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:baselineAligned="false" android:orientation="horizontal" > <FrameLayout android:id="@+id/fragment" android:layout_width="0px" android:layout_height="match_parent" android:layout_weight="1" /> </LinearLayout> 

使用ActionBarSearchView 。 您将能够处理没有任何活动连接的search。 只要设置一个OnQueryTextListener到SearchView。

 MenuItem item = menu.add("Search"); SearchView sv = new SearchView(getActionBar().getThemedContext()); item.setActionView(sv); item.setIcon(R.drawable.ic_search); item.setShowAsAction(MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW | MenuItem.SHOW_AS_ACTION_IF_ROOM); sv.setOnQueryTextListener(new OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String query) { //... return false; } @Override public boolean onQueryTextChange(String newText) { //... return false; } }); 

看到这个职位关于自定义search的更多细节。

Fragment不能存在于Activity之外,也不能将Fragment链接到android.intent.action.SEARCH或任何其他intent-filter

因此,如果不使用Activity来包装Fragment ,您所要求的是不可能的。

在碎片进入ViewPager的情况下,我可以通过阻止searchbutton,当我不在我想给一个search栏的片段。 进入活动:

 @Override public boolean onSearchRequested() { if (mPager.getCurrentItem() == mAdapter.getPosition(FragmentType.VIDEO)) return super.onSearchRequested(); else return false; } 

而在没有物理searchbutton的情况下,我添加了一个行动项目的片段,这将触发此代码:

 @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == R.id.search_item) { return getSherlockActivity().onSearchRequested(); } return super.onOptionsItemSelected(item); } 

别人的解决scheme…..我不喜欢那样。 这对我来说比较容易,但是我的想法,等待你的意见

 public interface SearchImpl { public void searchQuery(String val); } 

分段

 public class MyFragment extends Fragment implements SearchImpl { View view; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { view = inflater.inflate(R.layout.fragment_almanca, container, false); return view; } @Override public void searchQuery(String val) { Log.e("getted", val); } } 

Acitivty

  @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); SearchView searchView = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.action_search)); searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String query) { Log.e("setted", "" + query); try { MyFragment myFGM=new MyFragment(); myFGM.searchQuery(query); } catch (Exception e) { e.printStackTrace(); } return false; } @Override public boolean onQueryTextChange(String newText) { return false; } }); return super.onCreateOptionsMenu(menu); } 

是的,

请在您的Activity上实现Search视图,Activity中的onQueryTextChange也会侦听片段中的search,您可以在'onQueryTextChange'中检查片段的可见性,如果可见,您可以调用您的search方法来获取片段,

我发现了一个工作:)你可以在你的BaseActivity中覆盖这个方法(startActivity(Intent)),然后检查这个动作是否是ACTION_SEARCH然后做你的特殊工作:D

 @Override public void startActivity(Intent intent) { try { if (intent.getAction().equals(Intent.ACTION_SEARCH)) toast("hello"); } catch (Exception e) { } }