Blog para desarrollo de aplicaciones en Android, aprende paso a paso como crear aplicaciones.

Usamos cookies propias y de terceros que entre otras cosas recogen datos sobre sus hábitos de navegación para mostrarle publicidad personalizada y realizar análisis de uso de nuestro sitio.
Si continúa navegando consideramos que acepta su uso. OK Más información | Y más

Como crear un Spinner buscador de palabras en Android

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

Android Studio - Curso Español

2 comentarios:

  1. Genial, gracias por el tutorial.. pero hay unas cosas que agregar y corregir;

    1.- 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);

    ResponderEliminar
  2. No utiliza librería amigo pero puedes estar pendiente subiremos mas contenido.
    Y agregaremos un control nuevo.
    Saludos.

    ResponderEliminar

x

Registrate!

Curso Android Español

Curso Kotlin Español

eBook Free Android Studio

Noticias y Eventos

¡Directamente a tu INBOX!

Le enviaremos nuestros recursos gratis. Para obtener nuestro contenido nuevo, únase a nuestra comunidad. No te molestaremos enviando información inútil. ¡No te pierdas ninguna actualización, mantente conectado! Recuerda verificar tu correo electronico.

Ingrese su dirección de correo electrónico:

Entregado por FeedBurner