iOS의 UITableView와 유사한 행 / 섹션 로직을 처리하는 것은 Android에서 iOS만큼 간단하지는 않지만 RecyclerView를 사용하면 수행 할 수있는 작업의 유연성이 훨씬 더 큽니다.
결국 어댑터에 표시되는보기 유형을 파악하는 방법이 전부입니다. 일단 당신이 그것을 이해했다면, 그것은 쉬운 항해가 될 것입니다 (실제로는 아니지만 적어도 당신은 그것을 분류 할 것입니다).
어댑터는 재정의해야하는 두 가지 메서드를 제공합니다.
getItemViewType(int position)
이 메서드의 기본 구현은 항상 0을 반환하여 뷰 유형이 1 개뿐임을 나타냅니다. 귀하의 경우에는 그렇지 않으므로 어떤 행이 어떤 뷰 유형에 해당하는지 주장하는 방법을 찾아야합니다. 행과 섹션을 사용하여이를 관리하는 iOS와 달리 여기에는 신뢰할 수있는 색인이 하나만 있으며, 위치가 섹션 헤더와 언제 상호 연관되는지, 정상적인 행.
createViewHolder(ViewGroup parent, int viewType)
어쨌든이 메서드를 재정의해야하지만 일반적으로 사람들은 viewType 매개 변수를 무시합니다. 보기 유형에 따라 올바른 레이아웃 리소스를 확장하고 그에 따라보기 홀더를 만들어야합니다. RecyclerView는 서로 다른 뷰 유형의 충돌을 방지하는 방식으로 서로 다른 뷰 유형 재활용을 처리합니다.
와 같은 기본 LayoutManager를 사용할 계획이라면 LinearLayoutManager
가야합니다. 자신 만의 LayoutManager 구현을 계획하고 있다면 좀 더 열심히 작업해야합니다. 실제로 작업해야하는 유일한 API findViewByPosition(int position)
는 특정 위치에서 주어진 뷰를 제공하는 것입니다. 이 뷰가 어떤 유형 인지에 따라 다르게 레이아웃하고 싶을 것이므로 몇 가지 옵션이 있습니다.
일반적으로 ViewHolder 패턴을 사용할 때 뷰 홀더를 사용하여 뷰의 태그를 설정합니다. 런타임 동안 레이아웃 관리자에서이를 사용하여이를 표현하는 뷰 홀더에 필드를 추가하여 뷰가 어떤 유형인지 알아낼 수 있습니다.
어떤 위치가 어떤 뷰 유형과 상관 관계가 있는지를 결정하는 함수가 필요하기 때문에이 메서드를 어떻게 든 전역 적으로 액세스 할 수 있도록 (데이터를 관리하는 싱글 톤 클래스일까요?) 다음에 따라 동일한 메서드를 간단히 쿼리 할 수 있습니다. 위치.
다음은 코드 샘플입니다.
// in this sample, I use an object array to simulate the data of the list.
// I assume that if the object is a String, it means I should display a header with a basic title.
// If not, I assume it's a custom model object I created which I will use to bind my normal rows.
private Object[] myData;
public static final int ITEM_TYPE_NORMAL = 0;
public static final int ITEM_TYPE_HEADER = 1;
public class MyAdapter extends Adapter<ViewHolder> {
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == ITEM_TYPE_NORMAL) {
View normalView = LayoutInflater.from(getContext()).inflate(R.layout.my_normal_row, null);
return new MyNormalViewHolder(normalView); // view holder for normal items
} else if (viewType == ITEM_TYPE_HEADER) {
View headerRow = LayoutInflater.from(getContext()).inflate(R.layout.my_header_row, null);
return new MyHeaderViewHolder(headerRow); // view holder for header items
}
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
final int itemType = getItemViewType(position);
if (itemType == ITEM_TYPE_NORMAL) {
((MyNormalViewHolder)holder).bindData((MyModel)myData[position]);
} else if (itemType == ITEM_TYPE_HEADER) {
((MyHeaderViewHolder)holder).setHeaderText((String)myData[position]);
}
}
@Override
public int getItemViewType(int position) {
if (myData[position] instanceof String) {
return ITEM_TYPE_HEADER;
} else {
return ITEM_TYPE_NORMAL;
}
}
@Override
public int getItemCount() {
return myData.length;
}
}
다음은 이러한 뷰 보유자가 어떻게 생겼는지에 대한 샘플입니다.
public MyHeaderViewHolder extends ViewHolder {
private TextView headerLabel;
public MyHeaderViewHolder(View view) {
super(view);
headerLabel = (TextView)view.findViewById(R.id.headerLabel);
}
public void setHeaderText(String text) {
headerLabel.setText(text);
}
}
public MyNormalViewHolder extends ViewHolder {
private TextView titleLabel;
private TextView descriptionLabel;
public MyNormalViewHolder(View view) {
super(view);
titleLabel = (TextView)view.findViewById(R.id.titleLabel);
descriptionLabel = (TextView)view.findViewById(R.id.descriptionLabel);
}
public void bindData(MyModel model) {
titleLabel.setText(model.getTitle());
descriptionLabel.setText(model.getDescription());
}
}
물론이 샘플에서는 이러한 방식으로 어댑터를 쉽게 구현할 수있는 방식으로 데이터 소스 (myData)를 구성했다고 가정합니다. 예를 들어, 이름 목록과 이름의 첫 번째 글자가 변경 될 때마다 헤더를 표시하는 데이터 소스를 구성하는 방법을 보여 드리겠습니다 (목록이 알파벳순이라고 가정). 목록은 다음과 같습니다.
// Assume names & descriptions are non-null and have the same length.
// Assume names are alphabetized
private void processDataSource(String[] names, String[] descriptions) {
String nextFirstLetter = "";
String currentFirstLetter;
List<Object> data = new ArrayList<Object>();
for (int i = 0; i < names.length; i++) {
currentFirstLetter = names[i].substring(0, 1); // get the 1st letter of the name
// if the first letter of this name is different from the last one, add a header row
if (!currentFirstLetter.equals(nextFirstLetter)) {
nextFirstLetter = currentFirstLetter;
data.add(nextFirstLetter);
}
data.add(new MyModel(names[i], descriptions[i]));
}
myData = data.toArray();
}
이 예제는 상당히 구체적인 문제를 해결하기 위해 제공되지만 리사이클 러에서 다양한 행 유형을 처리하는 방법에 대한 좋은 개요를 제공하고 필요에 맞게 코드에서 필요한 조정을 수행 할 수 있기를 바랍니다.