studio programacion para móviles libro edición desarrollo desarrollar curso aprende aplicaciones java android sqlite android-fragments android-searchmanager

java - programacion - Búsqueda de Android con Fragmentos



manual de programacion android pdf (12)

Al trabajar con Fragments , aún necesita usar una Activity para controlar y asignar los Fragments . Esta Activity puede tener la funcionalidad de búsqueda como antes.

Recientemente cambié de una aplicación basada en Activity "normal" a una aplicación basada en Fragment y la funcionalidad de búsqueda funcionó igual para mí.

¿Has intentado trabajar en ello y no has tenido éxito? Si es así, brinde más detalles en su pregunta.

EDITAR:

Si desea tener una búsqueda específica de fragmentos, MyFragment que todos sus Fragments extiendan una interfaz MyFragment con un método startSearch , y startSearch método startSearch su Activity startSearch método startSearch del fragmento actual.

¿Alguien sabe de un tutorial o un ejemplo de cómo implementar la interfaz de búsqueda estándar de Android con Fragment s? En otras palabras, ¿es posible poner una búsqueda estándar con un SearchManager en un Fragmento?


Aquí está el ejemplo para buscar algo utilizando fragmentos. Espero que ayude y esto es lo que estás buscando:

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); } } }


Creo que lo logré: puedes usar fragmentos y agregar un ícono de búsqueda a una barra de acción para que sea posible realizar una búsqueda dentro de los fragmentos. El truco es usar una barra de acción, una vista de acción, un oyente para ella, un cargador y un adaptador, por supuesto.

Esto funciona bastante bien, aunque evita completamente el mecanismo de búsqueda de plataforma de Android (pero podría completarse con un poco de trabajo para encontrar lo que @Alex Lockwood describe y pasar la búsqueda a fragmentos). No reaccionaría a un intento como se esperaba en el caso de una actividad, pero funciona: los usuarios pueden buscar dentro de fragmentos.

Aquí está el código:

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

La clase de fragmento SearchFragment (utilizo 2 instancias dentro de la actividad anterior).

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

El archivo xml para el menú de la búsqueda fragmenta 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>

Y el archivo de diseño 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>


En el caso de Fragmentos en una ViewPager, podría hacerlo bloqueando el botón de búsqueda cuando no estoy en el fragmento donde quiero dar una barra de búsqueda. En la actividad:

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

Y en caso de que no haya un botón de búsqueda física, agregué un elemento de acción en el fragmento, que desencadena este código:

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


En resumen, no puedes. Hay un par de razones por las cuales no es posible crear una interfaz de búsqueda dentro de un Fragment .

  1. Al crear una interfaz de búsqueda, debe especificar una "actividad de búsqueda" predeterminada en su manifiesto de Android. Como estoy seguro que sabes, un Fragment no puede existir sin una Activity principal y, por lo tanto, esta separación no es posible.

  2. Si ya descubrió el # 1, supongo que hizo esta pregunta con la esperanza de que haya algún truco mágico que pueda hacer el trabajo. Sin embargo, la documentación establece que,

    Cuando el usuario ejecuta una búsqueda en el cuadro de diálogo o widget de búsqueda, el sistema inicia su actividad de búsqueda y le entrega la consulta de búsqueda en un Intento con la acción ACTION_SEARCH. Su actividad de búsqueda recupera la consulta del QUERY extra del intento, luego busca sus datos y presenta los resultados.

    El sistema interno subyacente que es responsable de proporcionar resultados de búsqueda espera una Activity , no un Fragment ; por lo tanto, no es posible implementar una interfaz de búsqueda que sea completamente independiente de una Activity , ya que requeriría cambios en el sistema subyacente . Mira el código fuente de la clase SearchableInfo si no me crees :).

Dicho esto, no parece que sea demasiado difícil lograr algo similar a lo que está describiendo. Por ejemplo, podría considerar implementar su Actividad de búsqueda para que acepte el intento android.intent.action.SEARCH y (en lugar de mostrar inmediatamente los resultados en un ListView , por ejemplo) pasará la consulta de búsqueda a su Fragment . Por ejemplo, considere la siguiente actividad de búsqueda:

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 } }

Cuando se realiza una solicitud de búsqueda, el sistema iniciará su actividad de búsqueda, realizará la consulta y pasará los resultados a alguna actividad de contenedor (en función de su implementación de doMySearch ). La Actividad del contenedor pasará estos resultados al Fragment búsqueda contenido, en el que se mostrarán los resultados. La implementación requiere un poco más de trabajo de lo que probablemente estabas esperando, pero estoy seguro de que hay formas en que puedes hacerlo más modular, y parece que esto podría ser lo mejor que puedes hacer.

ps Si utiliza este enfoque, es posible que deba prestar especial atención a qué actividades se agregan / quitan a la backstack. Consulte esta post para obtener más información sobre cómo se puede hacer esto.

pps. También puede olvidarse por completo de la interfaz de búsqueda estándar e implementar una búsqueda simple dentro de un Fragment como se describe en la publicación de Raghav a continuación .


Es bastante posible buscar en un fragmento utilizando la API ActionView SearchView ActionView estándar. Esto también funcionará con Android 2.1 (API nivel 7) usando las clases de soporte de AppCompat v7.

En tu fragmento:

@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; } }); }

En tu menú 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" />


Un Fragment no puede existir fuera de una Activity , ni un Fragment puede estar vinculado a un android.intent.action.SEARCH o cualquier otro intent-filter .

Entonces, sin usar una Activity para envolver el Fragment , lo que estás preguntando no es posible.


Use la ActionBar y ActionBar . Podrá gestionar búsquedas sin ninguna conexión con la Actividad. Simplemente configure OnQueryTextListener para OnQueryTextListener .

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; } });

Consulte this publicación para obtener más detalles sobre la búsqueda personalizada.


Uso de las clases de soporte de AppCompat v7. Simplemente agregando algo a la solución de @David de la solución @Rookie para que funcione correctamente de una manera simple, aquí está mi código de fragmento:

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 el onActivityCreated , primo sin llamar a setHasOptionsMenu(true); el sistema no sabrá que este fragmento necesita interactuar con el menú.

luego inflater.inflate(R.menu.main, menu); la línea inflater.inflate(R.menu.main, menu); porque duplicó los elementos del menú porque la Actividad infló un menú, luego Fragmento infló otro menú

Gracias a @David y @Rookie


encontré un trabajo :) Puedes anular este método (startActivity (Intent)) en tu BaseActivity y luego verificar si la acción es ACTION_SEARCH y luego hacer tu trabajo especial: D

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


la otra solución ... no me gusta eso. Esto es más fácil para mí. Pero es mi idea. Estoy esperando tu opinión.

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

Fragmento

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); } }

Acitividad

@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); }


si es posible,

implementa Activity Search en tu Activity, ''onQueryTextChange'' en Activity también escuchará la búsqueda en fragmento, puedes verificar la visibilidad del fragmento en ''onQueryTextChange'', si está visible puedes llamar a tu método de búsqueda para fragmentar, funciona perfectamente en mi código