RecyclerView를 사용하면서 많은 양의 데이터를 보여주게 될 경우 원하는 아이템을 찾기 어려운 부분이 있었고, 이 점을 개인 프로젝트를 구현하면서 많이 느꼈다. 이를 해결하기 위해 recyclerView에 검색 기능을 추가하였고 이 방법에 대해 정리하려고 한다.
검색 기능을 추가하기에 앞서 이글에서 사용한 코드를 가져와 사용하려고 한다.
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();
}
}
<?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도 하나 추가해주도록 하자.
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()
함수를 통해 어댑터의 아이템을 바꿔주면 된다.
많은 데이터에서 내가 필요한 정보만을 찾기 위해 recyclerView에서 editText를 활용하여 검색하는 기능을 구현해보았다.
전체 코드는 Github 링크 에서 확인할 수 있다.
[1] https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=777lover&logNo=10131263714 (editText 이벤트 리스너)
[2] https://stickode.tistory.com/49 (검색 기능 구현 코드)