Xử lý logic hàng / phần tương tự như UITableView của iOS không đơn giản trong Android như trong iOS, tuy nhiên, khi bạn sử dụng RecyclerView - tính linh hoạt của những gì bạn có thể làm còn lớn hơn nhiều.
Cuối cùng, tất cả là về cách bạn tìm ra loại chế độ xem nào bạn đang hiển thị trong Bộ điều hợp. Một khi bạn đã tìm ra điều đó, nó sẽ dễ dàng đi thuyền (không thực sự, nhưng ít nhất bạn sẽ có được sắp xếp đó).
Bộ điều hợp hiển thị hai phương thức mà bạn nên ghi đè:
getItemViewType(int position)
Việc triển khai mặc định của phương thức này sẽ luôn trả về 0, chỉ ra rằng chỉ có 1 kiểu xem. Trong trường hợp của bạn, nó không phải như vậy, và vì vậy bạn sẽ cần tìm cách để xác nhận hàng nào tương ứng với kiểu xem nào. Không giống như iOS, nơi quản lý điều này cho bạn với các hàng và phần, ở đây bạn sẽ chỉ có một chỉ mục để dựa vào và bạn sẽ cần sử dụng các kỹ năng dành cho nhà phát triển của mình để biết khi nào một vị trí tương quan với tiêu đề của phần và khi nào nó tương quan với một hàng bình thường.
createViewHolder(ViewGroup parent, int viewType)
Dù sao bạn cũng cần ghi đè phương thức này, nhưng thông thường mọi người chỉ bỏ qua tham số viewType. Theo loại chế độ xem, bạn sẽ cần tăng tài nguyên bố cục chính xác và tạo chủ sở hữu chế độ xem phù hợp. RecyclerView sẽ xử lý tái chế các loại chế độ xem khác nhau theo cách tránh sự xung đột của các loại chế độ xem khác nhau.
Nếu bạn đang dự định sử dụng Trình quản lý bố cục mặc định, chẳng hạn như LinearLayoutManager
, bạn nên sử dụng. Nếu bạn đang lên kế hoạch thực hiện Bố cục Trình quản lý của riêng mình, bạn sẽ cần làm việc chăm chỉ hơn một chút. API duy nhất bạn thực sự phải làm việc là findViewByPosition(int position)
cung cấp một chế độ xem nhất định tại một vị trí nhất định. Vì có thể bạn sẽ muốn bố trí nó khác nhau tùy thuộc vào loại chế độ xem này, bạn có một vài tùy chọn:
Thông thường khi sử dụng mẫu ViewHolder, bạn đặt thẻ của chế độ xem với chủ sở hữu chế độ xem. Bạn có thể sử dụng điều này trong thời gian chạy trong trình quản lý bố cục để tìm hiểu kiểu xem là gì bằng cách thêm một trường trong trình giữ khung thể hiện điều này.
Vì bạn sẽ cần một hàm xác định vị trí tương quan với kiểu xem nào, nên bạn cũng có thể làm cho phương thức này có thể truy cập toàn cầu bằng cách nào đó (có thể là một lớp đơn lẻ quản lý dữ liệu?), Và sau đó bạn có thể truy vấn cùng một phương thức theo vị trí.
Đây là một mẫu mã:
// 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;
}
}
Đây là một ví dụ về cách những người giữ chế độ xem này sẽ trông như thế nào:
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());
}
}
Tất nhiên, mẫu này giả định rằng bạn đã xây dựng nguồn dữ liệu của mình (myData) theo cách giúp dễ dàng thực hiện bộ điều hợp theo cách này. Ví dụ: tôi sẽ chỉ cho bạn cách tôi xây dựng nguồn dữ liệu hiển thị danh sách tên và tiêu đề cho mỗi lần chữ cái đầu tiên của tên thay đổi (giả sử danh sách được xếp theo thứ tự chữ cái) - tương tự như cách liên hệ danh sách sẽ như thế nào:
// 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();
}
Ví dụ này để giải quyết một vấn đề khá cụ thể, nhưng tôi hy vọng điều này cung cấp cho bạn một cái nhìn tổng quan tốt về cách xử lý các loại hàng khác nhau trong trình tái chế và cho phép bạn thực hiện các điều chỉnh cần thiết trong mã của riêng mình để phù hợp với nhu cầu của bạn.