반응형

ListView를 쓰다가 RecyclerView로 넘어온 대다수의 개발자들이 RecyclerView에서 제일 먼저 찾아보는 것을 꼽자면, 단연코 나는 'Header & Footer'라고 말할 것이다.


아닌데? 아닌데? 아닌데? RecyclerView에 Header Footer 그까이꺼 그냥 잘 만들어서 적용하면 되는데? 라고 한다면 바로 뒤로 가기 버튼을 눌러도 좋다. 그게 아니라면 아래 내용을 통해 많은 도움을 받기를 바란다.



어떤식으로 구현하나요?


View에 HeaderView와 FooterView를 추가해주는 ListView의 방식과는 다르게, RecyclerView에서는 adapter를 통해서 추가하는 방식을 사용한다. 추가 과정에서 RecyclerView Adapter를 좀더 쉽고 빠르게 쓸 수 있도록 구현하고자 이클립스 부엉이님의 블로그를 참고하여 구현하였다.



구현 코드 설명


구현 코드는 아래 코드를 보면서 설명하도록 한다.


public class HeaderAndFooterAdapter extends RecyclerView.Adapter {
protected Context context;

public static final int TYPE_HEADER = Integer.MIN_VALUE;
public static final int TYPE_FOOTER = Integer.MIN_VALUE + 1;

private Class<?> classTypeHeader;
protected Class<?> classTypeBody;
private Class<?> classTypeFooter;

...

public void setHeaderView(Class<?> classTypeHeader) {
this.classTypeHeader = classTypeHeader;
this.notifyDataSetChanged();
}

public void removeHeaderView() {
this.classTypeHeader = null;
this.notifyDataSetChanged();
}

public void setFooterView(Class<?> classTypeFooter) {
this.classTypeFooter = classTypeFooter;
this.notifyDataSetChanged();
}

public void removeFooterView() {
this.classTypeFooter = null;
this.notifyDataSetChanged();
}

private boolean hasHeader() {
return classTypeHeader != null;
}

private boolean hasFooter() {
return classTypeFooter != null;
}

@Override
public void onBindViewHolder(GeneralViewHolder holder, int position) {
if (getItemViewType(position) == TYPE_HEADER || getItemViewType(position) == TYPE_FOOTER) {
//if you need get header & footer state , do here
return;
}
holder.onBindData(position
, getItem(position));
}

@Override
public GeneralViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return onCreateViewHolder(parent, getClassType(viewType));
}

// viewType에 맞는 View를 반환합니다.

private Class<?> getClassType(int viewType) {
switch (viewType) {
case TYPE_HEADER:
return classTypeHeader;
case TYPE_FOOTER:
return classTypeFooter;
default:
return classTypeBody;
}
}


@Override
public int getItemViewType(int position) {
if (hasHeader() && position == 0) {
return TYPE_HEADER;
}

if (hasFooter() && position == getItemCount() - 1) {
return TYPE_FOOTER;
}
return super.getItemViewType(hasHeader() ? position - 1 : position);
}

@Override
public int getItemCount() {
return mItems.size() + (hasHeader() ? 1 : 0) + (hasFooter() ? 1 : 0);
}

public T getItem(int position) {
int max = mItems.size();
if (hasHeader()) {
position = position -
1;
}
return (max > position && position >= 0) ? mItems.get(position) : null;
}

...
}


코드를 간략하게 설명하면, getItemViewType 과정에서 headerView와 footerView의 유무와 position의 위치를 함께 판단하여 header, body, footer 타입으로 지정합니다.


지정된 타입에 따라 onCreateViewHolder 처리과정에서 각기 다른 뷰를 생성하여 반환하며, 이 과정에 따라 사용자는 아래 코드와 같이 아주 쉽게 headerView와 footerView를 추가, 삭제가 가능합니다.


HeaderAndFooterAdapter adapter = new HeaderAndFooterAdapter <>(...);

// FooterView 추가

adapter.setFooterView(FooterItem.class);


// FooterView 삭제

adapter.removeFooterView();



위의 이클립스 부엉이님의 블로그를 통해 RecyclerView를 적용하는 과정에서 불필요한 Adapter와 ViewHolder를 생성하는 과정을 생략하였으며, 인터페이스를 통해 쉽게 HeaderView와 FooterView를 

추가할 수 있도록 하였다.


GitHub에 있는 좋은 코드들을 가져다 쓰는것도 좋지만, 가끔은 블로그에 잘 정리된 내용들을 공부하면서 새롭게 만들어보는 과정도 많은 도움이 된다고 생각하며, 본 포스팅을 마친다.

반응형

'안드로이드 > 컴포넌트' 카테고리의 다른 글

[Android] UriMatcher, 스마트하게 써보자!  (0) 2019.06.03

+ Recent posts