반응형

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


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

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

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

RecyclerView #4 - 아이템 클릭 처리

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

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

RecyclerView #7 - ViewType 동적변경



RecyclerView #5까지의 샘플을 보면 

Adapter의 onBindViewHolder() 메소드에서 ViewHolder가 Hold하고 있는 위젯에 데이터를 설정하는 형태로 작성되어 있다.

public StdViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflate = LayoutInflater.from(mContext);

View view = inflate.inflate(R.layout.list_item, parent, true);
StdViewHolder vh = new StdViewHolder(view);

return vh;
}


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

}

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

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

}

}


샘플의 경우 아이템을 표시하는 위젯으로 TextView 하나만 추가된 형태이므로 큰 무리는 없겠지만

여러가지 위젯으로 복잡하게 구성된 경우, 처리하는 코드가 지저분하게 코딩될수 밖에 없다.


ViewHolder를 파라미터로 받는 함수를 작성하고 onBindViewHolder에서 호출함으로써 좀 정제화 할수는 있겠지만,

ItemView자체를 클래스화 해서 onBindViewHolder에서는 데이터만 던져주고 

클래스내부에서 나머지 처리를 하는 구조로 작성되면 좋을 것 같다.



대략적인 구현 방향은 다음과 같다.

1. ViewHolder가 Hold할 itemView로 LinearLayout 객체를 던져주고

2. 해당 LinearLayout에 우리가 작성한 Layout을 Inflate해서 붙여주자.


쉽게 말해 다음과 같은 코드로 LinearLayout 객체를 ViewHolder에 던져(?) 주면

RecyclerView는 아이템이 표시될 위치에 우리가 던져준 LinearLayout 을 배치하게 되고

우리는 해당 LinearLayout에 attach된 "Inflate된 View"를 통해 데이터를 갱신 할 수 있다.

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

LayoutInflater inflate = LayoutInflater.from(mContext);
View view = new LinearLayout(mContext);
View v = inflate.inflate(R.layout.list_item, view, true);
StdViewHolder vh = new StdViewHolder(view);

return vh;
}


그럼 위에서 정리된 내용대로 ItemView 클래스를 작성해 보자.


ItemView는 RecyclerView가 요구하는 View Class type이어야 할뿐 아니라, 우리가 inflate한 View를 attach할 수 있어야 하므로

일단은 제일 만만한 LinearLayout을 상속 받아 작성한다.


* Context를 파라미터로 갖는 기본적인 생성자는 구현이 필요하다.

public class ItemView extends LinearLayout {
TextView textView;
public ItemView(Context context) {
super(context);

LayoutInflater inflate = LayoutInflater.from(context);

// inflate itemLayout & attach to this LinearLayout
View v = inflate.inflate(R.layout.list_item, this, true);

// bind widget
textView = v.findViewById(R.id.textView);

v.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
}

void setContents(String contents) {
textView.setText(contents);
}
}


당연한 이야기 이지만, LinearLayout을 상속받은 이 클래스의 인스턴스와 

R.layout.list_item을 inflate한 View간의 관계가 맺어 지는 것은

inflate.inflate() 의 두번째 인자(root)와 세번째 인자(attachToRoot)에 의해서이다.



Adapter와 ViewHolder는 다음과 같이 변경될 수 있다.

public StdViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
ItemView view = new ItemView(mContext);

StdViewHolder vh = new StdViewHolder(view);

return vh;
}

@Override
public void onBindViewHolder(@NonNull StdViewHolder holder, int position) {
holder.mItemView.setContents(mdata.get(position));

}


public class StdViewHolder extends RecyclerView.ViewHolder {
public ItemView mItemView;

public StdViewHolder(@NonNull View itemView) {
super(itemView);
this.mItemView = (ItemView)itemView;
}
}

이제 ItemView Class의 setContents() 역할을 하는 메소드를 변형해서

Class 자체를 넘겨주고 ItemView에서 내용을 뿌리면 된다.


알고 있겠지만, 이러한 구조를 적용하더라도 잊지 말아야 하는 것은 

이번에 작성한 ItemView Class의 인스턴스 또한 재활용 되는 인스턴스라는 점이다.


반응형

+ Recent posts