Muszę utworzyć SearchView
z mojego arrayList<String>
i pokazać sugestie na liście rozwijanej to samo
Szukam samouczków, które wyjaśniają krok po kroku, jak zbudować SearchView
pasek akcji.
Przeczytałem dokumentację i idąc za przykładem google ale nie było to dla mnie przydatne.
Stworzyłem wyszukiwanie
<?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>`
Ale nie wiem, jak ustawić parametry tablicy ciągów. Próbowałem pobrać wynik w innym działaniu, ale nie zadziałało.
Odpowiedzi:
Znalezienie rozwiązania tego problemu zajęło trochę czasu, ale okazało się, że jest to najłatwiejszy sposób, aby to zadziałało w sposób, który opisałeś. Mogłyby być lepsze sposoby, aby to zrobić, ale ponieważ nie opublikowałeś kodu aktywności, będę musiał improwizować i założyć, że masz taką listę na początku swojej aktywności:
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)); } }
Teraz musisz utworzyć adapter rozszerzony z
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; } }
Lepszym sposobem na to jest, jeśli dane listy pochodzą z bazy danych, można przekazać
Cursor
zwracane przez funkcje bazy danych bezpośrednio doExampleAdapter
i użyć odpowiedniego selektora kolumny, aby wyświetlić tekst kolumny w elemencie, do któregoTextView
odwołuje się adapter.Uwaga: podczas importowania
CursorAdapter
nie importuj wersji obsługi systemu Android,android.widget.CursorAdapter
zamiast tego zaimportuj standard .Adapter będzie również wymagał niestandardowego układu:
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>
Teraz można dostosowywać elementy listy, dodając do układu dodatkowe widoki tekstu lub obrazów i wypełniając je danymi w adapterze.
To powinno być wszystko, ale jeśli jeszcze tego nie zrobiłeś, potrzebujesz elementu menu SearchView:
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>
Następnie utwórz konfigurację z możliwością wyszukiwania:
res / xml / searchable.xml
<searchable xmlns:android="http://schemas.android.com/apk/res/android" android:label="@string/search" android:hint="@string/search" > </searchable>
Na koniec dodaj to wewnątrz odpowiedniego tagu aktywności w pliku manifestu:
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" />
Uwaga:
@string/search
ciąg znaków użyty w przykładach powinien być zdefiniowany w values / strings.xml , nie zapomnij również zaktualizować odniesienia docom.example
swojego projektu.źródło
search.setSearchableInfo(manager.getSearchableInfo(getComponentName()));
wywołałeś dwukrotnie w metodachonCreateOptionsMenu()
iloadHistory()
. Dlatego tworzę zmienną globalną SearchView i SearchManager i wywołuję ją tylkogetSearchableInfo()
razonCreateOptionsMenu()
. Moja lista sugestii działa teraz doskonale. Sugeruję, abyś poprawił swój kod.Jeśli ktokolwiek inny ma nullptr w zmiennej searchview, dowiedziałem się, że konfiguracja przedmiotu jest nieco inna:
stary:
android:showAsAction="ifRoom" android:actionViewClass="android.widget.SearchView"
Nowy:
app:showAsAction="ifRoom|collapseActionView" app:actionViewClass="androidx.appcompat.widget.SearchView"
pre-android x:
app:showAsAction="ifRoom|collapseActionView" app:actionViewClass="android.support.v7.widget.SearchView"
Aby uzyskać więcej informacji, zaktualizowana dokumentacja znajduje się tutaj .
źródło
app:actionViewClass="androidx.appcompat.widget.SearchView"
dla androidxSearchDialog czy SearchWidget?
Jeśli chodzi o implementację funkcji wyszukiwania, istnieją dwa sugerowane podejścia w oficjalnej dokumentacji programisty Androida.
Możesz użyć SearchDialog lub SearchWidget .
Mam zamiar wyjaśnić implementację funkcji wyszukiwania za pomocą SearchWidget.
Jak to zrobić z widżetem wyszukiwania?
Wyjaśnię funkcjonalność wyszukiwania w RecyclerView przy użyciu SearchWidget. To całkiem proste.
Po prostu wykonaj 5 prostych kroków
1) Dodaj element searchView w menu
Możesz dodać,
SearchView
jakactionView
w menu za pomocą<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) Skonfiguruj tekst podpowiedzi SerchView, odbiornik itp
Powinieneś zainicjować SearchView w
onCreateOptionsMenu(Menu menu)
metodzie.@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) Zaimplementuj SearchView.OnQueryTextListener w swojej aktywności
OnQueryTextListener
ma dwie abstrakcyjne metodyonQueryTextSubmit(String query)
onQueryTextChange(String newText
Więc Twój szkielet aktywności wyglądałby tak
YourActivity extends AppCompatActivity implements SearchView.OnQueryTextListener{ public boolean onQueryTextSubmit(String query) public boolean onQueryTextChange(String newText) }
4) Zaimplementuj SearchView.OnQueryTextListener
Możesz zapewnić implementację dla metod abstrakcyjnych, takich jak ta
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) Napisz metodę filtru w adapterze RecyclerView.
Najważniejsza część. Możesz napisać własną logikę wyszukiwania.
Tutaj jest moje. Ten fragment kodu pokazuje listę Name, która zawiera tekst wpisany w
SearchView
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(); }
Odpowiedni link:
Pełny działający kod w SearchView z bazą danych SQLite w tej aplikacji muzycznej
źródło
Aby
Searchview
skorzystać z tego koduW przypadku 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>
W swoim fragmencie lub aktywności
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; } }
W klasie adapterów
public void setFilter(List<ProductDetailPojo> newList){ arrayList=new ArrayList<>(); arrayList.addAll(newList); notifyDataSetChanged(); }
źródło