I receive a JSON array from the server with the date and number of messages. I need to make a list in which the date will be before the start of messages of this date. I don’t understand how to teach an adapter to build such a list.

Help, point your finger where to dig?

There is an approximate method of implementation:

  1. Create an array with dates of messages in the format HH:mm

  2. ???

  • you need to use several View types in the adapter - Vladyslav Matviienko
  • There are already two of them. Someone’s and someone’s messages) I don’t understand how to insert it correctly so that it is above the messages. In addition, Meria has a lot of operation on the position, the header will get in the way - Flippy
  • one
    don't bicycles github.com/timehop/sticky-headers-recyclerview - georgehardcore
  • one
    Not looking for easy ways - Flippy
  • one
    @ SergeyGrushin make DateItem and MessageItem, when reading from JSON, if the date changes, add DateItem, then use get instanceof in getItemViewType, although the answer is also good - georgehardcore

1 answer 1

Data organization is such that JSON needs to be parsed into model objects, each model will contain a date field and a record field. The collection must be sorted by date.

First we need two types of markup. The first will display the date and record ( layout.header ), the second - only the record ( layout.record ). Layout layout.header includes layout layout.header via include .

layout.record:

  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content" > <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:id = "@+id/record" /> </LinearLayout> 

layout.header:

  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content" > <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:id = "@+id/date" /> <include android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout> 

The logic of determining what type of View to display is based on comparing the date of the current record and the past - if they are not equal, then display the title with the date and record, otherwise only the record. The zero element is processed separately and always contains the date and record.

I also ask you to pay attention to the organization of the switch - case block in the onBindViewHolder() method. When displaying a View with a date, case displays the date on the markup and “falls” on the next case (no break ), where the record is displayed on the markup. If the title is not required, then the date is not displayed on the markup (the second case works)

 class SomeAdapter extends RecyclerView.Adapter <SomeAdapter.ItemHolder> { private ArrayList <Data> mData; private final int TYPE_HEADER = 0; private final int TYPE_ITEM = 1; public SomeAdapter (ArrayList <Data> data) { mData = data; } @Override public ItemHolder onCreateViewHolder(ViewGroup parent, int viewType) { View v; switch (viewType) { case TYPE_HEADER: v = LayoutInflater.from(parent.getContext()).inflate(R.layout.header, parent, false); break; default: v = LayoutInflater.from(parent.getContext()).inflate(R.layout.record, parent, false); } return new ItemHolder(v); } @Override public void onBindViewHolder( ItemHolder holder, int position) { int type = getItemViewType(position); switch (type) { case TYPE_HEADER: holder.mHeaderDate.setText(mData.get(position).getDate())); case TYPE_ITEM: holder.mItemRecord.setText(mData.get(position).getRecord()); break; } } @Override public int getItemCount() { return mData.size(); } @Override public int getItemViewType(int position) { if (isIdentType(position)) return TYPE_ITEM; return TYPE_HEADER; } private boolean isIdentType (int position ){ if (!(position == 0)&&(mData.get(position).getDate()).equals(mData.get(position-1).getDate())) return true; return false; } public static class ItemHolder extends RecyclerView.ViewHolder{ TextView mHeaderDate; TextView mItemRecord; public ItemHolder(View v) { super(v); mHeaderDate = (TextView) v.findViewById(R.id.date); mItemRecord = (TextView) v.findViewById(R.id.record); } } 

Naturally, the markup should be made more beautiful like that, you can select a date with another background or another. This example is just an idea.

  • one
    It seems you can make it easier - only one type of markup, which has a field for the date on top. It is the default with visibility GONE. And in onBindViewHolder, just check whether it is necessary to show or change the text / visibility - YurySPb ♦
  • 2
    @YuriySPb This can be done, but it will be essentially the same as in the answer, only realized not by the means provided by the adapter, but by the “self-made” implementation. Of the minuses, it is better not to overload the business logic, if it is possible, especially when the data is not on two TextView (where I used it there were three widgets in the title, and 5 more in the item). In addition, the implementation of the response makes it possible to arrange the list more freely - pavlofff