Triển khai SearchView trong thanh hành động


82

Tôi cần tạo SearchViewtừ của tôi arrayList<String>và hiển thị các đề xuất trong danh sách thả xuống giống như cái này

nhập mô tả hình ảnh ở đây

Tôi tìm kiếm các hướng dẫn giải thích từng bước cách tạo một SearchViewthanh tác vụ trong thanh tác vụ.

Tôi đã đọc tài liệu và làm theo ví dụ google nhưng nó không hữu ích cho tôi.

Tôi đã tạo tìm kiếm

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

Nhưng tôi không biết làm thế nào để thiết lập các tham số của mảng chuỗi. Tôi đã cố gắng truy xuất kết quả trong Hoạt động khác nhưng không hoạt động.


6
Bạn nên đăng mọi thứ bạn đã thử, càng chi tiết càng tốt. Các câu hỏi cụ thể với mã mẫu có xu hướng nhận được câu trả lời nhanh hơn, có ý nghĩa hơn.
Collin Flynn

Câu trả lời:


127

Phải mất một lúc để đưa ra một giải pháp cho vấn đề này, nhưng tôi thấy đây là cách dễ nhất để làm cho nó hoạt động theo cách bạn mô tả. Có thể có nhiều cách tốt hơn để làm điều này, nhưng vì bạn chưa đăng mã hoạt động của mình, tôi sẽ phải ứng biến và giả sử bạn có một danh sách như thế này khi bắt đầu hoạt động của mình:

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

    }

}

Bây giờ bạn cần tạo một bộ điều hợp mở rộng từ 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;

    }

}

Cách tốt hơn để làm điều này là nếu dữ liệu danh sách của bạn là từ cơ sở dữ liệu, bạn có thể chuyển Cursortrực tiếp các hàm cơ sở dữ liệu trả về ExampleAdaptervà sử dụng bộ chọn cột có liên quan để hiển thị văn bản cột trong TextViewtham chiếu trong bộ điều hợp.

Xin lưu ý: khi bạn nhập, CursorAdapterkhông nhập phiên bản hỗ trợ Android, android.widget.CursorAdapterthay vào đó hãy nhập tiêu chuẩn .

Bộ điều hợp cũng sẽ yêu cầu bố cục tùy chỉnh:

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>

Giờ đây, bạn có thể tùy chỉnh các mục trong danh sách bằng cách thêm các chế độ xem hình ảnh hoặc văn bản bổ sung vào bố cục và đưa chúng vào dữ liệu trong bộ điều hợp.

Đây là tất cả, nhưng nếu bạn chưa làm điều này, bạn cần một mục 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>

Sau đó, tạo cấu hình có thể tìm kiếm:

res / xml / searchable.xml

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

Cuối cùng, thêm điều này vào bên trong thẻ hoạt động có liên quan trong tệp kê khai:

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

Xin lưu ý: @string/searchChuỗi được sử dụng trong các ví dụ phải được xác định trong giá trị / string.xml , cũng đừng quên cập nhật tham chiếu com.examplecho dự án của bạn.


3
Xin chào, nhưng có một điều nghi ngờ, tôi hy vọng bạn sẽ giúp tôi về điều này. Nếu tôi nhập một ký tự trên bộ lọc, mặc dù tôi có kết quả bộ lọc, không có gì sẽ hiển thị, nếu nhiều hơn thì một chữ cái. thì chỉ nó hiển thị. tại sao?
Naruto

Xin chào, có thể kiểm tra kiểu của bạn để tìm bất kỳ thứ gì liên quan đến EditText hoặc AutoCompleteTextView vì bạn có thể đặt số ký tự mặc định cần được nhập trước khi nó hiển thị tự động hoàn thành. Trên thực tế, tôi nghĩ mặc định là 2 ký tự, vì vậy có thể bạn sẽ cần thêm ký tự này vào các kiểu để thay đổi nó.
tpbapp

Xin chào, trong khi phát triển, tôi đã gặp phải một vấn đề nữa là searchview. nếu tôi hiển thị nhiều mục hơn trong trình đơn thả xuống, ví dụ: 3 lần xem văn bản, thì kích thước của mục sẽ tăng lên, vì vậy các mục tìm kiếm sẽ chảy trên bàn phím nếu tôi cuộn như i.stack.imgur.com/d7t3A.png . Điều này xảy ra nếu tôi tăng kích thước văn bản hoặc thêm nhiều chế độ xem hơn trong mục. Nó có phải là hành vi mặc định không?
Naruto

Xin chào một lần nữa, không điều đó không nên xảy ra. Có vẻ như bạn có rất nhiều mã trong dự án đang can thiệp vào AutoCompleteTextView trong SearchView hoặc có lẽ đã xảy ra lỗi với phần mềm bàn phím và ứng dụng hoặc plugin gây ra hành vi này. Hành vi mặc định phải giống như thế này stackoverflow.com/questions/22116237/… ngoại trừ người này thực sự đang hỏi làm thế nào để làm cho nó không bị ẩn sau bàn phím.
tpbapp

3
@tpbapp Tôi đã tìm ra nó. Lý do danh sách gợi ý không xuất hiện là vì trong mã của bạn, bạn đã search.setSearchableInfo(manager.getSearchableInfo(getComponentName()));gọi hai lần trong các phương thức onCreateOptionsMenu()loadHistory(). Vì vậy, tôi tạo biến SearchView và SearchManager toàn cục và chỉ được gọi getSearchableInfo()một lần trong đó onCreateOptionsMenu(). Và danh sách gợi ý của tôi hiện đang hoạt động hoàn hảo. Tôi đề nghị bạn sửa đổi mã của bạn.
Hafizh Herdi

52

Nếu bất kỳ ai khác gặp phải nullptr trên biến searchview, tôi phát hiện ra rằng thiết lập mục hơi khác một chút:

cũ:

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

Mới:

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

trước android x:

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

Để biết thêm thông tin, tài liệu cập nhật của nó nằm ở đây .


3
Cảm ơn bạn. Chỉ là những gì tôi đã thiếu. :-)
Morten E. Rasmussen

Cảm ơn bạn điều đó thật đơn giản và hữu ích.
Muhammad

1
app:actionViewClass="androidx.appcompat.widget.SearchView"cho androidx
HendraWD

3

SearchDialog hay SearchWidget?

Khi nói đến việc triển khai chức năng tìm kiếm, có hai cách tiếp cận được đề xuất bởi Tài liệu dành cho nhà phát triển Android chính thức.
Bạn có thể sử dụng SearchDialog hoặc SearchWidget .
Tôi sẽ giải thích việc triển khai chức năng Tìm kiếm bằng SearchWidget.

Làm thế nào để làm điều đó với tiện ích Tìm kiếm?

Tôi sẽ giải thích chức năng tìm kiếm trong RecyclerView bằng SearchWidget. Nó khá đơn giản.

Chỉ cần làm theo 5 bước đơn giản sau

1) Thêm mục searchView trong menu

Bạn có thể thêm SearchViewcó thể được thêm vào như actionViewtrong menu bằng cách sử dụng

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) Thiết lập văn bản gợi ý SerchView, trình nghe, v.v.

Bạn nên khởi tạo SearchView trong onCreateOptionsMenu(Menu menu)phương thức.

  @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) Triển khai SearchView.OnQueryTextListener trong Hoạt động của bạn

OnQueryTextListener có hai phương pháp trừu tượng

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

Vì vậy, khung Hoạt động của bạn sẽ giống như thế này

YourActivity extends AppCompatActivity implements SearchView.OnQueryTextListener{

     public boolean onQueryTextSubmit(String query)

     public boolean onQueryTextChange(String newText) 

}

4) Triển khai SearchView.OnQueryTextListener

Bạn có thể cung cấp triển khai cho các phương thức trừu tượng như thế này

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) Viết phương thức lọc trong Bộ điều hợp RecyclerView của bạn.

Phần quan trọng nhất. Bạn có thể viết logic của riêng mình để thực hiện tìm kiếm.
Đây là của tôi. Đoạn mã này hiển thị danh sách Tên chứa văn bản được nhập vàoSearchView

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

Liên kết có liên quan:

Mã làm việc đầy đủ trên SearchView với cơ sở dữ liệu SQLite trong Ứng dụng âm nhạc này


1

Để Searchviewsử dụng những mã này

  1. Đối với 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. Trong Phân đoạn hoặc Hoạt động của bạn

    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. Trong lớp bộ điều hợp

     public void setFilter(List<ProductDetailPojo> newList){
        arrayList=new ArrayList<>();
        arrayList.addAll(newList);
        notifyDataSetChanged();
    }
    
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.