Android Spinner Search Example
Hola amigos vamos a crear un tutorial sobre un
Spinner Search en nuestra aplicaciones. Para ello deben seguir paso a paso como crear un
Spinner Search en
Android.
|
Como crear un Spinner buscador de palabras en Android |
Crear un Proyecto Android (Aquí)
Vamos a crear nuestro proyecto para desarrollar este ejemplo sobre el
Spinner Search para tener una idea mas clara de como utilizarlo en nuestras aplicaciones
Android.
|
Crear un proyecto Spinner Search en Android |
Crear Diseño Spinner utilizando Buscador
Vamos a crear el diseño de nuestra aplicación para ver como va a quedar nuestro
Spinner utilizando un buscador de palabras.
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.hn.universoandroid.example_spinnersearch.SearchableSpinner
android:id="@+id/spinner"
android:layout_width="match_parent"
android:layout_height="40dp"
android:entries="@array/animes"
android:layout_margin="10dp"
android:layout_centerInParent="true"
app:hintText="Elige tu anime favorito!"/>
</RelativeLayout>
</android.support.constraint.ConstraintLayout>
El diseño nos quedara de la siguiente manera.
|
Diseño de nuestro Spinner buscador en Android View |
Ahora vamos a continuar con otros detalles del diseño y agregaremos una lista de palabras en nuestro archivo
String.xml crearemos un
String de tipo
Array para contener nuestras palabras y las que estarán asignadas a nuestro
Spinner Search.
<resources>
<string name="app_name">Spinner Search Android</string>
<string-array name="animes">
<item>Black Jack</item>
<item>Naruto Shippuden</item>
<item>Dragon Ball</item>
<item>Pokemon</item>
<item>Digimon</item>
<item>Samurai X</item>
<item>Berserk</item>
</string-array>
</resources>
Y esta seria nuestra lista que mostrara nuestro
Spinner y con el cual podremos buscar las palabras claves. Ahora añadiremos un archivo xml a nuestra carpeta Values. Y le pondremos attrs.xml.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="SearchableSpinner">
<attr name="hintText" format="string"/>
</declare-styleable>
</resources>
Y con esto quedaría listo nuestro diseño.
Crear el código de nuestro Spinner buscador en Android
Ahora vamos a crear el código para nuestro ejemplo utilizando el
Spinner con un buscador de palabras y nos dirigiremos a nuestros paquetes donde estan las clases Java.
Añadiremos una clase y le pondremos
SearchableListDialog ha esta clase le vamos a dar un
Extends de tipo
DialogFragment y añadiremos las siguientes
implementaciones de clases
SearchView.OnQueryTextListener, SearchView.OnCloseListener que seran las encargadas de ejecutar los eventos del
SearchView en nuestro
Spinner.
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.app.SearchManager;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.SearchView;
import java.io.Serializable;
import java.util.List;
public class SearchableListDialog extends DialogFragment implements
SearchView.OnQueryTextListener, SearchView.OnCloseListener {
private static final String ITEMS = "items";
private ArrayAdapter listAdapter;
private ListView _listViewItems;
private SearchableItem _searchableItem;
private OnSearchTextChanged _onSearchTextChanged;
private SearchView _searchView;
private String _strTitle;
private String _strPositiveButtonText;
private DialogInterface.OnClickListener _onClickListener;
public SearchableListDialog() {
}
public static SearchableListDialog newInstance(List items) {
SearchableListDialog multiSelectExpandableFragment = new
SearchableListDialog();
Bundle args = new Bundle();
args.putSerializable(ITEMS, (Serializable) items);
multiSelectExpandableFragment.setArguments(args);
return multiSelectExpandableFragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams
.SOFT_INPUT_STATE_HIDDEN);
return super.onCreateView(inflater, container, savedInstanceState);
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Getting the layout inflater to inflate the view in an alert dialog.
LayoutInflater inflater = LayoutInflater.from(getActivity());
// Crash on orientation change #7
// Change Start
// Description: As the instance was re initializing to null on rotating the device,
// getting the instance from the saved instance
if (null != savedInstanceState) {
_searchableItem = (SearchableItem) savedInstanceState.getSerializable("item");
}
// Change End
View rootView = inflater.inflate(R.layout.searchable_list_dialog, null);
setData(rootView);
AlertDialog.Builder alertDialog = new AlertDialog.Builder(getActivity());
alertDialog.setView(rootView);
String strPositiveButton = _strPositiveButtonText == null ? "CLOSE" : _strPositiveButtonText;
alertDialog.setPositiveButton(strPositiveButton, _onClickListener);
String strTitle = _strTitle == null ? "Select Item" : _strTitle;
alertDialog.setTitle(strTitle);
final AlertDialog dialog = alertDialog.create();
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams
.SOFT_INPUT_STATE_HIDDEN);
return dialog;
}
// Crash on orientation change #7
// Change Start
// Description: Saving the instance of searchable item instance.
@Override
public void onSaveInstanceState(Bundle outState) {
outState.putSerializable("item", _searchableItem);
super.onSaveInstanceState(outState);
}
// Change End
public void setTitle(String strTitle) {
_strTitle = strTitle;
}
public void setPositiveButton(String strPositiveButtonText) {
_strPositiveButtonText = strPositiveButtonText;
}
public void setPositiveButton(String strPositiveButtonText, DialogInterface.OnClickListener onClickListener) {
_strPositiveButtonText = strPositiveButtonText;
_onClickListener = onClickListener;
}
public void setOnSearchableItemClickListener(SearchableItem searchableItem) {
this._searchableItem = searchableItem;
}
public void setOnSearchTextChangedListener(OnSearchTextChanged onSearchTextChanged) {
this._onSearchTextChanged = onSearchTextChanged;
}
private void setData(View rootView) {
SearchManager searchManager = (SearchManager) getActivity().getSystemService(Context
.SEARCH_SERVICE);
_searchView = (SearchView) rootView.findViewById(R.id.search);
_searchView.setSearchableInfo(searchManager.getSearchableInfo(getActivity().getComponentName
()));
_searchView.setIconifiedByDefault(false);
_searchView.setOnQueryTextListener(this);
_searchView.setOnCloseListener(this);
_searchView.clearFocus();
InputMethodManager mgr = (InputMethodManager) getActivity().getSystemService(Context
.INPUT_METHOD_SERVICE);
mgr.hideSoftInputFromWindow(_searchView.getWindowToken(), 0);
List items = (List) getArguments().getSerializable(ITEMS);
_listViewItems = (ListView) rootView.findViewById(R.id.listItems);
//create the adapter by passing your ArrayList data
listAdapter = new ArrayAdapter(getActivity(), android.R.layout.simple_list_item_1,items); //attach the adapter to the list
_listViewItems.setAdapter(listAdapter);
_listViewItems.setTextFilterEnabled(true);
_listViewItems.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
_searchableItem.onSearchableItemClicked(listAdapter.getItem(position), position);
getDialog().dismiss();
}
});
}
@Override
public boolean onClose() {
return false;
}
@Override
public boolean onQueryTextSubmit(String s) {
_searchView.clearFocus();
return true;
}
@Override
public boolean onQueryTextChange(String s) {
//listAdapter.filterData(s);
if (TextUtils.isEmpty(s)) {
//listViewItems.clearTextFilter();
((ArrayAdapter) _listViewItems.getAdapter()).getFilter().filter(null);
} else {
((ArrayAdapter) _listViewItems.getAdapter()).getFilter().filter(s);
}
if (null != _onSearchTextChanged) {
_onSearchTextChanged.onSearchTextChanged(s);
}
return true;
}
public interface SearchableItem<T> extends Serializable {
void onSearchableItemClicked(T item, int position);
}
public interface OnSearchTextChanged {
void onSearchTextChanged(String strText);
}
}
Ahora continuamos con la clase principal de nuestro
Spinner utilizando un buscador de palabras. Le pondremos
SearchableSpinner a nuestra clase y le vamos a dar un
Extends de la clase
Spinner y le implementaremos la clase
View.OnTouchListener.
import android.app.Activity;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.res.TypedArray;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.SpinnerAdapter;
import android.widget.Toast
import java.util.ArrayList;
import java.util.List;
public class SearchableSpinner extends android.support.v7.widget.AppCompatSpinner implements View.OnTouchListener,
SearchableListDialog.SearchableItem {
String selectedItem;
//this string above will store the value of selected item.
public static final int NO_ITEM_SELECTED = -1;
private Context _context;
private List _items;
private SearchableListDialog _searchableListDialog;
private boolean _isDirty;
private ArrayAdapter _arrayAdapter;
private String _strHintText;
private boolean _isFromInit;
public SearchableSpinner(Context context) {
super(context);
this._context = context;
init();
}
public SearchableSpinner(Context context, AttributeSet attrs) {
super(context, attrs);
this._context = context;
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SearchableSpinner);
final int N = a.getIndexCount();
for (int i = 0; i < N; ++i) {
int attr = a.getIndex(i);
if (attr == R.styleable.SearchableSpinner_hintText) {
_strHintText = a.getString(attr);
}
}
a.recycle();
init();
}
public SearchableSpinner(Context context, AttributeSet attrs, int defStyleAttr)
super(context, attrs, defStyleAttr);
this._context = context;
init();
}
private void init() {
_items = new ArrayList();
_searchableListDialog = SearchableListDialog.newInstance
(_items);
_searchableListDialog.setOnSearchableItemClickListener(this);
setOnTouchListener(this);
_arrayAdapter = (ArrayAdapter) getAdapter();
if (!TextUtils.isEmpty(_strHintText)) {
ArrayAdapter arrayAdapter = new ArrayAdapter(_context, android.R.layout
.simple_list_item_1, new String[]{_strHintText});
_isFromInit = true;
setAdapter(arrayAdapter);
}
}
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
if (null != _arrayAdapter) {
// Refresh content #6
// Change Start
// Description: The items were only set initially, not reloading the data in the
// spinner every time it is loaded with items in the adapter.
_items.clear();
for (int i = 0; i < _arrayAdapter.getCount(); i++) {
_items.add(_arrayAdapter.getItem(i));
}
// Change end.
_searchableListDialog.show(scanForActivity(_context).getFragmentManager(), "TAG");
}
}
return true;
}
@Override
public void setAdapter(SpinnerAdapter adapter) {
if (!_isFromInit) {
_arrayAdapter = (ArrayAdapter) adapter;
if (!TextUtils.isEmpty(_strHintText) && !_isDirty) {
ArrayAdapter arrayAdapter = new ArrayAdapter(_context, android.R.layout
.simple_list_item_1, new String[]{_strHintText});
super.setAdapter(arrayAdapter)
} else {
super.setAdapter(adapter);
}
} else {
_isFromInit = false;
super.setAdapter(adapter);
}
}
//The method just below is executed when an item in the searchlist is tapped.This is where we store the value int string called selectedItem.
@Override
public void onSearchableItemClicked(Object item, int position) {
setSelection(_items.indexOf(item));
if (!_isDirty) {
_isDirty = true;
setAdapter(_arrayAdapter);
setSelection(_items.indexOf(item));
}
selectedItem= getItemAtPosition(position).toString();
Toast.makeText(getContext(),"You selected "+selectedItem,Toast.LENGTH_LONG).show();
}
private Activity scanForActivity(Context cont) {
if (cont == null)
return null;
else if (cont instanceof Activity)
return (Activity) cont;
else if (cont instanceof ContextWrapper)
return scanForActivity(((ContextWrapper) cont).getBaseContext());
return null;
}
@Override
public int getSelectedItemPosition() {
if (!TextUtils.isEmpty(_strHintText) && !_isDirty) {
return NO_ITEM_SELECTED;
} else {
return super.getSelectedItemPosition();
}
}
@Override
public Object getSelectedItem() {
if (!TextUtils.isEmpty(_strHintText) && !_isDirty) {
return null;
} else {
return super.getSelectedItem();
}
}
}
Y con esto tendríamos listo nuestro ejemplo utilizando un
Spinner con buscador de palabras.
Crear Emulador AVD en Android. (Aquí)
Vamos a crear un emulador para nuestro ejemplo y ver como funciona.
|
Spinner en nuestro emulador avd |
|
Spinner con SearchView con nuestra lista de palabras |
Android Studio - Curso Español
Genial, gracias por el tutorial.. pero hay unas cosas que agregar y corregir;
ResponderEliminar1.- Te faltó agregar el layout de searchable_list_dialog que me imagino sería:
//searchable_list_dialog.xml
LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
SearchView
android:id="@+id/search"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/SearchView
ListView
android:id="@+id/listItems"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/ListView
/LinearLayout
2.- En la clase SearchableSpinner, en el método sobrescrito onSearchableItemClicked, en la línea:
selectedItem = getItemAtPosition(position).toString();
no deberías enviar la variable position porque es la posición del item seleccionado de la lista filtrada, por lo tanto tendrías que cambiar por _items.indexOf(item) y quedaría así:
selectedItem = getItemAtPosition(_items.indexOf(item)).toString();
Con eso sale tu ejemplo.. gracias por el tuto (y);
No utiliza librería amigo pero puedes estar pendiente subiremos mas contenido.
ResponderEliminarY agregaremos un control nuevo.
Saludos.