Реализация SearchView в панели действий


83

Мне нужно создать SearchViewиз моего arrayList<String>и показать предложения в раскрывающемся списке так же, как это

введите описание изображения здесь

Я ищу руководства, которые шаг за шагом объясняют, как создать SearchViewпанель действий.

я прочитал документацию и следую примеру Google, но мне это не пригодилось.

Я создал поиск

<?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>`

Но я не знаю, как задать параметры массива строк. Я попытался получить результат в другом действии, но не работал.


6
Вы должны публиковать все, что вы пробовали, как можно подробнее. На конкретные вопросы с образцом кода обычно приходят более быстрые и содержательные ответы.
Коллин Флинн

Ответы:


128

Чтобы найти решение для этого, потребовалось время, но мы обнаружили, что это самый простой способ заставить его работать так, как вы описываете. Могут быть более эффективные способы сделать это, но, поскольку вы еще не опубликовали свой код активности, мне придется импровизировать и предположить, что у вас есть такой список в начале вашей активности:

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

    }

}

Теперь вам нужно создать адаптер, расширенный из 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;

    }

}

Лучший способ сделать это - если данные вашего списка взяты из базы данных, вы можете передать Cursorвозвращаемые функциями базы данных напрямую ExampleAdapterи использовать соответствующий селектор столбцов для отображения текста столбца в указанном TextViewв адаптере.

Обратите внимание: при импорте CursorAdapterне импортируйте версию поддержки Android, а android.widget.CursorAdapterвместо этого импортируйте стандарт .

Адаптер также потребует нестандартного макета:

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>

Теперь вы можете настраивать элементы списка, добавляя в макет дополнительные текстовые или графические представления и заполняя их данными в адаптере.

Это должно быть все, но если вы еще этого не сделали, вам понадобится пункт меню 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>

Затем создайте конфигурацию с возможностью поиска:

res / xml / searchchable.xml

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

Наконец, добавьте это в соответствующий тег активности в файле манифеста:

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" />

Обратите внимание: @string/searchстрока, используемая в примерах, должна быть определена в values ​​/ strings.xml , также не забудьте обновить ссылку com.exampleдля вашего проекта.


3
Привет, но одно сомнение, надеюсь, вы мне в этом поможете. Если я наберу одну букву в фильтре, хотя у меня есть результаты фильтра, ничего не будет отображаться, если их больше одной. только тогда отображается. Почему?
Наруто

Привет, возможно, проверьте свои стили на наличие чего-либо, связанного с EditText или AutoCompleteTextView, поскольку вы можете установить количество символов по умолчанию, которое необходимо ввести, прежде чем оно покажет автозаполнение. На самом деле я думаю, что по умолчанию это 2 символа, поэтому, возможно, вам нужно добавить это в стили, чтобы изменить его.
tpbapp

Привет, во время разработки я столкнулся с еще одной проблемой searchview. если я отображаю больше элементов в раскрывающемся списке, например: 3 текстовых просмотра, тогда размер элемента увеличивается, поэтому элементы поиска перемещаются по клавиатуре, если я прокручиваю, как i.stack.imgur.com/d7t3A.png . Это происходит, если я увеличиваю размер текста или добавляю больше просмотров в элементе. Это поведение по умолчанию?
Наруто

Еще раз привет, нет, этого не должно происходить. Похоже, что у вас уже есть много кода в проекте, который мешает AutoCompleteTextView в SearchView, или, возможно, что-то не так с программным обеспечением клавиатуры, приложением или плагином, вызывающим такое поведение. Поведение по умолчанию должно быть примерно таким: stackoverflow.com/questions/22116237/… за исключением того, что этот человек фактически спрашивает, как заставить его не быть скрытым за клавиатурой.
tpbapp

3
@tpbapp Я уже разобрался. Перечень причин предложения не появляется, потому что в вашем коде, что search.setSearchableInfo(manager.getSearchableInfo(getComponentName()));называется дважды в onCreateOptionsMenu()и loadHistory()методах. Поэтому я создаю глобальные переменные SearchView и SearchManager и вызываю их только getSearchableInfo()один раз onCreateOptionsMenu(). И мой список предложений теперь работает отлично. Предлагаю вам пересмотреть свой код.
Хафиж Херди

53

Если у кого-то еще есть nullptr в переменной searchview, я обнаружил, что настройка элемента немного отличается:

старый:

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

новый:

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

до Android x:

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

Для получения дополнительной информации обновленная документация находится здесь .


3
Спасибо. Именно то, что мне не хватало. :-)
Мортен Э. Расмуссен

Спасибо, что было просто и полезно.
Мухаммад

1
app:actionViewClass="androidx.appcompat.widget.SearchView"для androidx
HendraWD

4

SearchDialog или SearchWidget?

Когда дело доходит до реализации функции поиска , в официальной документации для разработчиков Android предлагается два подхода .
Вы можете использовать SearchDialog или SearchWidget .
Я собираюсь объяснить реализацию функции поиска с помощью SearchWidget.

Как это сделать с виджетом поиска?

Я объясню функции поиска в RecyclerView с помощью SearchWidget. Это довольно просто.

Просто выполните эти 5 простых шагов

1) Добавить в меню пункт searchView

Вы можете добавить, SearchViewможно добавить, как actionViewв меню, используя

приложение: 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) Настройте текст подсказки SerchView, слушателя и т. Д.

Вы должны инициализировать SearchView в onCreateOptionsMenu(Menu menu)методе.

  @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) Реализуйте SearchView.OnQueryTextListener в своей деятельности

OnQueryTextListener имеет два абстрактных метода

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

Итак, ваш каркас Activity будет выглядеть так

YourActivity extends AppCompatActivity implements SearchView.OnQueryTextListener{

     public boolean onQueryTextSubmit(String query)

     public boolean onQueryTextChange(String newText) 

}

4) Реализуйте SearchView.OnQueryTextListener

Вы можете предоставить реализацию для таких абстрактных методов, как этот

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) Напишите метод фильтрации в вашем адаптере RecyclerView.

Самая важная часть. Вы можете написать свою собственную логику для выполнения поиска.
Вот мой. Этот фрагмент показывает список Name, который содержит текст, введенный в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();
}

Соответствующая ссылка:

Полный рабочий код SearchView с базой данных SQLite в этом музыкальном приложении


1

За Searchview использования этого кода

  1. Для 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. В вашем фрагменте или действии

    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. В классе адаптера

     public void setFilter(List<ProductDetailPojo> newList){
        arrayList=new ArrayList<>();
        arrayList.addAll(newList);
        notifyDataSetChanged();
    }
    
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.