[Android] RecyclerView 검색 기능

Krrong·2022년 5월 18일
0

Android

목록 보기
10/14
post-thumbnail
post-custom-banner

📌 Intro

RecyclerView를 사용하면서 많은 양의 데이터를 보여주게 될 경우 원하는 아이템을 찾기 어려운 부분이 있었고, 이 점을 개인 프로젝트를 구현하면서 많이 느꼈다. 이를 해결하기 위해 recyclerView에 검색 기능을 추가하였고 이 방법에 대해 정리하려고 한다.



📌 검색 기능 추가하기

검색 기능을 추가하기에 앞서 이글에서 사용한 코드를 가져와 사용하려고 한다.

1. 어댑터 코드 수정(SimpleTextAdapter.java)

    public void setItems(ArrayList<SingleItem> list){
        items = list;
        notifyDataSetChanged();
    }

SimpleTextAdapter에 setItems() 함수를 추가로 만들어주자.

이 함수는 어댑터의 아이템을 인자로 받은 아이템으로 바꾸고 notifyDataSetChanged()를 통해 recyclerView에게 데이터가 변했다고 알리는 역할을 한다.

setItems()함수를 추가한 전체 SimpleTextAdapter.java 코드는 다음과 같다.

package com.example.recyclerview;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import java.util.ArrayList;
import java.util.List;

public class SimpleTextAdapter extends RecyclerView.Adapter<SimpleTextAdapter.ViewHolder> {
    private ArrayList<SingleItem> items = null;

    public class ViewHolder extends RecyclerView.ViewHolder{
        TextView text_name;
        TextView text_description;
        ImageView imageView;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);

            text_name = itemView.findViewById(R.id.text_name);
            text_description = itemView.findViewById(R.id.text_description);
            imageView = itemView.findViewById(R.id.imageView);
        }
    }

    // 생성자
    SimpleTextAdapter(ArrayList<SingleItem> list){
        items = list;
    }

    // 아이템 뷰를 위한 뷰홀더 객체 생성하여 리턴
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        Context context = parent.getContext();
        LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        View view = inflater.inflate(R.layout.item, parent, false);
        SimpleTextAdapter.ViewHolder vh = new SimpleTextAdapter.ViewHolder(view);

        return vh;
    }

    // position 에 해당하는 데이터를 뷰홀더의 아이템 뷰에 표시
    @Override
    public void onBindViewHolder(@NonNull SimpleTextAdapter.ViewHolder holder, int position) {
        String name = items.get(position).name;
        String description = items.get(position).description;
        int resId = items.get(position).resId;

        holder.text_name.setText(name);
        holder.text_description.setText(description);
        holder.imageView.setImageResource(resId);
    }

    // 전체 데이터 개수 리턴
    @Override
    public int getItemCount() {
        return items.size();
    }

    public void setItems(ArrayList<SingleItem> list){
        items = list;
        notifyDataSetChanged();
    }
}



2. activity_main.xml 수정

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <EditText
        android:id="@+id/editText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ems="10"
        android:hint="검색어 입력"
        android:inputType="textPersonName" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="627dp" />
</LinearLayout>

원래 activity_main.xml은 recyclerView만 가진 상태였지만 검색 기능을 추가하기 위해 editText도 하나 추가해주도록 하자.



3. MainActivity.java 수정

package com.example.recyclerview;

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.widget.EditText;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {
    // 검색시 같은 이름이 있는 아이템이 담길 리스트
    ArrayList<SingleItem> search_list = new ArrayList<>();
    // recyclerView에 추가할 아이템 리스트
    ArrayList<SingleItem> original_list = new ArrayList<>();
    // 어댑터
    SimpleTextAdapter adapter;
    EditText editText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 리스트에 아이템 추가
        for(int i=0; i<50; i++){
            if(i % 2 == 0){
                original_list.add(new SingleItem("ITEM " + i,"foreground image " + i,R.drawable.ic_launcher_foreground));
            }
            else{
                original_list.add(new SingleItem("ITEM " + i,"background image " + i,R.drawable.ic_launcher_background));
            }
        }

        editText = findViewById(R.id.editText);
        
        // editText 리스터 작성
        editText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }

            @Override
            public void afterTextChanged(Editable editable) {
                String searchText = editText.getText().toString();
                search_list.clear();

                if(searchText.equals("")){
                    adapter.setItems(original_list);
                }
                else {
                    // 검색 단어를 포함하는지 확인
                    for (int a = 0; a < original_list.size(); a++) {
                        if (original_list.get(a).name.toLowerCase().contains(searchText.toLowerCase())) {
                            search_list.add(original_list.get(a));
                        }
                        adapter.setItems(search_list);
                    }
                }
            }
        });

        // 리사이클러뷰, 어댑터 연결
        RecyclerView recyclerView = findViewById(R.id.recyclerView);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        adapter = new SimpleTextAdapter(original_list);
        recyclerView.setAdapter(adapter);
    }
}

editText에 대한 이벤트 리스너를 작성할 수 있다. 콜백 함수들은 다음과 같다.

  • void beforeTextChanged(CahrSequence s, int start, int count, int after)
    s문자열이 start위치로부터 count길이만큼이 after길이로 변경되려고 한다는 내용을 전ㄷ라해주면서 호출된다.

  • onTextChanged(CharSequence s, int start, int before, int count)
    s가 start위치로부터 count길이만큼 변경되었다는 것을 알려준다. 이전 문자열에서 before길이만큼 바뀌었다는 것을 알려준다.

  • afterTextChanged(CharSequence s, int start, int before, int count)
    s내의 어느 문자열이 변경되었다는 것을 알려주기 위해 호출된다. s를 변경할 시 다시 재호출이 되기 때문에 무한루프에 빠질 가능성이 있으니 주의해야 한다.

위 세개의 콜백 함수 중 afterTextChanged()함수를 사용하여 원하는 검색 기능을 구현할 수 있다.

아이템을 저장하고 있는 리스트를 순회하면서 사용자가 editText에 작성한 문자를 포함하고 있는지 확인한 뒤, 포함하는 아이템들을 search_list라는 새로운 리스트에 담고, setItems()함수를 통해 어댑터의 아이템을 바꿔주면 된다.

4. 실행화면

  • 기본 실행 화면
  • 검색 화면

많은 데이터에서 내가 필요한 정보만을 찾기 위해 recyclerView에서 editText를 활용하여 검색하는 기능을 구현해보았다.



📌 Github

전체 코드는 Github 링크 에서 확인할 수 있다.

📌 참고

[1] https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=777lover&logNo=10131263714 (editText 이벤트 리스너)
[2] https://stickode.tistory.com/49 (검색 기능 구현 코드)

post-custom-banner

0개의 댓글