이번에는 리사이클러뷰를 격자 모양으로 보이도록 변경해보고, 아이템을 클릭했을 때 동작하도록 만들어보았다.
코드는 리사이클러뷰(1)에서 사용한 코드를 수정하면서 진행하였다.
MainActivity.java의 LinearLayoutManager를 GridLayoutManager로 변경한다.
GridLayoutManager layoutManager = new GridLayoutManager(this, 2);
생성자에 전달된 숫자는 칼럼의 개수를 의미한다.
화면에 보이는 아이템의 개수를 늘리기 위해 어댑터에 객체를 더 추가한다.
adapter.addItem(new Person("AAA", "010-1111-1111"));
adapter.addItem(new Person("BBB", "010-2222-2222"));
adapter.addItem(new Person("CCC", "010-3333-3333"));
adapter.addItem(new Person("DDD", "010-4444-4444"));
adapter.addItem(new Person("EEE", "010-5555-5555"));
adapter.addItem(new Person("FFF", "010-6666-6666"));
adapter.addItem(new Person("GGG", "010-7777-7777"));
adapter.addItem(new Person("HHH", "010-8888-8888"));
adapter.addItem(new Person("III", "010-9999-9999"));
adapter.addItem(new Person("JJJ", "010-0000-0000"));
각 아이템이 눌렸을 때 토스트 메시지가 표시되도록 만들어보았다.
클릭 이벤트는 리사이클러뷰가 아니라 각 아이템에 발생하게 되므로 뷰홀더 안에서 클릭 이벤트를 처리하도록 만든다.
뷰홀더의 생성자로 뷰 객체가 전달되므로 이 뷰 객체에 onClickListener를 설정한다.
하지만 코드 수정의 편의성을 위해서 어댑터 객체 밖에서 리스터를 설정하고 설정된 리스너 쪽으로 이벤트를 전달받도록 하였다.
이를 위해 OnPersonItemClickListener 인터페이스를 정의한다.
public interface OnPersonItemClickListener {
public void onItemClick(PersonAdapter.ViewHolder holder, View view, int position);
}
onItemClick 메소드가 호출될 때 파리미터로 뷰홀더 객체와 뷰 객체 그리고 뷰의 position 정보가 전달되도록 하였다.
정의한 인터페이스를 사용하도록 ViewHolder 클래스를 수정한다.
static class ViewHolder extends RecyclerView.ViewHolder {
TextView textView;
TextView textView2;
public ViewHolder(@NonNull View itemView, final OnPersonItemClickListener listener) {
super(itemView);
textView = itemView.findViewById(R.id.textView);
textView2 = itemView.findViewById(R.id.textView2);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = getAdapterPosition();
if(listener != null){
listener.onItemClick(ViewHolder.this, v, position);
}
}
});
}
뷰홀더 객체의 생성자가 호출될 때 리스너 객체가 파라미터로 전달되도록 수정하였다.
public ViewHolder(@NonNull View itemView, final OnPersonItemClickListener listener) {
이 리스너 객체는 어댑터 밖에서 설정할 것이며 뷰홀더까지 전달된다.
이렇게 전달된 리스너 객체의 onItemClick 이벤트는 뷰가 클릭되었을 때 호출된다.
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = getAdapterPosition();
if(listener != null){
listener.onItemClick(ViewHolder.this, v, position);
}
}
});
getAdapterPosition 메소드는 뷰홀더에 표시할 아이템이 어댑터에서 몇 번째인지 정보를 반환해준다.
다음으로 어댑터 코드를 수정한다.
public class PersonAdapter extends RecyclerView.Adapter<PersonAdapter.ViewHolder> implements OnPersonItemClickListener{
ArrayList<Person> items = new ArrayList<Person>();
OnPersonItemClickListener listener;
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View itemView = inflater.inflate(R.layout.person_item, parent, false);
return new ViewHolder(itemView, this);
}
...
public void setOnItemClickListener(OnPersonItemClickListener listener) {
this.listener = listener;
}
@Override
public void onItemClick(ViewHolder holder, View view, int position) {
if(listener != null){
listener.onItemClick(holder, view, position);
}
}
어댑터 클래스는 새로 정의한 OnPersonItenClickListener 인터페이스를 구현하도록 한다.
public class PersonAdapter extends RecyclerView.Adapter<PersonAdapter.ViewHolder> implements OnPersonItemClickListener{
그리고 이 인터페이스에서 정의한 onItemClick 메소드를 추가한다.
@Override
public void onItemClick(ViewHolder holder, View view, int position) {
if(listener != null){
listener.onItemClick(holder, view, position);
}
}
이 메소드는 뷰홀더 클래스 안에서 뷰가 클릭되었을 때 호출되는 메소드이다.
그런데 이 어댑터 클래스 안에서가 아니라 밖에서 이벤트 처리를 하는 것이 일반적이므로 listener라는 이름의 변수를 하나 선언하고 setOnItemClickListener 메소드를 추가하여 이 메소드가 호출되었을 때 리스너 객체를 변수에 할당하도록 한다.
OnPersonItemClickListener listener;
...
public void setOnItemClickListener(OnPersonItemClickListener listener) {
this.listener = listener;
}
이렇게 함으로서 onItemClick 메소드가 호출되었을 때 다시 외부에서 설정한 메소드가 호출되도록 만들 수 있다.
마지막을 onCreateViewHolder 메소드 안에 new 연산자를 이용해 ViewHolder 객체를 생성하는 코드를 수정한다.
return new ViewHolder(itemView, this);
이전에는 뷰 객체만 전달했지만 여기에 리스너인 this를 추가로 전달한다.
MainActivity.java 파일에 어댑터에 리스너 객체를 설정하는 코드를 추가한다.
adapter.setOnItemClickListener(new OnPersonItemClickListener() {
@Override
public void onItemClick(PersonAdapter.ViewHolder holder, View view, int position) {
Person item = adapter.getItem(position);
Toast.makeText(getApplicationContext(), "아이템 선택됨 : " + item.getName(), Toast.LENGTH_SHORT).show();
}
});
어댑터 객체의 setOnItemClickListener 메소드를 호출하면서 리스너 객체를 설정하였다.
이렇게 하면 각 아이템이 클릭되었을 때 이 리스너의 onItemClick 메소드가 호출된다.