RecyclerView #4 - 아이템 클릭 처리


RecyclerView #1- 구조및 기본 사용법

RecyclerView #2 - 구분선 추가, 아이템간 간격 조절

RecyclerView #3 - 컨텍스트 메뉴 처리

RecyclerView #4 - 아이템 클릭 처리

RecyclerView #5 - 아이템 선택 처리하기

RecyclerView #6 - ItemView를 클래스화 하기

RecyclerView #7 - ViewType 동적변경


RecyclerView에 표시된 아이템을 클릭했을때의 처리 방법


#3에서 RecyclerView에 Context Menu를 연결하는 방법을 간단히 기술했습니다.

그외에도 아이템을 클릭했을때, 특정한 처리를 수행하는 것 또한

RecyclerView의 일반적인 사용패턴이므로 일단 정리해 봅니다.


ViewHolder의 ItemView에 onClick Listener 설치

ViewHolder가 보관하는 것은 결국 View Class(혹은 상속받은 객체)이기 때문에, onClick Listener 를 설치해서 처리하면 됩니다.

ViewHolder의 itemView에 onClick Listener를 설치하면 되는 것이죠.



onClick Listener를 설치 할만한 위치로는 어디가 좋을까요?


1. Apdater의 onBindViewHolder

생성된 ViewHolder에 대해 데이터가 바인딩 될때마다 호출되는 Methord로  굳이 여기서 반복해서 등록할 이유는 없습니다.

public void onBindViewHolder(@NonNull StdViewHolder holder, int position) {
holder.textView.setText(mdata.get(position));
}


2. Adapter의 onCreateViewHolder

ViewHolder를 생성하는 부분으로, inflate된 view에 Listener를 설치할 수 있겠습니다.

public StdViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflate = LayoutInflater.from(mContext);
View view = inflate.inflate(R.layout.list_item, parent, false);

StdViewHolder vh = new StdViewHolder(view);
return vh;
}

3. ViewHolder의 생성자

인자로 전달된 itemView에 Listener를 등록하는 방법도 유효하겠네요.

public StdViewHolder(@NonNull View itemView) {
super(itemView);
this.textView = itemView.findViewById(R.id.textView);


사실 onClick listener를 등록하는 위치는 2번(onCreateViewHolder)이나 3번(ViewHolder 생성자) 모두 유효해 보입니다만.


개인적으로는 View를 관리하는 ViewHolder쪽에서 처리하는 것이 좀 더 깔끔해 보입니다.

onClick이벤트 처리기 내에서 클릭된 Item의 위치를 가져올수 있는 방법을 

ViewHolder가 제공(ViewHolder.getAdapterPosition)하고 있다는 것도 또 하나의 이유일 수도 있겠습니다.

public class StdViewHolder extends RecyclerView.ViewHolder {
public TextView textView;

public StdViewHolder(@NonNull View itemView) {
super(itemView);
this.textView = itemView.findViewById(R.id.textView);

itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

Log.d("Recyclerview", "position = "+ getAdapterPosition());
}
});

itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
Log.d("Recyclerview", "position = "+ getAdapterPosition());
return false;
}
});
}
}


RecyclerView의 Item Click을 Activity나 Fragment에 전달하기

위에서 설명한 것처럼 ViewHolder에서 onClickListener를 통해 아이템 클릭 처리를 수행할 수 있습니다만,

개발을 하다보니 RecyclerView를 포함하고 있는 Activity나 Fragment에서 '아이템 클릭'에 대한 처리를 수행하는것이

수월할 경우가 많이 있습니다.


여러가지 방법이 있겠지만,

 Activity에서 Adapter에 Listenner를 전달하고 

ViewHolder의 onClickListener에서 Activity의 Listener를 호출하는 방식으로

다음과 같이 적용해 볼수 있습니다.


1. Adapter & ViewHolder

public class StdRecyclerAdapter extends RecyclerView.Adapter<StdRecyclerAdapter.StdViewHolder> {

public interface OnListItemLongSelectedInterface {
void onItemLongSelected(View v, int position);
}

public interface OnListItemSelectedInterface {
void onItemSelected(View v, int position);
}

private OnListItemSelectedInterface mListener;
private OnListItemLongSelectedInterface mLongListener;


Context mContext;
List<String> mdata;
RecyclerView recyclerView;

public StdRecyclerAdapter(Context context
, OnListItemSelectedInterface listener
, OnListItemLongSelectedInterface longListener) {
this.mContext = context;
this.mListener = listener;
this.mLongListener = longListener;
}


public class StdViewHolder extends RecyclerView.ViewHolder {
public TextView textView;

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

itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = getAdapterPosition();
mListener.onItemSelected(v, getAdapterPosition());

Log.d("test", "position = "+ getAdapterPosition());
}
});

itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
mLongListener.onItemLongSelected(v, getAdapterPosition());
return false;
}
});
}
}
}

2. MainActivity

public class MainActivity extends AppCompatActivity implements StdRecyclerAdapter.OnListItemLongSelectedInterface
, StdRecyclerAdapter.OnListItemSelectedInterface{


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


StdRecyclerAdapter mAdapter = new StdRecyclerAdapter(this, this,this);
recyclerView.setAdapter(mAdapter);
mAdapter.setData(dataSet);

}

@Override
public void onItemSelected(View v, int position) {
StdRecyclerAdapter.StdViewHolder viewHolder = (StdRecyclerAdapter.StdViewHolder)recyclerView.findViewHolderForAdapterPosition(position);
Toast.makeText(this, viewHolder.textView.getText().toString(), Toast.LENGTH_SHORT).show();
}

@Override
public void onItemLongSelected(View v, int position) {
Toast.makeText(this, position + " long clicked", Toast.LENGTH_SHORT).show();
}


 


  1. 토닥스 2019.10.31 00:47

    안녕하세요 다름이 아니라 질문이 하나 있습니다!MainActivity에서 new StdRecyclerAdapter(this, this,this);
    에서 세 this가 각각 다른 것을 의미하는 것 같은데 혹시 this의 원리가 무엇인가요!?

    • 좋은향기 2019.10.31 14:33 신고

      1. StdRecyclerAdapter Class의 생성자는 다음과 같이 정의되어 있습니다.

      public StdRecyclerAdapter(Context context
      , OnListItemSelectedInterface listener
      , OnListItemLongSelectedInterface longListener)

      2. MainActivity Class는 다음과 같이 정의되어 있습니다.

      public class MainActivity extends AppCompatActivity implements StdRecyclerAdapter.OnListItemLongSelectedInterface
      , StdRecyclerAdapter.OnListItemSelectedInterface

      3. MainActivity Class는 AppCompatActivity를 상속받고 있으며(AppCompatActivity Class의 상속계층을 따라가 보면 Context를 상속하고 있음을 알 수 있습니다.)
      StdRecyclerAdapter.OnListItemLongSelectedInterface 와 StdRecyclerAdapter.OnListItemSelectedInterface를 구현하고 있습니다.

      4. 결론적으로 아래와 같이 해석됩니다.
      new StdRecyclerAdapter((Context)this
      , (StdRecyclerAdapter.OnListItemLongSelectedInterface)this
      , ( StdRecyclerAdapter.OnListItemSelectedInterface)this)

+ Recent posts