Implementieren von SearchView in der Aktionsleiste

81

Ich muss SearchViewaus meinem erstellen arrayList<String>und die Vorschläge in der Dropdown-Liste gleich so anzeigen

Geben Sie hier die Bildbeschreibung ein

Ich suche nach Tutorials, die Schritt für Schritt erklären, wie man SearchVieweine Aktionsleiste erstellt.

Ich habe die Dokumentation gelesen und folge dem Beispiel Google, aber es war für mich nicht nützlich.

Ich habe die Suche erstellt

<?xml version="1.0" encoding="utf-8"?>

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/action_search"
          android:title="Search"
          android:icon="@android:drawable/ic_menu_search"
          android:showAsAction="always"
          android:actionViewClass="android.widget.SearchView" />
</menu>`

Ich weiß jedoch nicht, wie ich die Parameter des String-Arrays einstellen soll. Ich habe versucht, das Ergebnis in einer anderen Aktivität abzurufen, aber es funktioniert nicht.

Matteo
quelle
6
Sie sollten alles, was Sie versucht haben, so detailliert wie möglich veröffentlichen. Spezifische Fragen mit Beispielcode erhalten in der Regel schnellere und aussagekräftigere Antworten.
Collin Flynn

Antworten:

126

Es hat eine Weile gedauert, eine Lösung dafür zusammenzustellen, aber wir haben festgestellt, dass dies der einfachste Weg ist, um es so zu machen, wie Sie es beschreiben. Es gibt bessere Möglichkeiten, dies zu tun, aber da Sie Ihren Aktivitätscode nicht veröffentlicht haben, muss ich improvisieren und davon ausgehen, dass Sie zu Beginn Ihrer Aktivität eine solche Liste haben:

private List<String> items = db.getItems();

ExampleActivity.java

private List<String> items;

private Menu menu;

@Override
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public boolean onCreateOptionsMenu(Menu menu) {

    getMenuInflater().inflate(R.menu.example, menu);

    this.menu = menu;

    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {

        SearchManager manager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);

        SearchView search = (SearchView) menu.findItem(R.id.search).getActionView();

        search.setSearchableInfo(manager.getSearchableInfo(getComponentName()));

        search.setOnQueryTextListener(new OnQueryTextListener() { 

            @Override 
            public boolean onQueryTextChange(String query) {

                loadHistory(query);

                return true; 

            } 

        });

    }

    return true;

}

// History
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private void loadHistory(String query) {

    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {

        // Cursor
        String[] columns = new String[] { "_id", "text" };
        Object[] temp = new Object[] { 0, "default" };

        MatrixCursor cursor = new MatrixCursor(columns);

        for(int i = 0; i < items.size(); i++) {

            temp[0] = i;
            temp[1] = items.get(i);

            cursor.addRow(temp);

        }

        // SearchView
        SearchManager manager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);

        final SearchView search = (SearchView) menu.findItem(R.id.search).getActionView();

        search.setSuggestionsAdapter(new ExampleAdapter(this, cursor, items));

    }

}

Jetzt müssen Sie einen Adapter erstellen, der erweitert ist aus CursorAdapter:

ExampleAdapter.java

public class ExampleAdapter extends CursorAdapter {

    private List<String> items;

    private TextView text;

    public ExampleAdapter(Context context, Cursor cursor, List<String> items) {

        super(context, cursor, false);

        this.items = items;

    }

    @Override
    public void bindView(View view, Context context, Cursor cursor) {

        text.setText(items.get(cursor.getPosition()));

    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {

        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        View view = inflater.inflate(R.layout.item, parent, false);

        text = (TextView) view.findViewById(R.id.text);

        return view;

    }

}

Eine bessere Möglichkeit, dies zu tun, besteht darin, wenn Ihre Listendaten aus einer Datenbank stammen, die Cursorvon der Datenbank zurückgegebenen Funktionen direkt an ExampleAdapterdie entsprechende Spaltenauswahl zu übergeben und den entsprechenden Spaltentext zu verwenden, um den Spaltentext in dem TextViewim Adapter angegebenen anzuzeigen .

Bitte beachten Sie: Wenn Sie importieren, importieren CursorAdapterSie nicht die Android-Support-Version, android.widget.CursorAdaptersondern stattdessen den Standard .

Der Adapter benötigt außerdem ein benutzerdefiniertes Layout:

res / layout / item.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <TextView
        android:id="@+id/item"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</RelativeLayout>

Sie können jetzt Listenelemente anpassen, indem Sie dem Layout zusätzliche Text- oder Bildansichten hinzufügen und diese mit Daten im Adapter füllen.

Dies sollte alles sein, aber wenn Sie dies noch nicht getan haben, benötigen Sie einen SearchView-Menüpunkt:

res / menu / example.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:id="@+id/search"
        android:title="@string/search"
        android:showAsAction="ifRoom"
        android:actionViewClass="android.widget.SearchView" />

</menu>

Erstellen Sie dann eine durchsuchbare Konfiguration:

res / xml / searchable.xml

<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    android:label="@string/search"
    android:hint="@string/search" >
</searchable>

Fügen Sie dies schließlich in das entsprechende Aktivitäts-Tag in der Manifest-Datei ein:

AndroidManifest.xml

<intent-filter>
    <action android:name="android.intent.action.SEARCH" />
</intent-filter>

<meta-data
    android:name="android.app.default_searchable"
    android:value="com.example.ExampleActivity" />
<meta-data
    android:name="android.app.searchable"
    android:resource="@xml/searchable" />

Bitte beachten Sie: Die @string/searchin den Beispielen verwendete Zeichenfolge sollte in values ​​/ strings.xml definiert sein. Vergessen Sie auch nicht, den Verweis auf com.examplefür Ihr Projekt zu aktualisieren .

tpbapp
quelle
3
Hallo, aber ein Zweifel, ich hoffe du hilfst mir dabei. Wenn ich einen Buchstaben in den Filter eingebe, obwohl ich Filterergebnisse habe, wird nichts angezeigt, wenn es mehr als einer ist. dann wird nur noch angezeigt. Warum?
Naruto
Hallo, überprüfen Sie Ihre Stile möglicherweise auf alles, was mit EditText oder AutoCompleteTextView zu tun hat, da Sie die Standardanzahl der Zeichen festlegen können, die eingegeben werden müssen, bevor die automatische Vervollständigung angezeigt wird. Eigentlich denke ich, dass die Standardeinstellung 2 Zeichen ist, daher müssten Sie dies möglicherweise zu Stilen hinzufügen, um sie zu ändern.
tpbapp
Hallo, während der Entwicklung bin ich auf eine weitere Ausgabe von Searchview gestoßen. Wenn ich mehr Elemente in der Dropdown-Liste anzeige, z. B. 3 Textansichten, erhöht sich die Größe des Elements, sodass die Suchelemente auf der Tastatur angezeigt werden, wenn ich wie i.stack.imgur.com/d7t3A.png scrolle . Dies passiert, wenn ich den Text vergrößere oder mehr Ansichten zum Element hinzufüge. Ist es Standardverhalten?
Naruto
Hallo nochmal, nein das sollte nicht passieren. Es hört sich so an, als ob Sie bereits viel Code im Projekt haben, der die AutoCompleteTextView in der SearchView stört, oder vielleicht stimmt etwas mit der Tastatursoftware und der App oder einem Plugin nicht, die dieses Verhalten verursachen. Das Standardverhalten sollte ungefähr so lauten: stackoverflow.com/questions/22116237/…, außer dass diese Person tatsächlich fragt, wie es nicht hinter der Tastatur versteckt werden soll.
tpbapp
3
@tpbapp Ich finde es schon heraus. Der Grund, warum die Vorschlagsliste nicht angezeigt wird, liegt darin, dass Sie in Ihrem Code search.setSearchableInfo(manager.getSearchableInfo(getComponentName()));die Methoden onCreateOptionsMenu()und zweimal aufgerufen haben loadHistory(). Also mache ich die globale Variable SearchView und SearchManager und rufe sie nur getSearchableInfo()einmal auf onCreateOptionsMenu(). Und meine Vorschlagsliste funktioniert jetzt einwandfrei. Ich empfehle Ihnen, Ihren Code zu überarbeiten.
Hafizh Herdi
52

Wenn jemand anderes ein Nullptr in der Suchansichtsvariablen hat, habe ich festgestellt, dass das Element-Setup ein kleines bisschen anders ist:

alt:

android:showAsAction="ifRoom"
android:actionViewClass="android.widget.SearchView"

Neu:

app:showAsAction="ifRoom|collapseActionView"
app:actionViewClass="androidx.appcompat.widget.SearchView"

Pre-Android x:

app:showAsAction="ifRoom|collapseActionView"
app:actionViewClass="android.support.v7.widget.SearchView"

Für weitere Informationen wird die aktualisierte Dokumentation befindet sich hier .

Fett
quelle
3
Danke dir. Genau das, was mir gefehlt hat. :-)
Morten E. Rasmussen
Danke, das war einfach und hilfreich.
Muhammad
1
app:actionViewClass="androidx.appcompat.widget.SearchView"für Androidx
HendraWD
3

SearchDialog oder SearchWidget?

Wenn es um die Implementierung einer Suchfunktion geht, gibt es zwei Vorschläge für die offizielle Android Developer Documentation.
Sie können entweder einen SearchDialog oder ein SearchWidget verwenden .
Ich werde die Implementierung der Suchfunktion mit SearchWidget erklären.

Wie geht das mit dem Such-Widget?

Ich werde die Suchfunktion in einer RecyclerView mit SearchWidget erläutern. Es ist ziemlich einfach.

Befolgen Sie einfach diese 5 einfachen Schritte

1) Fügen Sie das SearchView-Element im Menü hinzu

Sie können hinzufügen, SearchViewkönnen wie actionViewim Menü mit hinzugefügt werden

App: useActionClass = "android.support.v7.widget.SearchView".

<menu 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"
   tools:context="rohksin.com.searchviewdemo.MainActivity">
   <item
       android:id="@+id/searchBar"
       app:showAsAction="always"
       app:actionViewClass="android.support.v7.widget.SearchView"
   />
</menu>

2) Richten Sie SerchView Hint-Text, Listener usw. Ein

Sie sollten SearchView in der onCreateOptionsMenu(Menu menu)Methode initialisieren .

  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
     // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);

        MenuItem searchItem = menu.findItem(R.id.searchBar);

        SearchView searchView = (SearchView) searchItem.getActionView();
        searchView.setQueryHint("Search People");
        searchView.setOnQueryTextListener(this);
        searchView.setIconified(false);

        return true;
   }

3) Implementieren Sie SearchView.OnQueryTextListener in Ihrer Aktivität

OnQueryTextListener hat zwei abstrakte Methoden

  1. onQueryTextSubmit(String query)
  2. onQueryTextChange(String newText

Ihr Aktivitätsskelett würde also so aussehen

YourActivity extends AppCompatActivity implements SearchView.OnQueryTextListener{

     public boolean onQueryTextSubmit(String query)

     public boolean onQueryTextChange(String newText) 

}

4) Implementieren Sie SearchView.OnQueryTextListener

Sie können die Implementierung für diese abstrakten Methoden bereitstellen

public boolean onQueryTextSubmit(String query) {

    // This method can be used when a query is submitted eg. creating search history using SQLite DB

    Toast.makeText(this, "Query Inserted", Toast.LENGTH_SHORT).show();
    return true;
}

@Override
public boolean onQueryTextChange(String newText) {

    adapter.filter(newText);
    return true;
}

5) Schreiben Sie eine Filtermethode in Ihren RecyclerView-Adapter.

Wichtigster Teil. Sie können Ihre eigene Logik schreiben, um die Suche durchzuführen.
Hier ist mein. Dieses Snippet zeigt die Liste der Namen, die den in das Feld eingegebenen Text enthältSearchView

public void filter(String queryText)
{
    list.clear();

    if(queryText.isEmpty())
    {
       list.addAll(copyList);
    }
    else
    {

       for(String name: copyList)
       {
           if(name.toLowerCase().contains(queryText.toLowerCase()))
           {
              list.add(name);
           }
       }

    }

   notifyDataSetChanged();
}

Relevanter Link:

Vollständiger Arbeitscode in SearchView mit einer SQLite-Datenbank in dieser Musik-App

Rohit Singh
quelle
1

Zur SearchviewVerwendung dieses Codes

  1. Für XML

    <android.support.v7.widget.SearchView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/searchView">
    
    </android.support.v7.widget.SearchView>

  2. In Ihrem Fragment oder Ihrer Aktivität

    package com.example.user.salaryin;
    
    import android.app.ProgressDialog;
    import android.os.Bundle;
    import android.support.v4.app.Fragment;
    import android.support.v4.view.MenuItemCompat;
    import android.support.v7.widget.GridLayoutManager;
    import android.support.v7.widget.LinearLayoutManager;
    import android.support.v7.widget.RecyclerView;
    import android.support.v7.widget.SearchView;
    import android.view.LayoutInflater;
    import android.view.Menu;
    import android.view.MenuInflater;
    import android.view.MenuItem;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.Toast;
    import com.example.user.salaryin.Adapter.BusinessModuleAdapter;
    import com.example.user.salaryin.Network.ApiClient;
    import com.example.user.salaryin.POJO.ProductDetailPojo;
    import com.example.user.salaryin.Service.ServiceAPI;
    import java.util.ArrayList;
    import java.util.List;
    import retrofit2.Call;
    import retrofit2.Callback;
    import retrofit2.Response;
    
    
    public class OneFragment extends Fragment implements SearchView.OnQueryTextListener {
    
    RecyclerView recyclerView;
    RecyclerView.LayoutManager layoutManager;
    ArrayList<ProductDetailPojo> arrayList;
    BusinessModuleAdapter adapter;
    private ProgressDialog pDialog;
    GridLayoutManager gridLayoutManager;
    SearchView searchView;
    
    public OneFragment() {
        // Required empty public constructor
    }
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
    
        View rootView = inflater.inflate(R.layout.one_fragment,container,false);
    
        pDialog = new ProgressDialog(getActivity());
        pDialog.setMessage("Please wait...");
    
    
        searchView=(SearchView)rootView.findViewById(R.id.searchView);
        searchView.setQueryHint("Search BY Brand");
        searchView.setOnQueryTextListener(this);
    
        recyclerView = (RecyclerView) rootView.findViewById(R.id.recyclerView);
        layoutManager = new LinearLayoutManager(this.getActivity());
        recyclerView.setLayoutManager(layoutManager);
        gridLayoutManager = new GridLayoutManager(this.getActivity().getApplicationContext(), 2);
        recyclerView.setLayoutManager(gridLayoutManager);
        recyclerView.setHasFixedSize(true);
        getImageData();
    
    
        // Inflate the layout for this fragment
        //return inflater.inflate(R.layout.one_fragment, container, false);
        return rootView;
    }
    
    
    private void getImageData() {
        pDialog.show();
        ServiceAPI service = ApiClient.getRetrofit().create(ServiceAPI.class);
        Call<List<ProductDetailPojo>> call = service.getBusinessImage();
    
        call.enqueue(new Callback<List<ProductDetailPojo>>() {
            @Override
            public void onResponse(Call<List<ProductDetailPojo>> call, Response<List<ProductDetailPojo>> response) {
                if (response.isSuccessful()) {
                    arrayList = (ArrayList<ProductDetailPojo>) response.body();
                    adapter = new BusinessModuleAdapter(arrayList, getActivity());
                    recyclerView.setAdapter(adapter);
                    pDialog.dismiss();
                } else if (response.code() == 401) {
                    pDialog.dismiss();
                    Toast.makeText(getActivity(), "Data is not found", Toast.LENGTH_SHORT).show();
                }
    
            }
    
            @Override
            public void onFailure(Call<List<ProductDetailPojo>> call, Throwable t) {
                Toast.makeText(getActivity(), t.getMessage(), Toast.LENGTH_SHORT).show();
                pDialog.dismiss();
    
            }
        });
    }
    
       /* @Override
        public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        getActivity().getMenuInflater().inflate(R.menu.menu_search, menu);
        MenuItem menuItem = menu.findItem(R.id.action_search);
        SearchView searchView = (SearchView) MenuItemCompat.getActionView(menuItem);
        searchView.setQueryHint("Search Product");
        searchView.setOnQueryTextListener(this);
    }*/
    
    @Override
    public boolean onQueryTextSubmit(String query) {
        return false;
    }
    
    @Override
    public boolean onQueryTextChange(String newText) {
        newText = newText.toLowerCase();
        ArrayList<ProductDetailPojo> newList = new ArrayList<>();
        for (ProductDetailPojo productDetailPojo : arrayList) {
            String name = productDetailPojo.getDetails().toLowerCase();
    
            if (name.contains(newText) )
                newList.add(productDetailPojo);
            }
        adapter.setFilter(newList);
        return true;
       }
    }
  3. In der Adapterklasse

     public void setFilter(List<ProductDetailPojo> newList){
        arrayList=new ArrayList<>();
        arrayList.addAll(newList);
        notifyDataSetChanged();
    }
Neeraj Gupta
quelle